parent
ca8d8f114f
commit
5f7685336f
@ -1,6 +1,6 @@
|
||||
export executable "cat";
|
||||
|
||||
pub main(argv: [][]u8) -> i32 {
|
||||
pub fn main(argv: [][]u8) i32 => {
|
||||
|
||||
|
||||
return 0;
|
||||
|
@ -3,7 +3,7 @@ export executable "guess_number";
|
||||
import "std.zig";
|
||||
import "rand.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_str("Welcome to the Guess Number Game in Zig.\n");
|
||||
|
||||
var seed : u32;
|
||||
|
@ -2,7 +2,7 @@ export executable "hello";
|
||||
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_str("Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ export executable "test-multiple-files";
|
||||
import "std.zig";
|
||||
import "foo.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
private_function();
|
||||
print_str("OK 2\n");
|
||||
return 0;
|
||||
|
121
src/analyze.cpp
121
src/analyze.cpp
@ -64,7 +64,7 @@ static AstNode *first_executing_node(AstNode *node) {
|
||||
case NodeTypeArrayType:
|
||||
return node;
|
||||
}
|
||||
zig_panic("unreachable");
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
@ -81,29 +81,6 @@ void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
g->errors.append(err);
|
||||
}
|
||||
|
||||
static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
|
||||
char *dot1 = strstr(buf_ptr(buf), ".");
|
||||
if (!dot1)
|
||||
return ErrorInvalidFormat;
|
||||
char *dot2 = strstr(dot1 + 1, ".");
|
||||
if (!dot2)
|
||||
return ErrorInvalidFormat;
|
||||
|
||||
*major = (int)strtol(buf_ptr(buf), nullptr, 10);
|
||||
*minor = (int)strtol(dot1 + 1, nullptr, 10);
|
||||
*patch = (int)strtol(dot2 + 1, nullptr, 10);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
|
||||
int err;
|
||||
if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("invalid version string"));
|
||||
}
|
||||
}
|
||||
|
||||
TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
||||
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
|
||||
entry->arrays_by_size.init(2);
|
||||
@ -258,9 +235,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, ui
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import,
|
||||
TypeTableEntry *child_type, bool is_const)
|
||||
{
|
||||
static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
|
||||
assert(child_type->id != TypeTableEntryIdInvalid);
|
||||
TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)];
|
||||
if (*parent_pointer) {
|
||||
@ -268,8 +243,9 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry
|
||||
} else {
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
|
||||
|
||||
const char *const_str = is_const ? "const " : "";
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "[]%s%s", const_str, buf_ptr(&child_type->name));
|
||||
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
|
||||
|
||||
TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
|
||||
@ -818,47 +794,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
preview_fn_proto(g, import, node);
|
||||
break;
|
||||
case NodeTypeRootExportDecl:
|
||||
if (import == g->root_import) {
|
||||
for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
|
||||
AstNode *directive_node = node->data.root_export_decl.directives->at(i);
|
||||
Buf *name = &directive_node->data.directive.name;
|
||||
Buf *param = &directive_node->data.directive.param;
|
||||
if (buf_eql_str(name, "version")) {
|
||||
set_root_export_version(g, param, directive_node);
|
||||
} else {
|
||||
add_node_error(g, directive_node,
|
||||
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
||||
}
|
||||
}
|
||||
|
||||
if (g->root_export_decl) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("only one root export declaration allowed"));
|
||||
} else {
|
||||
g->root_export_decl = node;
|
||||
|
||||
if (!g->root_out_name)
|
||||
g->root_out_name = &node->data.root_export_decl.name;
|
||||
|
||||
Buf *out_type = &node->data.root_export_decl.type;
|
||||
OutType export_out_type;
|
||||
if (buf_eql_str(out_type, "executable")) {
|
||||
export_out_type = OutTypeExe;
|
||||
} else if (buf_eql_str(out_type, "library")) {
|
||||
export_out_type = OutTypeLib;
|
||||
} else if (buf_eql_str(out_type, "object")) {
|
||||
export_out_type = OutTypeObj;
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
|
||||
}
|
||||
if (g->out_type == OutTypeUnknown)
|
||||
g->out_type = export_out_type;
|
||||
}
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("root export declaration only valid in root source file"));
|
||||
}
|
||||
// handled earlier
|
||||
break;
|
||||
case NodeTypeStructDecl:
|
||||
{
|
||||
@ -1126,7 +1062,7 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
|
||||
if (expected_type->id == TypeTableEntryIdInt &&
|
||||
actual_type->id == TypeTableEntryIdInt &&
|
||||
expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
|
||||
expected_type->size_in_bits > actual_type->size_in_bits)
|
||||
expected_type->size_in_bits >= actual_type->size_in_bits)
|
||||
{
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->implicit_cast.after_type = expected_type;
|
||||
@ -1149,7 +1085,7 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
// implicit non-const to const and ignore noalias
|
||||
// implicit non-const to const for pointers
|
||||
if (expected_type->id == TypeTableEntryIdPointer &&
|
||||
actual_type->id == TypeTableEntryIdPointer &&
|
||||
(!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const))
|
||||
@ -1163,6 +1099,23 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
// implicit non-const to const for unknown size arrays
|
||||
if (expected_type->id == TypeTableEntryIdStruct &&
|
||||
actual_type->id == TypeTableEntryIdStruct &&
|
||||
expected_type->data.structure.is_unknown_size_array &&
|
||||
actual_type->data.structure.is_unknown_size_array &&
|
||||
(!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
|
||||
expected_type->data.structure.fields[0].type_entry->data.pointer.is_const))
|
||||
{
|
||||
TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
|
||||
expected_type->data.structure.fields[0].type_entry->data.pointer.child_type,
|
||||
actual_type->data.structure.fields[0].type_entry->data.pointer.child_type);
|
||||
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||
return resolved_type;
|
||||
}
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
add_node_error(g, first_executing_node(node),
|
||||
buf_sprintf("expected type '%s', got '%s'",
|
||||
buf_ptr(&expected_type->name),
|
||||
@ -1511,15 +1464,15 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
|
||||
if (array_type->id == TypeTableEntryIdInvalid) {
|
||||
return_type = g->builtin_types.entry_invalid;
|
||||
} else if (array_type->id == TypeTableEntryIdArray) {
|
||||
return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type,
|
||||
return_type = get_unknown_size_array_type(g, array_type->data.array.child_type,
|
||||
node->data.slice_expr.is_const);
|
||||
} else if (array_type->id == TypeTableEntryIdPointer) {
|
||||
return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type,
|
||||
return_type = get_unknown_size_array_type(g, array_type->data.pointer.child_type,
|
||||
node->data.slice_expr.is_const);
|
||||
} else if (array_type->id == TypeTableEntryIdStruct &&
|
||||
array_type->data.structure.is_unknown_size_array)
|
||||
{
|
||||
return_type = get_unknown_size_array_type(g, import,
|
||||
return_type = get_unknown_size_array_type(g,
|
||||
array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
|
||||
node->data.slice_expr.is_const);
|
||||
} else {
|
||||
@ -2045,6 +1998,11 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("unable to infer variable type"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
} else if (implicit_type->id == TypeTableEntryIdMetaType &&
|
||||
!variable_declaration->is_const)
|
||||
{
|
||||
add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2175,12 +2133,12 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
|
||||
return resolve_expr_const_val_as_type(g, node,
|
||||
get_array_type(g, child_type, const_val->data.x_uint));
|
||||
} else {
|
||||
add_node_error(g, size_node, buf_create_from_str("unable to resolve constant expression"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
return resolve_expr_const_val_as_type(g, node,
|
||||
get_unknown_size_array_type(g, child_type, node->data.array_type.is_const));
|
||||
}
|
||||
} else {
|
||||
return resolve_expr_const_val_as_type(g, node,
|
||||
get_unknown_size_array_type(g, import, child_type, node->data.array_type.is_const));
|
||||
get_unknown_size_array_type(g, child_type, node->data.array_type.is_const));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2587,7 +2545,6 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
||||
return resolve_expr_const_val_as_type(g, node, type_entry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -3677,14 +3634,6 @@ void semantic_analyze(CodeGen *g) {
|
||||
analyze_top_level_decls_root(g, import, import->root);
|
||||
}
|
||||
}
|
||||
|
||||
if (!g->root_out_name) {
|
||||
add_node_error(g, g->root_import->root,
|
||||
buf_sprintf("missing export declaration and output name not provided"));
|
||||
} else if (g->out_type == OutTypeUnknown) {
|
||||
add_node_error(g, g->root_import->root,
|
||||
buf_sprintf("missing export declaration and export type not provided"));
|
||||
}
|
||||
}
|
||||
|
||||
Expr *get_resolved_expr(AstNode *node) {
|
||||
|
166
src/codegen.cpp
166
src/codegen.cpp
@ -636,7 +636,19 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
|
||||
|
||||
return tmp_struct_ptr;
|
||||
} else if (array_type->id == TypeTableEntryIdPointer) {
|
||||
zig_panic("TODO gen_slice_expr pointer");
|
||||
LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start);
|
||||
LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end);
|
||||
|
||||
add_debug_source_node(g, node);
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
|
||||
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
|
||||
LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr);
|
||||
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
|
||||
LLVMValueRef len_value = LLVMBuildSub(g->builder, end_val, start_val, "");
|
||||
LLVMBuildStore(g->builder, len_value, len_field_ptr);
|
||||
|
||||
return tmp_struct_ptr;
|
||||
} else if (array_type->id == TypeTableEntryIdStruct) {
|
||||
assert(array_type->data.structure.is_unknown_size_array);
|
||||
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
|
||||
@ -1767,25 +1779,62 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
||||
}
|
||||
gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
|
||||
value, variable->type, expr_type);
|
||||
} else if (g->build_type != CodeGenBuildTypeRelease) {
|
||||
// memset uninitialized memory to 0xa
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
|
||||
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
|
||||
LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
|
||||
variable->type->size_in_bits / 8, false);
|
||||
LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
|
||||
variable->type->align_in_bits / 8, false);
|
||||
LLVMValueRef params[] = {
|
||||
dest_ptr,
|
||||
fill_char,
|
||||
byte_count,
|
||||
align_in_bytes,
|
||||
LLVMConstNull(LLVMInt1Type()), // is volatile
|
||||
};
|
||||
} else {
|
||||
bool ignore_uninit = false;
|
||||
TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
|
||||
if (var_type->id == TypeTableEntryIdStruct &&
|
||||
var_type->data.structure.is_unknown_size_array)
|
||||
{
|
||||
assert(var_decl->type->type == NodeTypeArrayType);
|
||||
AstNode *size_node = var_decl->type->data.array_type.size;
|
||||
if (size_node) {
|
||||
ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
|
||||
if (!const_val->ok) {
|
||||
TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
|
||||
|
||||
LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
|
||||
LLVMValueRef size_val = gen_expr(g, size_node);
|
||||
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
|
||||
size_val, "");
|
||||
|
||||
// store the freshly allocated pointer in the unknown size array struct
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
|
||||
variable->value_ref, 0, "");
|
||||
LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
|
||||
|
||||
// store the size in the len field
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
|
||||
variable->value_ref, 1, "");
|
||||
LLVMBuildStore(g->builder, size_val, len_field_ptr);
|
||||
|
||||
// don't clobber what we just did with debug initialization
|
||||
ignore_uninit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ignore_uninit && g->build_type != CodeGenBuildTypeRelease) {
|
||||
// memset uninitialized memory to 0xa
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
|
||||
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
|
||||
LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
|
||||
variable->type->size_in_bits / 8, false);
|
||||
LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
|
||||
variable->type->align_in_bits / 8, false);
|
||||
LLVMValueRef params[] = {
|
||||
dest_ptr,
|
||||
fill_char,
|
||||
byte_count,
|
||||
align_in_bytes,
|
||||
LLVMConstNull(LLVMInt1Type()), // is volatile
|
||||
};
|
||||
|
||||
LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
|
||||
}
|
||||
}
|
||||
|
||||
LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
|
||||
@ -2592,6 +2641,30 @@ static bool directives_contains_link_libc(ZigList<AstNode*> *directives) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
|
||||
char *dot1 = strstr(buf_ptr(buf), ".");
|
||||
if (!dot1)
|
||||
return ErrorInvalidFormat;
|
||||
char *dot2 = strstr(dot1 + 1, ".");
|
||||
if (!dot2)
|
||||
return ErrorInvalidFormat;
|
||||
|
||||
*major = (int)strtol(buf_ptr(buf), nullptr, 10);
|
||||
*minor = (int)strtol(dot1 + 1, nullptr, 10);
|
||||
*patch = (int)strtol(dot2 + 1, nullptr, 10);
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
|
||||
int err;
|
||||
if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("invalid version string"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
||||
Buf *src_dirname, Buf *src_basename, Buf *source_code)
|
||||
{
|
||||
@ -2657,7 +2730,50 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
||||
for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {
|
||||
AstNode *top_level_decl = import_entry->root->data.root.top_level_decls.at(decl_i);
|
||||
|
||||
if (top_level_decl->type == NodeTypeUse) {
|
||||
if (top_level_decl->type == NodeTypeRootExportDecl) {
|
||||
if (g->root_import) {
|
||||
add_node_error(g, top_level_decl,
|
||||
buf_sprintf("root export declaration only valid in root source file"));
|
||||
} else {
|
||||
for (int i = 0; i < top_level_decl->data.root_export_decl.directives->length; i += 1) {
|
||||
AstNode *directive_node = top_level_decl->data.root_export_decl.directives->at(i);
|
||||
Buf *name = &directive_node->data.directive.name;
|
||||
Buf *param = &directive_node->data.directive.param;
|
||||
if (buf_eql_str(name, "version")) {
|
||||
set_root_export_version(g, param, directive_node);
|
||||
} else {
|
||||
add_node_error(g, directive_node,
|
||||
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
||||
}
|
||||
}
|
||||
|
||||
if (g->root_export_decl) {
|
||||
add_node_error(g, top_level_decl,
|
||||
buf_sprintf("only one root export declaration allowed"));
|
||||
} else {
|
||||
g->root_export_decl = top_level_decl;
|
||||
|
||||
if (!g->root_out_name)
|
||||
g->root_out_name = &top_level_decl->data.root_export_decl.name;
|
||||
|
||||
Buf *out_type = &top_level_decl->data.root_export_decl.type;
|
||||
OutType export_out_type;
|
||||
if (buf_eql_str(out_type, "executable")) {
|
||||
export_out_type = OutTypeExe;
|
||||
} else if (buf_eql_str(out_type, "library")) {
|
||||
export_out_type = OutTypeLib;
|
||||
} else if (buf_eql_str(out_type, "object")) {
|
||||
export_out_type = OutTypeObj;
|
||||
} else {
|
||||
add_node_error(g, top_level_decl,
|
||||
buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
|
||||
}
|
||||
if (g->out_type == OutTypeUnknown) {
|
||||
g->out_type = export_out_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (top_level_decl->type == NodeTypeUse) {
|
||||
Buf *import_target_path = &top_level_decl->data.use.path;
|
||||
Buf full_path = BUF_INIT;
|
||||
Buf *import_code = buf_alloc();
|
||||
@ -2756,8 +2872,16 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
|
||||
|
||||
g->root_import = codegen_add_code(g, abs_full_path, src_dir, src_basename, source_code);
|
||||
|
||||
if (!g->root_out_name) {
|
||||
add_node_error(g, g->root_import->root,
|
||||
buf_sprintf("missing export declaration and output name not provided"));
|
||||
} else if (g->out_type == OutTypeUnknown) {
|
||||
add_node_error(g, g->root_import->root,
|
||||
buf_sprintf("missing export declaration and export type not provided"));
|
||||
}
|
||||
|
||||
if (!g->link_libc) {
|
||||
if (g->have_exported_main && g->out_type != OutTypeLib) {
|
||||
if (g->have_exported_main && (g->out_type == OutTypeObj || g->out_type == OutTypeExe)) {
|
||||
g->bootstrap_import = add_special_code(g, "bootstrap.zig");
|
||||
}
|
||||
|
||||
|
@ -3,18 +3,28 @@ import "syscall.zig";
|
||||
// The compiler treats this file special by implicitly importing the function `main`
|
||||
// from the root source file.
|
||||
|
||||
var argc: usize;
|
||||
var argv: &&u8;
|
||||
var env: &&u8;
|
||||
|
||||
#attribute("naked")
|
||||
export fn _start() unreachable => {
|
||||
const argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
|
||||
const argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
|
||||
argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));
|
||||
argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
|
||||
env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8));
|
||||
call_main()
|
||||
}
|
||||
|
||||
exit(main(argc, argv, env));
|
||||
fn strlen(ptr: &u8) usize => {
|
||||
var count: usize = 0;
|
||||
while (ptr[count] != 0) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
var args = @alloca_array([]u8, argc);
|
||||
fn call_main() unreachable => {
|
||||
var args: [argc][]u8;
|
||||
var i : @typeof(argc) = 0;
|
||||
// TODO for in loop over the array
|
||||
while (i < argc) {
|
||||
@ -23,15 +33,4 @@ export fn _start() unreachable => {
|
||||
i += 1;
|
||||
}
|
||||
exit(main(args))
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
fn strlen(ptr: &u8) isize => {
|
||||
var count: isize = 0;
|
||||
while (ptr[count]) {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
*/
|
||||
|
@ -101,7 +101,7 @@ extern {
|
||||
fn puts(s: &const u8) i32;
|
||||
}
|
||||
|
||||
export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => {
|
||||
export fn main(argc: i32, argv: &&u8) i32 => {
|
||||
puts(c"Hello, world!");
|
||||
return 0;
|
||||
}
|
||||
@ -114,7 +114,7 @@ import "syscall.zig";
|
||||
fn empty_function_1() => {}
|
||||
fn empty_function_2() => { return; }
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
empty_function_1();
|
||||
empty_function_2();
|
||||
this_is_a_function();
|
||||
@ -136,7 +136,7 @@ fn another_function() => {}
|
||||
|
||||
/// this is a documentation comment
|
||||
/// doc comment line 2
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_str(/* mid-line comment /* nested */ */ "OK\n");
|
||||
return 0;
|
||||
}
|
||||
@ -147,7 +147,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
import "std.zig";
|
||||
import "foo.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
private_function();
|
||||
print_str("OK 2\n");
|
||||
return 0;
|
||||
@ -178,7 +178,7 @@ pub fn print_text() => {
|
||||
import "foo.zig";
|
||||
import "bar.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
foo_function();
|
||||
bar_function();
|
||||
return 0;
|
||||
@ -214,7 +214,7 @@ pub fn foo_function() bool => {
|
||||
add_simple_case("if statements", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (1 != 0) {
|
||||
print_str("1 is true\n");
|
||||
} else {
|
||||
@ -239,7 +239,7 @@ fn add(a: i32, b: i32) i32 => {
|
||||
a + b
|
||||
}
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (add(22, 11) == 33) {
|
||||
print_str("pass\n");
|
||||
}
|
||||
@ -261,7 +261,7 @@ done:
|
||||
return;
|
||||
}
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
loop(3);
|
||||
return 0;
|
||||
}
|
||||
@ -270,7 +270,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("local variables", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const a : i32 = 1;
|
||||
const b = i32(2);
|
||||
if (a + b == 3) {
|
||||
@ -283,7 +283,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("bool literals", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (true) { print_str("OK 1\n"); }
|
||||
if (false) { print_str("BAD 1\n"); }
|
||||
if (!true) { print_str("BAD 2\n"); }
|
||||
@ -295,7 +295,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("separate block scopes", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (true) {
|
||||
const no_conflict : i32 = 5;
|
||||
if (no_conflict == 5) { print_str("OK 1\n"); }
|
||||
@ -313,7 +313,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("void parameters", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
void_fun(1, void{}, 2);
|
||||
return 0;
|
||||
}
|
||||
@ -333,7 +333,7 @@ struct Foo {
|
||||
b : i32,
|
||||
c : void,
|
||||
}
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const foo = Foo {
|
||||
.a = void{},
|
||||
.b = 1,
|
||||
@ -354,7 +354,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("void arrays", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var array: [4]void;
|
||||
array[0] = void{};
|
||||
array[1] = array[2];
|
||||
@ -373,7 +373,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("mutable local variables", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var zero : i32 = 0;
|
||||
if (zero == 0) { print_str("zero\n"); }
|
||||
|
||||
@ -393,7 +393,7 @@ done:
|
||||
add_simple_case("arrays", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var array : [5]u32;
|
||||
|
||||
var i : u32 = 0;
|
||||
@ -429,7 +429,7 @@ fn get_array_len(a: []u32) usize => {
|
||||
add_simple_case("hello world without libc", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_str("Hello, world!\n");
|
||||
return 0;
|
||||
}
|
||||
@ -439,7 +439,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
add_simple_case("a + b + c", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (false || false || false) { print_str("BAD 1\n"); }
|
||||
if (true && true && false) { print_str("BAD 2\n"); }
|
||||
if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); }
|
||||
@ -461,7 +461,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
add_simple_case("short circuit", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (true || { print_str("BAD 1\n"); false }) {
|
||||
print_str("OK 1\n");
|
||||
}
|
||||
@ -484,7 +484,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
add_simple_case("modify operators", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var i : i32 = 0;
|
||||
i += 5; if (i != 5) { print_str("BAD +=\n"); }
|
||||
i -= 2; if (i != 3) { print_str("BAD -=\n"); }
|
||||
@ -510,7 +510,7 @@ extern {
|
||||
fn printf(__format: &const u8, ...) i32;
|
||||
}
|
||||
|
||||
export fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
export fn main(argc: i32, argv: &&u8) i32 => {
|
||||
printf(c"\n");
|
||||
|
||||
printf(c"0: %llu\n",
|
||||
@ -636,7 +636,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
add_simple_case("structs", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var foo : Foo;
|
||||
@memset(&foo, 0, @sizeof(Foo));
|
||||
foo.a += 1;
|
||||
@ -711,7 +711,7 @@ import "std.zig";
|
||||
const g1 : i32 = 1233 + 1;
|
||||
var g2 : i32 = 0;
|
||||
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (g2 != 0) { print_str("BAD\n"); }
|
||||
g2 = g1;
|
||||
if (g2 != 1234) { print_str("BAD\n"); }
|
||||
@ -722,7 +722,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
|
||||
add_simple_case("while loop", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var i : i32 = 0;
|
||||
while (i < 4) {
|
||||
print_str("loop\n");
|
||||
@ -739,7 +739,7 @@ fn f() i32 => {
|
||||
|
||||
add_simple_case("continue and break", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var i : i32 = 0;
|
||||
while (true) {
|
||||
print_str("loop\n");
|
||||
@ -755,7 +755,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
|
||||
add_simple_case("maybe type", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const x : ?bool = true;
|
||||
|
||||
if (const y ?= x) {
|
||||
@ -790,7 +790,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
|
||||
add_simple_case("implicit cast after unreachable", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const x = outer();
|
||||
if (x == 1234) {
|
||||
print_str("OK\n");
|
||||
@ -807,7 +807,7 @@ fn outer() isize => {
|
||||
import "std.zig";
|
||||
const x: u16 = 13;
|
||||
const z: @typeof(x) = 19;
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const y: @typeof(x) = 120;
|
||||
print_u64(@sizeof(@typeof(y)));
|
||||
print_str("\n");
|
||||
@ -823,7 +823,7 @@ struct Rand {
|
||||
r.seed
|
||||
}
|
||||
}
|
||||
pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const r = Rand {.seed = 1234};
|
||||
if (r.get_seed() != 1234) {
|
||||
print_str("BAD seed\n");
|
||||
@ -836,7 +836,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
add_simple_case("pointer dereferencing", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var x = i32(3);
|
||||
const y = &x;
|
||||
|
||||
@ -858,7 +858,7 @@ import "std.zig";
|
||||
|
||||
const ARRAY_SIZE : u8 = 20;
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var array : [ARRAY_SIZE]u8;
|
||||
print_u64(@sizeof(@typeof(array)));
|
||||
print_str("\n");
|
||||
@ -868,7 +868,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
|
||||
add_simple_case("#min_value() and #max_value()", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_str("max u8: ");
|
||||
print_u64(@max_value(u8));
|
||||
print_str("\n");
|
||||
@ -956,7 +956,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
|
||||
add_simple_case("slicing", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var array : [20]i32;
|
||||
|
||||
array[5] = 1234;
|
||||
@ -984,7 +984,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
|
||||
add_simple_case("else if expression", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
if (f(1) == 1) {
|
||||
print_str("OK\n");
|
||||
}
|
||||
@ -1003,7 +1003,7 @@ fn f(c: u8) u8 => {
|
||||
|
||||
add_simple_case("overflow intrinsics", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var result: u8;
|
||||
if (!@add_with_overflow(u8, 250, 100, &result)) {
|
||||
print_str("BAD\n");
|
||||
@ -1021,7 +1021,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
|
||||
add_simple_case("memcpy and memset intrinsics", R"SOURCE(
|
||||
import "std.zig";
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
var foo : [20]u8;
|
||||
var bar : [20]u8;
|
||||
|
||||
@ -1042,7 +1042,7 @@ import "std.zig";
|
||||
const z : @typeof(stdin_fileno) = 0;
|
||||
const x : @typeof(y) = 1234;
|
||||
const y : u16 = 5678;
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
print_ok(x)
|
||||
}
|
||||
fn print_ok(val: @typeof(x)) @typeof(foo) => {
|
||||
@ -1073,7 +1073,7 @@ enum Bar {
|
||||
D,
|
||||
}
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const foo1 = Foo.One(13);
|
||||
const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, });
|
||||
const bar = Bar.B;
|
||||
@ -1106,7 +1106,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
add_simple_case("array literal", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const HEX_MULT = []u16{4096, 256, 16, 1};
|
||||
|
||||
if (HEX_MULT.len != 4) {
|
||||
@ -1442,6 +1442,10 @@ fn f(noalias x: i32) => {}
|
||||
add_compile_fail_case("struct init syntax for array", R"SOURCE(
|
||||
const foo = []u16{.x = 1024,};
|
||||
)SOURCE", 1, ".tmp_source.zig:2:18: error: type '[]u16' does not support struct initialization syntax");
|
||||
|
||||
add_compile_fail_case("type variables must be constant", R"SOURCE(
|
||||
var foo = u8;
|
||||
)SOURCE", 1, ".tmp_source.zig:2:1: error: variable of type 'type' must be constant");
|
||||
}
|
||||
|
||||
static void print_compiler_invocation(TestCase *test_case) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user