| author | |
| committer | |
| log | 44d5d008d025c7f081d87da393363f40616bfe47 |
| tree | af63ee97991dd83528b21a4c4fccd20abafa629b |
| parent | 333a3221275a7bea929f9eb1e2642043027c25f1 |
See #35 files changed, 115 insertions(+), 35 deletions(-)
src/analyze.cpp+53-24| ... | ... | @@ -13,15 +13,18 @@ |
| 13 | 13 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 14 | 14 | TypeTableEntry *expected_type, AstNode *node); |
| 15 | 15 | |
| 16 | static void alloc_codegen_node(AstNode *node) { | |
| 17 | assert(!node->codegen_node); | |
| 18 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 19 | } | |
| 20 | ||
| 21 | 16 | static AstNode *first_executing_node(AstNode *node) { |
| 22 | 17 | switch (node->type) { |
| 23 | 18 | case NodeTypeFnCallExpr: |
| 24 | 19 | return first_executing_node(node->data.fn_call_expr.fn_ref_expr); |
| 20 | case NodeTypeBinOpExpr: | |
| 21 | return first_executing_node(node->data.bin_op_expr.op1); | |
| 22 | case NodeTypeArrayAccessExpr: | |
| 23 | return first_executing_node(node->data.array_access_expr.array_ref_expr); | |
| 24 | case NodeTypeFieldAccessExpr: | |
| 25 | return first_executing_node(node->data.field_access_expr.struct_expr); | |
| 26 | case NodeTypeCastExpr: | |
| 27 | return first_executing_node(node->data.cast_expr.expr); | |
| 25 | 28 | case NodeTypeRoot: |
| 26 | 29 | case NodeTypeRootExportDecl: |
| 27 | 30 | case NodeTypeFnProto: |
| ... | ... | @@ -34,15 +37,12 @@ static AstNode *first_executing_node(AstNode *node) { |
| 34 | 37 | case NodeTypeDirective: |
| 35 | 38 | case NodeTypeReturnExpr: |
| 36 | 39 | case NodeTypeVariableDeclaration: |
| 37 | case NodeTypeBinOpExpr: | |
| 38 | case NodeTypeCastExpr: | |
| 39 | 40 | case NodeTypeNumberLiteral: |
| 40 | 41 | case NodeTypeStringLiteral: |
| 41 | 42 | case NodeTypeCharLiteral: |
| 42 | 43 | case NodeTypeUnreachable: |
| 43 | 44 | case NodeTypeSymbol: |
| 44 | 45 | case NodeTypePrefixOpExpr: |
| 45 | case NodeTypeArrayAccessExpr: | |
| 46 | 46 | case NodeTypeUse: |
| 47 | 47 | case NodeTypeVoid: |
| 48 | 48 | case NodeTypeBoolLiteral: |
| ... | ... | @@ -53,7 +53,6 @@ static AstNode *first_executing_node(AstNode *node) { |
| 53 | 53 | case NodeTypeBreak: |
| 54 | 54 | case NodeTypeContinue: |
| 55 | 55 | case NodeTypeAsmExpr: |
| 56 | case NodeTypeFieldAccessExpr: | |
| 57 | 56 | case NodeTypeStructDecl: |
| 58 | 57 | case NodeTypeStructField: |
| 59 | 58 | case NodeTypeStructValueExpr: |
| ... | ... | @@ -476,7 +475,6 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 476 | 475 | AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i); |
| 477 | 476 | assert(fn_decl->type == NodeTypeFnDecl); |
| 478 | 477 | AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto; |
| 479 | bool is_pub = (fn_proto->data.fn_proto.visib_mod == FnProtoVisibModPub); | |
| 480 | 478 | |
| 481 | 479 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 482 | 480 | fn_table_entry->proto_node = fn_proto; |
| ... | ... | @@ -490,9 +488,6 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 490 | 488 | Buf *name = &fn_proto->data.fn_proto.name; |
| 491 | 489 | g->fn_protos.append(fn_table_entry); |
| 492 | 490 | import->fn_table.put(name, fn_table_entry); |
| 493 | if (is_pub) { | |
| 494 | g->fn_table.put(name, fn_table_entry); | |
| 495 | } | |
| 496 | 491 | |
| 497 | 492 | alloc_codegen_node(fn_proto); |
| 498 | 493 | fn_proto->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; |
| ... | ... | @@ -514,7 +509,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 514 | 509 | node->codegen_node->data.fn_def_node.skip = true; |
| 515 | 510 | skip = true; |
| 516 | 511 | } else if (is_pub) { |
| 517 | auto entry = g->fn_table.maybe_get(proto_name); | |
| 512 | auto entry = import->fn_table.maybe_get(proto_name); | |
| 518 | 513 | if (entry) { |
| 519 | 514 | add_node_error(g, node, |
| 520 | 515 | buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); |
| ... | ... | @@ -540,8 +535,9 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 540 | 535 | g->fn_defs.append(fn_table_entry); |
| 541 | 536 | |
| 542 | 537 | import->fn_table.put(proto_name, fn_table_entry); |
| 543 | if (is_pub) { | |
| 544 | g->fn_table.put(proto_name, fn_table_entry); | |
| 538 | ||
| 539 | if (g->bootstrap_import && import == g->root_import && buf_eql_str(proto_name, "main")) { | |
| 540 | g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); | |
| 545 | 541 | } |
| 546 | 542 | |
| 547 | 543 | resolve_function_proto(g, proto_node, fn_table_entry, import); |
| ... | ... | @@ -1748,8 +1744,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1748 | 1744 | Buf *name = &fn_ref_expr->data.symbol; |
| 1749 | 1745 | |
| 1750 | 1746 | auto entry = import->fn_table.maybe_get(name); |
| 1751 | if (!entry) | |
| 1752 | entry = g->fn_table.maybe_get(name); | |
| 1753 | 1747 | |
| 1754 | 1748 | if (!entry) { |
| 1755 | 1749 | add_node_error(g, fn_ref_expr, |
| ... | ... | @@ -2011,13 +2005,41 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 2011 | 2005 | // already looked at these in the preview pass |
| 2012 | 2006 | break; |
| 2013 | 2007 | case NodeTypeUse: |
| 2014 | for (int i = 0; i < node->data.use.directives->length; i += 1) { | |
| 2015 | AstNode *directive_node = node->data.use.directives->at(i); | |
| 2016 | Buf *name = &directive_node->data.directive.name; | |
| 2017 | add_node_error(g, directive_node, | |
| 2018 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | |
| 2008 | { | |
| 2009 | for (int i = 0; i < node->data.use.directives->length; i += 1) { | |
| 2010 | AstNode *directive_node = node->data.use.directives->at(i); | |
| 2011 | Buf *name = &directive_node->data.directive.name; | |
| 2012 | add_node_error(g, directive_node, | |
| 2013 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | |
| 2014 | } | |
| 2015 | ||
| 2016 | ImportTableEntry *target_import = node->codegen_node->data.import_node.import; | |
| 2017 | assert(target_import); | |
| 2018 | ||
| 2019 | // import all the public functions | |
| 2020 | { | |
| 2021 | auto it = target_import->fn_table.entry_iterator(); | |
| 2022 | for (;;) { | |
| 2023 | auto *entry = it.next(); | |
| 2024 | if (!entry) | |
| 2025 | break; | |
| 2026 | ||
| 2027 | FnTableEntry *fn_entry = entry->value; | |
| 2028 | bool is_pub = (fn_entry->proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); | |
| 2029 | if (is_pub) { | |
| 2030 | auto existing_entry = import->fn_table.maybe_get(entry->key); | |
| 2031 | if (existing_entry) { | |
| 2032 | add_node_error(g, node, | |
| 2033 | buf_sprintf("import of function '%s' overrides existing definition", | |
| 2034 | buf_ptr(&fn_entry->proto_node->data.fn_proto.name))); | |
| 2035 | } else { | |
| 2036 | import->fn_table.put(entry->key, entry->value); | |
| 2037 | } | |
| 2038 | } | |
| 2039 | } | |
| 2040 | } | |
| 2041 | break; | |
| 2019 | 2042 | } |
| 2020 | break; | |
| 2021 | 2043 | case NodeTypeStructDecl: |
| 2022 | 2044 | // nothing to do |
| 2023 | 2045 | break; |
| ... | ... | @@ -2118,6 +2140,7 @@ void semantic_analyze(CodeGen *g) { |
| 2118 | 2140 | find_function_declarations_root(g, import, import->root); |
| 2119 | 2141 | } |
| 2120 | 2142 | } |
| 2143 | ||
| 2121 | 2144 | { |
| 2122 | 2145 | auto it = g->import_table.entry_iterator(); |
| 2123 | 2146 | for (;;) { |
| ... | ... | @@ -2139,3 +2162,9 @@ void semantic_analyze(CodeGen *g) { |
| 2139 | 2162 | buf_sprintf("missing export declaration and export type not provided")); |
| 2140 | 2163 | } |
| 2141 | 2164 | } |
| 2165 | ||
| 2166 | void alloc_codegen_node(AstNode *node) { | |
| 2167 | assert(!node->codegen_node); | |
| 2168 | node->codegen_node = allocate<CodeGenNode>(1); | |
| 2169 | } | |
| 2170 |
src/analyze.hpp+8-1| ... | ... | @@ -150,7 +150,6 @@ struct CodeGen { |
| 150 | 150 | ZigList<Buf *> lib_search_paths; |
| 151 | 151 | |
| 152 | 152 | // reminder: hash tables must be initialized before use |
| 153 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | |
| 154 | 153 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; |
| 155 | 154 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; |
| 156 | 155 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; |
| ... | ... | @@ -215,7 +214,9 @@ struct CodeGen { |
| 215 | 214 | bool verbose; |
| 216 | 215 | ErrColor err_color; |
| 217 | 216 | ImportTableEntry *root_import; |
| 217 | ImportTableEntry *bootstrap_import; | |
| 218 | 218 | LLVMValueRef memcpy_fn_val; |
| 219 | bool error_during_imports; | |
| 219 | 220 | }; |
| 220 | 221 | |
| 221 | 222 | struct VariableTableEntry { |
| ... | ... | @@ -328,6 +329,10 @@ struct ParamDeclNode { |
| 328 | 329 | VariableTableEntry *variable; |
| 329 | 330 | }; |
| 330 | 331 | |
| 332 | struct ImportNode { | |
| 333 | ImportTableEntry *import; | |
| 334 | }; | |
| 335 | ||
| 331 | 336 | struct CodeGenNode { |
| 332 | 337 | union { |
| 333 | 338 | TypeNode type_node; // for NodeTypeType |
| ... | ... | @@ -345,6 +350,7 @@ struct CodeGenNode { |
| 345 | 350 | StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr |
| 346 | 351 | IfVarNode if_var_node; // for NodeTypeStructValueExpr |
| 347 | 352 | ParamDeclNode param_decl_node; // for NodeTypeParamDecl |
| 353 | ImportNode import_node; // for NodeTypeUse | |
| 348 | 354 | } data; |
| 349 | 355 | ExprNode expr_node; // for all the expression nodes |
| 350 | 356 | }; |
| ... | ... | @@ -358,6 +364,7 @@ static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) { |
| 358 | 364 | |
| 359 | 365 | void semantic_analyze(CodeGen *g); |
| 360 | 366 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 367 | void alloc_codegen_node(AstNode *node); | |
| 361 | 368 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 362 | 369 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 363 | 370 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); |
src/codegen.cpp+13-10| ... | ... | @@ -19,7 +19,6 @@ |
| 19 | 19 | |
| 20 | 20 | CodeGen *codegen_create(Buf *root_source_dir) { |
| 21 | 21 | CodeGen *g = allocate<CodeGen>(1); |
| 22 | g->fn_table.init(32); | |
| 23 | 22 | g->str_table.init(32); |
| 24 | 23 | g->type_table.init(32); |
| 25 | 24 | g->link_table.init(32); |
| ... | ... | @@ -146,12 +145,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 146 | 145 | |
| 147 | 146 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); |
| 148 | 147 | |
| 149 | FnTableEntry *fn_table_entry; | |
| 150 | auto entry = g->cur_fn->import_entry->fn_table.maybe_get(name); | |
| 151 | if (entry) | |
| 152 | fn_table_entry = entry->value; | |
| 153 | else | |
| 154 | fn_table_entry = g->fn_table.get(name); | |
| 148 | FnTableEntry *fn_table_entry = g->cur_fn->import_entry->fn_table.get(name); | |
| 155 | 149 | |
| 156 | 150 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 157 | 151 | AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto; |
| ... | ... | @@ -2062,6 +2056,8 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2062 | 2056 | Buf *import_code = buf_alloc(); |
| 2063 | 2057 | bool found_it = false; |
| 2064 | 2058 | |
| 2059 | alloc_codegen_node(top_level_decl); | |
| 2060 | ||
| 2065 | 2061 | for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) { |
| 2066 | 2062 | Buf *search_path = g->lib_search_paths.at(path_i); |
| 2067 | 2063 | os_path_join(search_path, import_target_path, &full_path); |
| ... | ... | @@ -2071,6 +2067,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2071 | 2067 | if (err == ErrorFileNotFound) { |
| 2072 | 2068 | continue; |
| 2073 | 2069 | } else { |
| 2070 | g->error_during_imports = true; | |
| 2074 | 2071 | add_node_error(g, top_level_decl, |
| 2075 | 2072 | buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err))); |
| 2076 | 2073 | goto done_looking_at_imports; |
| ... | ... | @@ -2080,22 +2077,26 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 2080 | 2077 | auto entry = g->import_table.maybe_get(abs_full_path); |
| 2081 | 2078 | if (entry) { |
| 2082 | 2079 | found_it = true; |
| 2080 | top_level_decl->codegen_node->data.import_node.import = entry->value; | |
| 2083 | 2081 | } else { |
| 2084 | 2082 | if ((err = os_fetch_file_path(abs_full_path, import_code))) { |
| 2085 | 2083 | if (err == ErrorFileNotFound) { |
| 2086 | 2084 | continue; |
| 2087 | 2085 | } else { |
| 2086 | g->error_during_imports = true; | |
| 2088 | 2087 | add_node_error(g, top_level_decl, |
| 2089 | 2088 | buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err))); |
| 2090 | 2089 | goto done_looking_at_imports; |
| 2091 | 2090 | } |
| 2092 | 2091 | } |
| 2093 | codegen_add_code(g, abs_full_path, search_path, &top_level_decl->data.use.path, import_code); | |
| 2092 | top_level_decl->codegen_node->data.import_node.import = codegen_add_code(g, | |
| 2093 | abs_full_path, search_path, &top_level_decl->data.use.path, import_code); | |
| 2094 | 2094 | found_it = true; |
| 2095 | 2095 | } |
| 2096 | 2096 | break; |
| 2097 | 2097 | } |
| 2098 | 2098 | if (!found_it) { |
| 2099 | g->error_during_imports = true; | |
| 2099 | 2100 | add_node_error(g, top_level_decl, |
| 2100 | 2101 | buf_sprintf("unable to find '%s'", buf_ptr(import_target_path))); |
| 2101 | 2102 | } |
| ... | ... | @@ -2147,14 +2148,16 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou |
| 2147 | 2148 | zig_panic("unable to open '%s': %s", buf_ptr(&path_to_bootstrap_src), err_str(err)); |
| 2148 | 2149 | } |
| 2149 | 2150 | |
| 2150 | codegen_add_code(g, abs_full_path, bootstrap_dir, bootstrap_basename, import_code); | |
| 2151 | g->bootstrap_import = codegen_add_code(g, abs_full_path, bootstrap_dir, bootstrap_basename, import_code); | |
| 2151 | 2152 | } |
| 2152 | 2153 | |
| 2153 | 2154 | if (g->verbose) { |
| 2154 | 2155 | fprintf(stderr, "\nSemantic Analysis:\n"); |
| 2155 | 2156 | fprintf(stderr, "--------------------\n"); |
| 2156 | 2157 | } |
| 2157 | semantic_analyze(g); | |
| 2158 | if (!g->error_during_imports) { | |
| 2159 | semantic_analyze(g); | |
| 2160 | } | |
| 2158 | 2161 | |
| 2159 | 2162 | if (g->errors.length == 0) { |
| 2160 | 2163 | if (g->verbose) { |
std/bootstrap.zig+3| ... | ... | @@ -1,5 +1,8 @@ |
| 1 | 1 | use "std.zig"; |
| 2 | 2 | |
| 3 | // The compiler treats this file special by implicitly importing the function `main` | |
| 4 | // from the root source file. | |
| 5 | ||
| 3 | 6 | #attribute("naked") |
| 4 | 7 | export fn _start() -> unreachable { |
| 5 | 8 | const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize)); |
test/run_tests.cpp+38| ... | ... | @@ -173,6 +173,44 @@ pub fn print_text() { |
| 173 | 173 | )SOURCE"); |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | { | |
| 177 | TestCase *tc = add_simple_case("import segregation", R"SOURCE( | |
| 178 | use "foo.zig"; | |
| 179 | use "bar.zig"; | |
| 180 | ||
| 181 | pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 { | |
| 182 | foo_function(); | |
| 183 | bar_function(); | |
| 184 | return 0; | |
| 185 | } | |
| 186 | )SOURCE", "OK\nOK\n"); | |
| 187 | ||
| 188 | add_source_file(tc, "foo.zig", R"SOURCE( | |
| 189 | use "std.zig"; | |
| 190 | pub fn foo_function() { | |
| 191 | print_str("OK\n"); | |
| 192 | } | |
| 193 | )SOURCE"); | |
| 194 | ||
| 195 | add_source_file(tc, "bar.zig", R"SOURCE( | |
| 196 | use "other.zig"; | |
| 197 | use "std.zig"; | |
| 198 | ||
| 199 | pub fn bar_function() { | |
| 200 | if (foo_function()) { | |
| 201 | print_str("OK\n"); | |
| 202 | } | |
| 203 | } | |
| 204 | )SOURCE"); | |
| 205 | ||
| 206 | add_source_file(tc, "other.zig", R"SOURCE( | |
| 207 | pub fn foo_function() -> bool { | |
| 208 | // this one conflicts with the one from foo | |
| 209 | return true; | |
| 210 | } | |
| 211 | )SOURCE"); | |
| 212 | } | |
| 213 | ||
| 176 | 214 | add_simple_case("if statements", R"SOURCE( |
| 177 | 215 | use "std.zig"; |
| 178 | 216 |