Commit 97c61313da

Andrew Kelley <superjoe30@gmail.com>
2016-01-28 07:22:37
c_import of stdio.h works for some functions
See #88
1 parent 51ab9b0
example/hello_world/hello_libc.zig
@@ -1,7 +1,9 @@
 #link("c")
 export executable "hello";
 
-extern fn printf(__format: &const u8, ...) -> c_int;
+c_import {
+    @c_include("stdio.h");
+}
 
 export fn main(argc: c_int, argv: &&u8) -> c_int {
     printf(c"Hello, world!\n");
src/all_types.hpp
@@ -894,7 +894,7 @@ struct ImportTableEntry {
     ZigList<int> *line_offsets;
     BlockContext *block_context;
     ZigList<ImporterInfo> importers;
-    bool is_c_import;
+    AstNode *c_import_node;
 
     // reminder: hash tables must be initialized before use
     HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
src/analyze.cpp
@@ -12,6 +12,7 @@
 #include "os.hpp"
 #include "parseh.hpp"
 #include "config.h"
+#include "ast_render.hpp"
 
 static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node);
@@ -26,6 +27,7 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
 static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node);
 static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
+static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node);
 
 static AstNode *first_executing_node(AstNode *node) {
     switch (node->type) {
@@ -87,6 +89,8 @@ static AstNode *first_executing_node(AstNode *node) {
 }
 
 ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
+    assert(!node->owner->c_import_node);
+
     ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
             node->owner->source_code, node->owner->line_offsets, msg);
 
@@ -1056,11 +1060,15 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *parent_import, A
 
     find_libc_path(g);
 
-    ImportTableEntry child_import = {0};
+    ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
+    child_import->fn_table.init(32);
+    child_import->fn_type_table.init(32);
+    child_import->c_import_node = node;
+
     ZigList<ErrorMsg *> errors = {0};
 
     int err;
-    if ((err = parse_h_buf(&child_import, &errors, child_context->c_import_buf, g->clang_argv, g->clang_argv_len,
+    if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g->clang_argv, g->clang_argv_len,
                     buf_ptr(g->libc_include_path))))
     {
         zig_panic("unable to parse h file: %s\n", err_str(err));
@@ -1075,7 +1083,24 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *parent_import, A
         return;
     }
 
-    zig_panic("TODO integrate the AST");
+    if (g->verbose) {
+        fprintf(stderr, "\nc_import:\n");
+        fprintf(stderr, "-----------\n");
+        ast_render(stderr, child_import->root, 4);
+    }
+
+    child_import->di_file = parent_import->di_file;
+    child_import->block_context = new_block_context(child_import->root, nullptr);
+    child_import->importers.append({parent_import, node});
+
+    detect_top_level_decl_deps(g, child_import, child_import->root);
+}
+
+static void satisfy_dep(CodeGen *g, AstNode *node) {
+    Buf *name = get_resolved_top_level_decl(node)->name;
+    if (name) {
+        g->unresolved_top_level_decls.maybe_remove(name);
+    }
 }
 
 static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
@@ -1085,7 +1110,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
             break;
         case NodeTypeRootExportDecl:
             // handled earlier
-            break;
+            return;
         case NodeTypeStructDecl:
             {
                 TypeTableEntry *type_entry = node->data.struct_decl.type_entry;
@@ -1115,7 +1140,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
             break;
         case NodeTypeImport:
             // nothing to do here
-            break;
+            return;
         case NodeTypeCImport:
             resolve_c_import_decl(g, import, node);
             break;
@@ -1159,6 +1184,9 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
         case NodeTypeErrorType:
             zig_unreachable();
     }
+
+
+    satisfy_dep(g, node);
 }
 
 static FnTableEntry *get_context_fn_entry(BlockContext *context) {
@@ -4512,6 +4540,12 @@ static TypeTableEntryId container_to_type(ContainerKind kind) {
 
 static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node) {
     switch (node->type) {
+        case NodeTypeRoot:
+            for (int i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
+                AstNode *child = import->root->data.root.top_level_decls.at(i);
+                detect_top_level_decl_deps(g, import, child);
+            }
+            break;
         case NodeTypeStructDecl:
             {
                 Buf *name = &node->data.struct_decl.name;
@@ -4664,7 +4698,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
         case NodeTypeParamDecl:
         case NodeTypeFnDecl:
         case NodeTypeReturnExpr:
-        case NodeTypeRoot:
         case NodeTypeBlock:
         case NodeTypeBinOpExpr:
         case NodeTypeUnwrapErrorExpr:
@@ -4732,7 +4765,6 @@ static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode
     }
 
     resolve_top_level_decl(g, import, node);
-    g->unresolved_top_level_decls.remove(get_resolved_top_level_decl(node)->name);
 }
 
 static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
@@ -4823,10 +4855,7 @@ void semantic_analyze(CodeGen *g) {
 
             ImportTableEntry *import = entry->value;
 
-            for (int i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
-                AstNode *child = import->root->data.root.top_level_decls.at(i);
-                detect_top_level_decl_deps(g, import, child);
-            }
+            detect_top_level_decl_deps(g, import, import->root);
         }
     }
 
src/hash_map.hpp
@@ -72,6 +72,12 @@ public:
         return internal_get(key);
     }
 
+    void maybe_remove(const K &key) {
+        if (maybe_get(key)) {
+            remove(key);
+        }
+    }
+
     void remove(const K &key) {
         _modification_count += 1;
         int start_index = key_to_index(key);
src/parseh.cpp
@@ -27,6 +27,7 @@ struct Context {
     AstNode *c_void_decl_node;
     AstNode *root;
     HashMap<Buf *, bool, buf_hash, buf_eql_buf> type_table;
+    HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
 };
 
 static AstNode *make_qual_type_node(Context *c, QualType qt);
@@ -107,8 +108,8 @@ static AstNode *make_type_node(Context *c, const Type *ty) {
                         return simple_type_node(c, "bool");
                     case BuiltinType::Char_U:
                     case BuiltinType::UChar:
-                        return simple_type_node(c, "u8");
                     case BuiltinType::Char_S:
+                        return simple_type_node(c, "u8");
                     case BuiltinType::SChar:
                         return simple_type_node(c, "i8");
                     case BuiltinType::UShort:
@@ -266,11 +267,18 @@ static AstNode *make_qual_type_node(Context *c, QualType qt) {
 
 static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
     AstNode *node = create_node(c, NodeTypeFnProto);
+    buf_init_from_str(&node->data.fn_proto.name, decl_name(fn_decl));
+
+    auto fn_entry = c->fn_table.maybe_get(&node->data.fn_proto.name);
+    if (fn_entry) {
+        // we already saw this function
+        return;
+    }
+
     node->data.fn_proto.is_extern = true;
     node->data.fn_proto.visib_mod = c->visib_mod;
     node->data.fn_proto.directives = create_empty_directives(c);
     node->data.fn_proto.is_var_args = fn_decl->isVariadic();
-    buf_init_from_str(&node->data.fn_proto.name, decl_name(fn_decl));
 
     int arg_count = fn_decl->getNumParams();
     bool all_ok = true;
@@ -313,6 +321,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
 
     normalize_parent_ptrs(node);
 
+    c->fn_table.put(&node->data.fn_proto.name, true);
     c->root->data.root.top_level_decls.append(node);
 }
 
@@ -392,7 +401,9 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, ZigList<
     Context *c = &context;
     c->import = import;
     c->errors = errors;
-    c->type_table.init(64);
+    c->visib_mod = VisibModPub;
+    c->type_table.init(32);
+    c->fn_table.init(32);
 
     char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS");
     if (ZIG_PARSEH_CFLAGS) {
@@ -486,7 +497,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, ZigList<
     normalize_parent_ptrs(c->root);
 
     import->root = c->root;
-    import->is_c_import = true;
 
     return 0;
 }
test/run_tests.cpp
@@ -98,7 +98,11 @@ static void add_compiling_test_cases(void) {
     add_simple_case("hello world with libc", R"SOURCE(
 #link("c")
 export executable "test";
-extern fn puts(s: &const u8) -> c_int;
+
+c_import {
+    @c_include("stdio.h");
+}
+
 export fn main(argc: c_int, argv: &&u8) -> c_int {
     puts(c"Hello, world!");
     return 0;
@@ -481,7 +485,10 @@ pub fn main(args: [][]u8) -> %void {
     add_simple_case("number literals", R"SOURCE(
 #link("c")
 export executable "test";
-extern fn printf(__format: &const u8, ...) -> c_int;
+
+c_import {
+    @c_include("stdio.h");
+}
 
 export fn main(argc: c_int, argv: &&u8) -> c_int {
     printf(c"\n");