diff --git a/example/multiple_files/foo.zig b/example/multiple_files/foo.zig index aacc49a556..a42e58397c 100644 --- a/example/multiple_files/foo.zig +++ b/example/multiple_files/foo.zig @@ -1,5 +1,11 @@ use "libc.zig"; -fn print_text() { +// purposefully conflicting function with main.zig +// but it's private so it should be OK +fn private_function() { puts("it works!"); } + +fn print_text() { + private_function(); +} diff --git a/example/multiple_files/main.zig b/example/multiple_files/main.zig index 993d4234c2..9bc489e925 100644 --- a/example/multiple_files/main.zig +++ b/example/multiple_files/main.zig @@ -4,6 +4,10 @@ use "libc.zig"; use "foo.zig"; fn _start() -> unreachable { + private_function(); +} + +fn private_function() -> unreachable { print_text(); exit(0); } diff --git a/src/analyze.cpp b/src/analyze.cpp index 248300bbba..c04d349504 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -9,6 +9,7 @@ #include "semantic_info.hpp" #include "error.hpp" #include "zig_llvm.hpp" +#include "os.hpp" struct BlockContext { AstNode *node; @@ -218,7 +219,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, } break; case NodeTypeUse: - zig_panic("TODO use"); + // nothing to do here break; case NodeTypeDirective: case NodeTypeParamDecl: @@ -545,9 +546,16 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { case NodeTypeRootExportDecl: case NodeTypeExternBlock: - case NodeTypeUse: // already looked at these in the preview pass break; + case NodeTypeUse: + for (int i = 0; i < node->data.use.directives->length; i += 1) { + AstNode *directive_node = node->data.use.directives->at(i); + Buf *name = &directive_node->data.directive.name; + add_node_error(g, directive_node, + buf_sprintf("invalid directive: '%s'", buf_ptr(name))); + } + break; case NodeTypeDirective: case NodeTypeParamDecl: case NodeTypeFnProto: @@ -591,7 +599,14 @@ static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { } } -void semantic_analyze(CodeGen *g, ImportTableEntry *import_table_entry) { - analyze_root(g, import_table_entry, import_table_entry->root); -} +void semantic_analyze(CodeGen *g) { + auto it = g->import_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + ImportTableEntry *import = entry->value; + analyze_root(g, import, import->root); + } +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 374fcad748..0dca23194d 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -9,8 +9,7 @@ #define ZIG_ANALYZE_HPP struct CodeGen; -struct ImportTableEntry; -void semantic_analyze(CodeGen *g, ImportTableEntry *entry); +void semantic_analyze(CodeGen *g); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index cb1b1b222e..7f636ab367 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -664,12 +664,7 @@ static void init(CodeGen *g, Buf *source_path) { } -void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { - if (!g->initialized) { - g->initialized = true; - init(g, source_path); - } - +static void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { Buf full_path = BUF_INIT; os_path_join(g->root_source_dir, source_path, &full_path); @@ -696,20 +691,46 @@ void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { } ImportTableEntry *import_entry = allocate(1); + import_entry->fn_table.init(32); import_entry->root = ast_parse(source_code, tokens); assert(import_entry->root); if (g->verbose) { ast_print(import_entry->root, 0); - - fprintf(stderr, "\nSemantic Analysis:\n"); - fprintf(stderr, "--------------------\n"); } import_entry->path = source_path; import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname)); g->import_table.put(source_path, import_entry); - semantic_analyze(g, import_entry); + + assert(import_entry->root->type == NodeTypeRoot); + 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) + continue; + + auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path); + if (!entry) { + Buf full_path = BUF_INIT; + os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path); + Buf import_code = BUF_INIT; + os_fetch_file_path(&full_path, &import_code); + codegen_add_code(g, &top_level_decl->data.use.path, &import_code); + } + } +} + +void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) { + init(g, source_path); + + codegen_add_code(g, source_path, source_code); + + + if (g->verbose) { + fprintf(stderr, "\nSemantic Analysis:\n"); + fprintf(stderr, "--------------------\n"); + } + semantic_analyze(g); if (g->errors.length == 0) { if (g->verbose) { diff --git a/src/codegen.hpp b/src/codegen.hpp index 403931b834..4476017840 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -42,7 +42,7 @@ void codegen_set_verbose(CodeGen *codegen, bool verbose); void codegen_set_out_type(CodeGen *codegen, OutType out_type); void codegen_set_out_name(CodeGen *codegen, Buf *out_name); -void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code); +void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code); void codegen_link(CodeGen *g, const char *out_file); diff --git a/src/main.cpp b/src/main.cpp index b88d6ecd6b..d96cb92e40 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -73,7 +73,7 @@ static int build(const char *arg0, Build *b) { if (b->out_name) codegen_set_out_name(g, buf_create_from_str(b->out_name)); codegen_set_verbose(g, b->verbose); - codegen_add_code(g, &root_source_name, &root_source_code); + codegen_add_root_code(g, &root_source_name, &root_source_code); codegen_link(g, b->out_file); return 0; diff --git a/src/semantic_info.hpp b/src/semantic_info.hpp index dc87c12930..ec2d2403e3 100644 --- a/src/semantic_info.hpp +++ b/src/semantic_info.hpp @@ -12,6 +12,8 @@ #include "hash_map.hpp" #include "zig_llvm.hpp" +struct FnTableEntry; + struct TypeTableEntry { LLVMTypeRef type_ref; LLVMZigDIType *di_type; @@ -28,6 +30,9 @@ struct ImportTableEntry { AstNode *root; Buf *path; // relative to root_source_dir LLVMZigDIFile *di_file; + + // reminder: hash tables must be initialized before use + HashMap fn_table; }; struct FnTableEntry { @@ -81,7 +86,6 @@ struct CodeGen { int version_minor; int version_patch; bool verbose; - bool initialized; }; struct TypeNode {