authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-04 03:31:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-04 03:31:57-07:00
log44d5d008d025c7f081d87da393363f40616bfe47
treeaf63ee97991dd83528b21a4c4fccd20abafa629b
parent333a3221275a7bea929f9eb1e2642043027c25f1

partial import segregation

See #3

5 files changed, 115 insertions(+), 35 deletions(-)

src/analyze.cpp+53-24
......@@ -13,15 +13,18 @@
1313static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1414 TypeTableEntry *expected_type, AstNode *node);
1515
16static void alloc_codegen_node(AstNode *node) {
17 assert(!node->codegen_node);
18 node->codegen_node = allocate<CodeGenNode>(1);
19}
20
2116static AstNode *first_executing_node(AstNode *node) {
2217 switch (node->type) {
2318 case NodeTypeFnCallExpr:
2419 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);
2528 case NodeTypeRoot:
2629 case NodeTypeRootExportDecl:
2730 case NodeTypeFnProto:
......@@ -34,15 +37,12 @@ static AstNode *first_executing_node(AstNode *node) {
3437 case NodeTypeDirective:
3538 case NodeTypeReturnExpr:
3639 case NodeTypeVariableDeclaration:
37 case NodeTypeBinOpExpr:
38 case NodeTypeCastExpr:
3940 case NodeTypeNumberLiteral:
4041 case NodeTypeStringLiteral:
4142 case NodeTypeCharLiteral:
4243 case NodeTypeUnreachable:
4344 case NodeTypeSymbol:
4445 case NodeTypePrefixOpExpr:
45 case NodeTypeArrayAccessExpr:
4646 case NodeTypeUse:
4747 case NodeTypeVoid:
4848 case NodeTypeBoolLiteral:
......@@ -53,7 +53,6 @@ static AstNode *first_executing_node(AstNode *node) {
5353 case NodeTypeBreak:
5454 case NodeTypeContinue:
5555 case NodeTypeAsmExpr:
56 case NodeTypeFieldAccessExpr:
5756 case NodeTypeStructDecl:
5857 case NodeTypeStructField:
5958 case NodeTypeStructValueExpr:
......@@ -476,7 +475,6 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
476475 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
477476 assert(fn_decl->type == NodeTypeFnDecl);
478477 AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
479 bool is_pub = (fn_proto->data.fn_proto.visib_mod == FnProtoVisibModPub);
480478
481479 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
482480 fn_table_entry->proto_node = fn_proto;
......@@ -490,9 +488,6 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
490488 Buf *name = &fn_proto->data.fn_proto.name;
491489 g->fn_protos.append(fn_table_entry);
492490 import->fn_table.put(name, fn_table_entry);
493 if (is_pub) {
494 g->fn_table.put(name, fn_table_entry);
495 }
496491
497492 alloc_codegen_node(fn_proto);
498493 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,
514509 node->codegen_node->data.fn_def_node.skip = true;
515510 skip = true;
516511 } else if (is_pub) {
517 auto entry = g->fn_table.maybe_get(proto_name);
512 auto entry = import->fn_table.maybe_get(proto_name);
518513 if (entry) {
519514 add_node_error(g, node,
520515 buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
......@@ -540,8 +535,9 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
540535 g->fn_defs.append(fn_table_entry);
541536
542537 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);
545541 }
546542
547543 resolve_function_proto(g, proto_node, fn_table_entry, import);
......@@ -1748,8 +1744,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
17481744 Buf *name = &fn_ref_expr->data.symbol;
17491745
17501746 auto entry = import->fn_table.maybe_get(name);
1751 if (!entry)
1752 entry = g->fn_table.maybe_get(name);
17531747
17541748 if (!entry) {
17551749 add_node_error(g, fn_ref_expr,
......@@ -2011,13 +2005,41 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
20112005 // already looked at these in the preview pass
20122006 break;
20132007 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;
20192042 }
2020 break;
20212043 case NodeTypeStructDecl:
20222044 // nothing to do
20232045 break;
......@@ -2118,6 +2140,7 @@ void semantic_analyze(CodeGen *g) {
21182140 find_function_declarations_root(g, import, import->root);
21192141 }
21202142 }
2143
21212144 {
21222145 auto it = g->import_table.entry_iterator();
21232146 for (;;) {
......@@ -2139,3 +2162,9 @@ void semantic_analyze(CodeGen *g) {
21392162 buf_sprintf("missing export declaration and export type not provided"));
21402163 }
21412164}
2165
2166void 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 {
150150 ZigList<Buf *> lib_search_paths;
151151
152152 // reminder: hash tables must be initialized before use
153 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
154153 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
155154 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
156155 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
......@@ -215,7 +214,9 @@ struct CodeGen {
215214 bool verbose;
216215 ErrColor err_color;
217216 ImportTableEntry *root_import;
217 ImportTableEntry *bootstrap_import;
218218 LLVMValueRef memcpy_fn_val;
219 bool error_during_imports;
219220};
220221
221222struct VariableTableEntry {
......@@ -328,6 +329,10 @@ struct ParamDeclNode {
328329 VariableTableEntry *variable;
329330};
330331
332struct ImportNode {
333 ImportTableEntry *import;
334};
335
331336struct CodeGenNode {
332337 union {
333338 TypeNode type_node; // for NodeTypeType
......@@ -345,6 +350,7 @@ struct CodeGenNode {
345350 StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
346351 IfVarNode if_var_node; // for NodeTypeStructValueExpr
347352 ParamDeclNode param_decl_node; // for NodeTypeParamDecl
353 ImportNode import_node; // for NodeTypeUse
348354 } data;
349355 ExprNode expr_node; // for all the expression nodes
350356};
......@@ -358,6 +364,7 @@ static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) {
358364
359365void semantic_analyze(CodeGen *g);
360366void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
367void alloc_codegen_node(AstNode *node);
361368TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
362369TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
363370VariableTableEntry *find_variable(BlockContext *context, Buf *name);
src/codegen.cpp+13-10
......@@ -19,7 +19,6 @@
1919
2020CodeGen *codegen_create(Buf *root_source_dir) {
2121 CodeGen *g = allocate<CodeGen>(1);
22 g->fn_table.init(32);
2322 g->str_table.init(32);
2423 g->type_table.init(32);
2524 g->link_table.init(32);
......@@ -146,12 +145,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
146145
147146 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
148147
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);
155149
156150 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
157151 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,
20622056 Buf *import_code = buf_alloc();
20632057 bool found_it = false;
20642058
2059 alloc_codegen_node(top_level_decl);
2060
20652061 for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) {
20662062 Buf *search_path = g->lib_search_paths.at(path_i);
20672063 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,
20712067 if (err == ErrorFileNotFound) {
20722068 continue;
20732069 } else {
2070 g->error_during_imports = true;
20742071 add_node_error(g, top_level_decl,
20752072 buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
20762073 goto done_looking_at_imports;
......@@ -2080,22 +2077,26 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
20802077 auto entry = g->import_table.maybe_get(abs_full_path);
20812078 if (entry) {
20822079 found_it = true;
2080 top_level_decl->codegen_node->data.import_node.import = entry->value;
20832081 } else {
20842082 if ((err = os_fetch_file_path(abs_full_path, import_code))) {
20852083 if (err == ErrorFileNotFound) {
20862084 continue;
20872085 } else {
2086 g->error_during_imports = true;
20882087 add_node_error(g, top_level_decl,
20892088 buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
20902089 goto done_looking_at_imports;
20912090 }
20922091 }
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);
20942094 found_it = true;
20952095 }
20962096 break;
20972097 }
20982098 if (!found_it) {
2099 g->error_during_imports = true;
20992100 add_node_error(g, top_level_decl,
21002101 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
21012102 }
......@@ -2147,14 +2148,16 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
21472148 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_bootstrap_src), err_str(err));
21482149 }
21492150
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);
21512152 }
21522153
21532154 if (g->verbose) {
21542155 fprintf(stderr, "\nSemantic Analysis:\n");
21552156 fprintf(stderr, "--------------------\n");
21562157 }
2157 semantic_analyze(g);
2158 if (!g->error_during_imports) {
2159 semantic_analyze(g);
2160 }
21582161
21592162 if (g->errors.length == 0) {
21602163 if (g->verbose) {
std/bootstrap.zig+3
......@@ -1,5 +1,8 @@
11use "std.zig";
22
3// The compiler treats this file special by implicitly importing the function `main`
4// from the root source file.
5
36#attribute("naked")
47export fn _start() -> unreachable {
58 const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize));
test/run_tests.cpp+38
......@@ -173,6 +173,44 @@ pub fn print_text() {
173173 )SOURCE");
174174 }
175175
176 {
177 TestCase *tc = add_simple_case("import segregation", R"SOURCE(
178use "foo.zig";
179use "bar.zig";
180
181pub 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(
189use "std.zig";
190pub fn foo_function() {
191 print_str("OK\n");
192}
193 )SOURCE");
194
195 add_source_file(tc, "bar.zig", R"SOURCE(
196use "other.zig";
197use "std.zig";
198
199pub 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(
207pub fn foo_function() -> bool {
208 // this one conflicts with the one from foo
209 return true;
210}
211 )SOURCE");
212 }
213
176214 add_simple_case("if statements", R"SOURCE(
177215 use "std.zig";
178216