Commit 4d45d14b55

Andrew Kelley <superjoe30@gmail.com>
2015-12-16 05:48:41
use realpath to avoid duplicate imports
1 parent aa56f01
Changed files (5)
example/structs/structs.zig
@@ -17,6 +17,8 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
         print_str("BAD\n");
     }
 
+    test_point_to_self();
+
     print_str("OK\n");
     return 0;
 }
@@ -27,6 +29,11 @@ struct Foo {
     c : f32,
 }
 
+struct Node {
+    val: i32,
+    next: &Node,
+}
+
 fn test_foo(foo : Foo) {
     if !foo.b {
         print_str("BAD\n");
@@ -36,3 +43,16 @@ fn test_foo(foo : Foo) {
 fn modify_foo(foo : &Foo) {
     foo.c = 100;
 }
+
+fn test_point_to_self() {
+    var root : Node;
+    root.val = 1;
+
+    var node : Node;
+    node.next = &root;
+    node.val = 2;
+
+    if node.next.val != 1 {
+        print_str("BAD\n");
+    }
+}
src/codegen.cpp
@@ -209,10 +209,17 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
 static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
     assert(node->type == NodeTypeFieldAccessExpr);
 
+    //TypeTableEntry *struct_type = get_expr_type(node->data.field_access_expr.struct_expr);
     LLVMValueRef struct_ptr = gen_expr(g, node->data.field_access_expr.struct_expr);
-
     assert(struct_ptr);
 
+    /*
+    if (struct_type->id == TypeTableEntryIdPointer) {
+        add_debug_source_node(g, node);
+        struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, "");
+    }
+    */
+
     FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
 
     assert(codegen_field_access->field_index >= 0);
@@ -244,12 +251,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
         } else {
             zig_panic("gen_field_access_expr bad array field");
         }
-    } else if (struct_type->id == TypeTableEntryIdStruct) {
+    } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
+               struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
+    {
         TypeTableEntry *type_entry;
         LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
         return LLVMBuildLoad(g->builder, ptr, "");
-    } else if (struct_type->id == TypeTableEntryIdPointer) {
-        zig_panic("TODO struct pointer access");
     } else {
         zig_panic("gen_field_access_expr bad struct type");
     }
@@ -1611,7 +1618,9 @@ static bool directives_contains_link_libc(ZigList<AstNode*> *directives) {
     return false;
 }
 
-static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {
+static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
+        Buf *src_dirname, Buf *src_basename, Buf *source_code)
+{
     int err;
     Buf *full_path = buf_alloc();
     os_path_join(src_dirname, src_basename, full_path);
@@ -1662,7 +1671,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
     }
 
     import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
-    g->import_table.put(full_path, import_entry);
+    g->import_table.put(abs_full_path, import_entry);
 
     import_entry->block_context = new_block_context(import_entry->root, nullptr);
     import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file);
@@ -1674,17 +1683,30 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
 
         if (top_level_decl->type == NodeTypeUse) {
             Buf *import_target_path = &top_level_decl->data.use.path;
-            auto entry = g->import_table.maybe_get(import_target_path);
-            if (!entry) {
-                Buf full_path = BUF_INIT;
-                Buf *import_code = buf_alloc();
-                bool found_it = false;
-
-                for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) {
-                    Buf *search_path = g->lib_search_paths.at(path_i);
-                    os_path_join(search_path, import_target_path, &full_path);
+            Buf full_path = BUF_INIT;
+            Buf *import_code = buf_alloc();
+            bool found_it = false;
+
+            for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) {
+                Buf *search_path = g->lib_search_paths.at(path_i);
+                os_path_join(search_path, import_target_path, &full_path);
+
+                Buf *abs_full_path = buf_alloc();
+                if ((err = os_path_real(&full_path, abs_full_path))) {
+                    if (err == ErrorFileNotFound) {
+                        continue;
+                    } else {
+                        add_node_error(g, top_level_decl,
+                                buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
+                        goto done_looking_at_imports;
+                    }
+                }
 
-                    if ((err = os_fetch_file_path(&full_path, import_code))) {
+                auto entry = g->import_table.maybe_get(abs_full_path);
+                if (entry) {
+                    found_it = true;
+                } else {
+                    if ((err = os_fetch_file_path(abs_full_path, import_code))) {
                         if (err == ErrorFileNotFound) {
                             continue;
                         } else {
@@ -1693,14 +1715,14 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *src_dirname, Buf *src
                             goto done_looking_at_imports;
                         }
                     }
-                    codegen_add_code(g, search_path, &top_level_decl->data.use.path, import_code);
+                    codegen_add_code(g, abs_full_path, search_path, &top_level_decl->data.use.path, import_code);
                     found_it = true;
-                    break;
-                }
-                if (!found_it) {
-                    add_node_error(g, top_level_decl,
-                            buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
                 }
+                break;
+            }
+            if (!found_it) {
+                add_node_error(g, top_level_decl,
+                        buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
             }
         } else if (top_level_decl->type == NodeTypeFnDef) {
             AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
@@ -1727,20 +1749,30 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
     os_path_join(src_dir, src_basename, &source_path);
     init(g, &source_path);
 
-    g->root_import = codegen_add_code(g, src_dir, src_basename, source_code);
+    Buf *abs_full_path = buf_alloc();
+    int err;
+    if ((err = os_path_real(&source_path, abs_full_path))) {
+        zig_panic("unable to open '%s': %s", buf_ptr(&source_path), err_str(err));
+    }
+
+    g->root_import = codegen_add_code(g, abs_full_path, src_dir, src_basename, source_code);
 
     if (g->have_exported_main && !g->link_libc && g->out_type != OutTypeLib) {
         Buf *bootstrap_dir = buf_create_from_str(ZIG_STD_DIR);
         Buf *bootstrap_basename = buf_create_from_str("bootstrap.zig");
         Buf path_to_bootstrap_src = BUF_INIT;
         os_path_join(bootstrap_dir, bootstrap_basename, &path_to_bootstrap_src);
+        Buf *abs_full_path = buf_alloc();
+        if ((err = os_path_real(&path_to_bootstrap_src, abs_full_path))) {
+            zig_panic("unable to open '%s': %s", buf_ptr(&path_to_bootstrap_src), err_str(err));
+        }
         Buf *import_code = buf_alloc();
         int err;
-        if ((err = os_fetch_file_path(&path_to_bootstrap_src, import_code))) {
+        if ((err = os_fetch_file_path(abs_full_path, import_code))) {
             zig_panic("unable to open '%s': %s", buf_ptr(&path_to_bootstrap_src), err_str(err));
         }
 
-        codegen_add_code(g, bootstrap_dir, bootstrap_basename, import_code);
+        codegen_add_code(g, abs_full_path, bootstrap_dir, bootstrap_basename, import_code);
     }
 
     if (g->verbose) {
@@ -1963,6 +1995,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
         crt1o = "Scrt1.o";
     }
 
+    // TODO don't pass this parameter unless linking with libc
     char *ZIG_NATIVE_DYNAMIC_LINKER = getenv("ZIG_NATIVE_DYNAMIC_LINKER");
     if (g->is_native_target && ZIG_NATIVE_DYNAMIC_LINKER) {
         if (ZIG_NATIVE_DYNAMIC_LINKER[0] != 0) {
src/os.cpp
@@ -83,6 +83,25 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
     buf_append_buf(out_full_path, basename);
 }
 
+int os_path_real(Buf *rel_path, Buf *out_abs_path) {
+    buf_resize(out_abs_path, PATH_MAX + 1);
+    char *result = realpath(buf_ptr(rel_path), buf_ptr(out_abs_path));
+    if (!result) {
+        int err = errno;
+        if (err == EACCES) {
+            return ErrorAccess;
+        } else if (err == ENOENT) {
+            return ErrorFileNotFound;
+        } else if (err == ENOMEM) {
+            return ErrorNoMem;
+        } else {
+            return ErrorFileSystem;
+        }
+    }
+    buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path)));
+    return ErrorNone;
+}
+
 void os_exec_process(const char *exe, ZigList<const char *> &args,
         int *return_code, Buf *out_stderr, Buf *out_stdout)
 {
src/os.hpp
@@ -19,6 +19,7 @@ void os_exec_process(const char *exe, ZigList<const char *> &args,
 
 void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
 void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
+int os_path_real(Buf *rel_path, Buf *out_abs_path);
 
 void os_write_file(Buf *full_path, Buf *contents);
 
src/parser.cpp
@@ -1113,38 +1113,41 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
         return nullptr;
     }
 
-    Token *token = &pc->tokens->at(*token_index);
-    if (token->id == TokenIdLParen) {
-        *token_index += 1;
+    while (true) {
+        Token *token = &pc->tokens->at(*token_index);
+        if (token->id == TokenIdLParen) {
+            *token_index += 1;
 
-        AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
-        node->data.fn_call_expr.fn_ref_expr = primary_expr;
-        ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
-        return node;
-    } else if (token->id == TokenIdLBracket) {
-        *token_index += 1;
+            AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
+            node->data.fn_call_expr.fn_ref_expr = primary_expr;
+            ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
 
-        AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, token);
-        node->data.array_access_expr.array_ref_expr = primary_expr;
-        node->data.array_access_expr.subscript = ast_parse_expression(pc, token_index, true);
+            primary_expr = node;
+        } else if (token->id == TokenIdLBracket) {
+            *token_index += 1;
 
-        Token *r_bracket = &pc->tokens->at(*token_index);
-        *token_index += 1;
-        ast_expect_token(pc, r_bracket, TokenIdRBracket);
+            AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, token);
+            node->data.array_access_expr.array_ref_expr = primary_expr;
+            node->data.array_access_expr.subscript = ast_parse_expression(pc, token_index, true);
 
-        return node;
-    } else if (token->id == TokenIdDot) {
-        *token_index += 1;
+            Token *r_bracket = &pc->tokens->at(*token_index);
+            *token_index += 1;
+            ast_expect_token(pc, r_bracket, TokenIdRBracket);
 
-        Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
+            primary_expr = node;
+        } else if (token->id == TokenIdDot) {
+            *token_index += 1;
 
-        AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token);
-        node->data.field_access_expr.struct_expr = primary_expr;
-        ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
+            Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
 
-        return node;
-    } else {
-        return primary_expr;
+            AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token);
+            node->data.field_access_expr.struct_expr = primary_expr;
+            ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
+
+            primary_expr = node;
+        } else {
+            return primary_expr;
+        }
     }
 }