From 5f7685336f2b0bd5e14765d885b0cf87ebe1f578 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Jan 2016 00:07:20 -0700 Subject: [PATCH] better main symbol prototype closes #64 --- example/cat/main.zig | 2 +- example/guess_number/main.zig | 2 +- example/hello_world/hello.zig | 2 +- example/multiple_files/main.zig | 2 +- src/analyze.cpp | 121 +++++++---------------- src/codegen.cpp | 166 ++++++++++++++++++++++++++++---- std/bootstrap.zig | 31 +++--- test/run_tests.cpp | 82 ++++++++-------- 8 files changed, 242 insertions(+), 166 deletions(-) diff --git a/example/cat/main.zig b/example/cat/main.zig index a411853cf4..e1529552d8 100644 --- a/example/cat/main.zig +++ b/example/cat/main.zig @@ -1,6 +1,6 @@ export executable "cat"; -pub main(argv: [][]u8) -> i32 { +pub fn main(argv: [][]u8) i32 => { return 0; diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index f42ff5586f..29b7497fb5 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -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; diff --git a/example/hello_world/hello.zig b/example/hello_world/hello.zig index 0b009aee54..6a0fc6283b 100644 --- a/example/hello_world/hello.zig +++ b/example/hello_world/hello.zig @@ -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; } diff --git a/example/multiple_files/main.zig b/example/multiple_files/main.zig index d1f4d80a2e..f7c2cbba30 100644 --- a/example/multiple_files/main.zig +++ b/example/multiple_files/main.zig @@ -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; diff --git a/src/analyze.cpp b/src/analyze.cpp index b86f6bb7da..4a95ab53fc 100644 --- a/src/analyze.cpp +++ b/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(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) { diff --git a/src/codegen.cpp b/src/codegen.cpp index fd5f048ffe..db9d770884 100644 --- a/src/codegen.cpp +++ b/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 *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"); } diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 06191d47e7..3368539aaa 100644 --- a/std/bootstrap.zig +++ b/std/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; -} -*/ diff --git a/test/run_tests.cpp b/test/run_tests.cpp index d612463449..edb9afa0ba 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -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) {