From 4d45d14b557365bfb5b9059347ec144784d481b7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Dec 2015 21:48:41 -0700 Subject: [PATCH] use realpath to avoid duplicate imports --- example/structs/structs.zig | 20 +++++++++ src/codegen.cpp | 81 ++++++++++++++++++++++++++----------- src/os.cpp | 19 +++++++++ src/os.hpp | 1 + src/parser.cpp | 53 ++++++++++++------------ 5 files changed, 125 insertions(+), 49 deletions(-) diff --git a/example/structs/structs.zig b/example/structs/structs.zig index e4e949c62b..0d32f010c3 100644 --- a/example/structs/structs.zig +++ b/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"); + } +} diff --git a/src/codegen.cpp b/src/codegen.cpp index c29e3653eb..9adc78a573 100644 --- a/src/codegen.cpp +++ b/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 *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; + 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); + 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); - if ((err = os_fetch_file_path(&full_path, import_code))) { + 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; + } + } + + 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) { diff --git a/src/os.cpp b/src/os.cpp index b7af9a599d..d099c3482c 100644 --- a/src/os.cpp +++ b/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 &args, int *return_code, Buf *out_stderr, Buf *out_stdout) { diff --git a/src/os.hpp b/src/os.hpp index 7b71437852..bc7679464a 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -19,6 +19,7 @@ void os_exec_process(const char *exe, ZigList &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); diff --git a/src/parser.cpp b/src/parser.cpp index 3231cc0d2f..65f9c7e6da 100644 --- a/src/parser.cpp +++ b/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; + } } }