Commit cd68969115

Andrew Kelley <superjoe30@gmail.com>
2015-12-01 06:53:37
closer to multiple files working
1 parent 55b8472
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();
+}
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);
 }
src/analyze.cpp
@@ -9,6 +9,7 @@
 #include "semantic_info.hpp"
 #include "error.hpp"
 #include "zig_llvm.hpp"
+#include "os.hpp"
 
 static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
     g->errors.add_one();
@@ -212,7 +213,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:
@@ -383,9 +384,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:
@@ -429,7 +437,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);
+    }
+}
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
src/codegen.cpp
@@ -661,12 +661,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);
 
@@ -693,20 +688,46 @@ void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
     }
 
     ImportTableEntry *import_entry = allocate<ImportTableEntry>(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) {
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);
 
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;
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<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
 };
 
 struct FnTableEntry {
@@ -81,7 +86,6 @@ struct CodeGen {
     int version_minor;
     int version_patch;
     bool verbose;
-    bool initialized;
 };
 
 struct TypeNode {