diff --git a/code/demo.odin b/code/demo.odin index 3b22859e2..3d737a001 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,4 +1,4 @@ -#import "print.odin" +#import "print.odin" as _ test_proc :: proc() { println("Hello?") diff --git a/code/file.odin b/code/file.odin deleted file mode 100644 index 816672fdf..000000000 --- a/code/file.odin +++ /dev/null @@ -1,106 +0,0 @@ -#import "win32.odin" - -File :: type struct { - Handle :: type HANDLE - handle: Handle -} - -file_open :: proc(name: string) -> (File, bool) { - buf: [300]byte - _ = copy(buf[:], name as []byte) - f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)} - success := f.handle != INVALID_HANDLE_VALUE as File.Handle - - return f, success -} - -file_create :: proc(name: string) -> (File, bool) { - buf: [300]byte - _ = copy(buf[:], name as []byte) - f := File{ - handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null), - } - success := f.handle != INVALID_HANDLE_VALUE as File.Handle - return f, success -} - - -file_close :: proc(f: ^File) { - CloseHandle(f.handle) -} - -file_write :: proc(f: ^File, buf: []byte) -> bool { - bytes_written: i32 - return WriteFile(f.handle, ^buf[0], buf.count as i32, ^bytes_written, null) != 0 -} - -File_Standard :: type enum { - INPUT, - OUTPUT, - ERROR, - COUNT, -} - - -__std_files := __set_file_standards(); - -__set_file_standards :: proc() -> [File_Standard.COUNT as int]File { - return [File_Standard.COUNT as int]File{ - File{handle = GetStdHandle(STD_INPUT_HANDLE)}, - File{handle = GetStdHandle(STD_OUTPUT_HANDLE)}, - File{handle = GetStdHandle(STD_ERROR_HANDLE)}, - } -} - -file_get_standard :: proc(std: File_Standard) -> ^File { - return ^__std_files[std] -} - - -read_entire_file :: proc(name: string) -> (string, bool) { - buf: [300]byte - _ = copy(buf[:], name as []byte) - c_string := ^buf[0] - - - f, file_ok := file_open(name) - if !file_ok { - return "", false - } - defer file_close(^f) - - length: i64 - file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0 - if !file_size_ok { - return "", false - } - - data := new_slice(u8, length) - if ^data[0] == null { - return "", false - } - - single_read_length: i32 - total_read: i64 - - for total_read < length { - remaining := length - total_read - to_read: u32 - MAX :: 0x7fffffff - if remaining <= MAX { - to_read = remaining as u32 - } else { - to_read = MAX - } - - ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null) - if single_read_length <= 0 { - free(^data[0]) - return "", false - } - - total_read += single_read_length as i64 - } - - return data as string, true -} diff --git a/code/print.odin b/code/print.odin index 6095730a6..b8f326151 100644 --- a/code/print.odin +++ b/code/print.odin @@ -1,6 +1,5 @@ -#import "runtime.odin" -#import "win32.odin" -#import "file.odin" +#import "runtime.odin" as _ +#import "os.odin" as os print_byte_buffer :: proc(buf: ^[]byte, b: []byte) { if buf.count < buf.capacity { @@ -555,31 +554,31 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) { PRINT_BUF_SIZE :: 1<<12 -print_to_file :: proc(f: ^File, fmt: string, args: ..any) { +print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) { data: [PRINT_BUF_SIZE]byte buf := data[:0] print_to_buffer(^buf, fmt, ..args) - file_write(f, buf) + os.write(f, buf) } -println_to_file :: proc(f: ^File, fmt: string, args: ..any) { +println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) { data: [PRINT_BUF_SIZE]byte buf := data[:0] print_to_buffer(^buf, fmt, ..args) print_nl_to_buffer(^buf) - file_write(f, buf) + os.write(f, buf) } print :: proc(fmt: string, args: ..any) { - print_to_file(file_get_standard(File_Standard.OUTPUT), fmt, ..args) + print_to_file(os.file_get_standard(os.File_Standard.OUTPUT), fmt, ..args) } print_err :: proc(fmt: string, args: ..any) { - print_to_file(file_get_standard(File_Standard.ERROR), fmt, ..args) + print_to_file(os.file_get_standard(os.File_Standard.ERROR), fmt, ..args) } println :: proc(fmt: string, args: ..any) { - println_to_file(file_get_standard(File_Standard.OUTPUT), fmt, ..args) + println_to_file(os.file_get_standard(os.File_Standard.OUTPUT), fmt, ..args) } println_err :: proc(fmt: string, args: ..any) { - println_to_file(file_get_standard(File_Standard.ERROR), fmt, ..args) + println_to_file(os.file_get_standard(os.File_Standard.ERROR), fmt, ..args) } diff --git a/code/runtime.odin b/code/runtime.odin index 89d3f7861..2c3a8ca43 100644 --- a/code/runtime.odin +++ b/code/runtime.odin @@ -1,9 +1,9 @@ #global_scope // TODO(bill): Remove #import in runtime.odin -#import "win32.odin" -#import "file.odin" -#import "print.odin" +#import "win32.odin" as win32 +#import "os.odin" as os +#import "print.odin" as _ // IMPORTANT NOTE(bill): Do not change the order of any of this data // The compiler relies upon this _exact_ order @@ -84,15 +84,15 @@ fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" heap_alloc :: proc(len: int) -> rawptr { - return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len) + return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, len) } heap_free :: proc(ptr: rawptr) { - _ = HeapFree(GetProcessHeap(), 0, ptr) + _ = win32.HeapFree(win32.GetProcessHeap(), 0, ptr) } current_thread_id :: proc() -> int { - id := GetCurrentThreadId() + id := win32.GetCurrentThreadId() return id as int } @@ -171,7 +171,7 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > __assert :: proc(msg: string) { - file_write(file_get_standard(File_Standard.ERROR), msg as []byte) + os.write(os.file_get_standard(os.File_Standard.ERROR), msg as []byte) __debug_trap() } diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 19df9a1b4..6de9858eb 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -315,7 +315,7 @@ void check_close_scope(Checker *c) { c->context.scope = c->context.scope->parent; } -void scope_lookup_parent_entity(Checker *c, Scope *scope, String name, Scope **scope_, Entity **entity_) { +void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entity **entity_) { b32 gone_thru_proc = false; HashKey key = hash_string(name); for (Scope *s = scope; s != NULL; s = s->parent) { @@ -366,9 +366,9 @@ void scope_lookup_parent_entity(Checker *c, Scope *scope, String name, Scope **s if (scope_) *scope_ = NULL; } -Entity *scope_lookup_entity(Checker *c, Scope *s, String name) { +Entity *scope_lookup_entity(Scope *s, String name) { Entity *entity = NULL; - scope_lookup_parent_entity(c, s, name, NULL, &entity); + scope_lookup_parent_entity(s, name, NULL, &entity); return entity; } @@ -949,33 +949,41 @@ void check_parsed_files(Checker *c) { gb_for_array(decl_index, f->decls) { AstNode *decl = f->decls[decl_index]; - switch (decl->kind) { - case_ast_node(id, ImportDecl, decl); - HashKey key = hash_string(id->fullpath); - auto found = map_get(&file_scopes, key); - GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath)); - Scope *scope = *found; - b32 previously_added = false; - gb_for_array(import_index, file_scope->imported) { - Scope *prev = file_scope->imported[import_index]; - if (prev == scope) { - previously_added = true; - break; - } - } - if (!previously_added) { - gb_array_append(file_scope->imported, scope); - } + if (decl->kind != AstNode_ImportDecl) { + continue; + } + ast_node(id, ImportDecl, decl); + HashKey key = hash_string(id->fullpath); + auto found = map_get(&file_scopes, key); + GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath)); + Scope *scope = *found; + b32 previously_added = false; + gb_for_array(import_index, file_scope->imported) { + Scope *prev = file_scope->imported[import_index]; + if (prev == scope) { + previously_added = true; + break; + } + } + if (!previously_added) { + gb_array_append(file_scope->imported, scope); + } + + if (are_strings_equal(id->import_name.string, make_string("_"))) { // NOTE(bill): Add imported entities to this file's scope gb_for_array(elem_index, scope->elements.entries) { Entity *e = scope->elements.entries[elem_index].value; // NOTE(bill): Do not add other imported entities - if (e->scope == scope) { + if (e->scope == scope && e->kind != Entity_ImportName) { add_entity(c, file_scope, NULL, e); } } - case_end; + } else { + Entity *e = make_entity_import_name(c->allocator, file_scope, id->import_name, t_invalid, + id->fullpath, id->import_name.string, + scope); + add_entity(c, file_scope, NULL, e); } } } diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index 85e668c0d..3814f38f0 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -9,6 +9,7 @@ enum BuiltinProcId; ENTITY_KIND(TypeName), \ ENTITY_KIND(Procedure), \ ENTITY_KIND(Builtin), \ + ENTITY_KIND(ImportName), \ ENTITY_KIND(Count), @@ -49,11 +50,19 @@ struct Entity { i32 field_index; // Order in source b8 is_field; // Is struct field } Variable; - struct {} TypeName; + struct { + struct DeclInfo *decl; // Usually NULL + } TypeName; struct { b8 pure; } Procedure; struct { BuiltinProcId id; } Builtin; + struct { + String path; + String name; + Scope *scope; + b32 used; + } ImportName; }; }; @@ -124,6 +133,15 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type return entity; } +Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type, + String path, String name, Scope *import_scope) { + Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type); + entity->ImportName.path = path; + entity->ImportName.name = name; + entity->ImportName.scope = import_scope; + return entity; +} + Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) { token.string = make_string("_"); return make_entity_variable(a, file_scope, token, NULL); diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 4389b7884..0d113af23 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -286,8 +286,9 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = td->name->Ident; Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL); - check_type_decl(c, e, td->type, NULL, NULL); add_entity(c, c->context.scope, td->name, e); + gb_printf("%.*s\n", LIT(e->token.string)); + check_type_decl(c, e, td->type, NULL, NULL); HashKey key = hash_string(name_token.string); if (map_get(&entity_map, key) != NULL) { @@ -728,10 +729,14 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl GB_ASSERT(n->kind == AstNode_Ident); o->mode = Addressing_Invalid; o->expr = n; - Entity *e = scope_lookup_entity(c, c->context.scope, n->Ident.string); + Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string); if (e == NULL) { - error(&c->error_collector, n->Ident, - "Undeclared type or identifier `%.*s`", LIT(n->Ident.string)); + if (are_strings_equal(n->Ident.string, make_string("_"))) { + error(&c->error_collector, n->Ident, "`_` cannot be used as a value type"); + } else { + error(&c->error_collector, n->Ident, + "Undeclared named: `%.*s`", LIT(n->Ident.string)); + } return; } add_entity_use(&c->info, n, e); @@ -744,14 +749,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl gb_array_free(local_cycle_checker.path); }); - if (e->type == NULL) { - auto *found = map_get(&c->info.entities, hash_pointer(e)); - if (found != NULL) { - check_entity_decl(c, e, *found, named_type, cycle_checker); - } else { - GB_PANIC("Internal Compiler Error: DeclInfo not found!"); - } - } + check_entity_decl(c, e, NULL, named_type, cycle_checker); if (e->type == NULL) { GB_PANIC("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(n->Ident.string)); @@ -808,6 +806,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl o->mode = Addressing_Builtin; break; + case Entity_ImportName: + error(&c->error_collector, ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name)); + return; + default: GB_PANIC("Compiler error: Unknown EntityKind"); break; @@ -875,18 +877,30 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c case_ast_node(se, SelectorExpr, e); Operand o = {}; - o.mode = Addressing_Type; - o.type = check_type(c, se->expr, named_type, cycle_checker); - // gb_printf_err("mode: %.*s\n", LIT(addressing_mode_strings[o.mode])); check_selector(c, &o, e); - // gb_printf_err("%s.%s\n", expr_to_string(se->expr), expr_to_string(se->selector)); - // gb_printf_err("%s\n", type_to_string(o.type)); - // gb_printf_err("mode: %.*s\n", LIT(addressing_mode_strings[o.mode])); - if (o.mode == Addressing_Type) { + switch (o.mode) { + case Addressing_Type: + GB_ASSERT(o.type != NULL); set_base_type(type, o.type); o.type->flags |= e->type_flags; return o.type; + + case Addressing_Invalid: + break; + case Addressing_NoValue: { + gbString err = expr_to_string(e); + defer (gb_string_free(err)); + error(&c->error_collector, ast_node_token(e), "`%s` used as a type", err); + } break; + default: { + gbString err = expr_to_string(e); + defer (gb_string_free(err)); + error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err); + } break; + } + + if (o.mode == Addressing_Type) { } case_end; @@ -1959,54 +1973,90 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu } Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { - GB_ASSERT(node->kind == AstNode_SelectorExpr); - ast_node(se, SelectorExpr, node); + + b32 check_op_expr = true; + Entity *entity = NULL; + AstNode *op_expr = se->expr; - AstNode *selector = se->selector; - if (selector) { - Entity *entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity; - if (entity == NULL) { - gbString op_str = expr_to_string(op_expr); - gbString type_str = type_to_string(operand->type); - gbString sel_str = expr_to_string(selector); - defer (gb_string_free(op_str)); - defer (gb_string_free(type_str)); - defer (gb_string_free(sel_str)); - error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); - operand->mode = Addressing_Invalid; - operand->expr = node; - return NULL; - } - add_entity_use(&c->info, selector, entity); - - operand->type = entity->type; - operand->expr = node; - switch (entity->kind) { - case Entity_Constant: - operand->mode = Addressing_Constant; - operand->value = entity->Constant.value; - break; - case Entity_Variable: - operand->mode = Addressing_Variable; - break; - case Entity_TypeName: - operand->mode = Addressing_Type; - break; - case Entity_Procedure: - operand->mode = Addressing_Value; - break; - case Entity_Builtin: - operand->mode = Addressing_Builtin; - operand->builtin_id = entity->Builtin.id; - break; - } - - return entity; - } else { - operand->mode = Addressing_Invalid; - operand->expr = node; + AstNode *selector = unparen_expr(se->selector); + if (selector == NULL) { + goto error; } + + GB_ASSERT(selector->kind == AstNode_Ident); + + if (op_expr->kind == AstNode_Ident) { + String name = op_expr->Ident.string; + Entity *e = scope_lookup_entity(c->context.scope, name); + add_entity_use(&c->info, op_expr, e); + if (e != NULL && e->kind == Entity_ImportName) { + check_op_expr = false; + entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string); + add_entity_use(&c->info, selector, entity); + if (entity == NULL) { + gbString sel_str = expr_to_string(selector); + defer (gb_string_free(sel_str)); + error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared in `%.*s`", sel_str, LIT(name)); + goto error; + } + if (entity->type == NULL) { // Not setup yet + check_entity_decl(c, entity, NULL, NULL); + } + GB_ASSERT(entity->type != NULL); + } + } + if (check_op_expr) { + check_expr_base(c, operand, op_expr); + if (operand->mode == Addressing_Invalid) { + goto error; + } + } + + if (entity == NULL) { + entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity; + } + if (entity == NULL) { + gbString op_str = expr_to_string(op_expr); + gbString type_str = type_to_string(operand->type); + gbString sel_str = expr_to_string(selector); + defer (gb_string_free(op_str)); + defer (gb_string_free(type_str)); + defer (gb_string_free(sel_str)); + error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); + goto error; + } + + + add_entity_use(&c->info, selector, entity); + + operand->type = entity->type; + operand->expr = node; + switch (entity->kind) { + case Entity_Constant: + operand->mode = Addressing_Constant; + operand->value = entity->Constant.value; + break; + case Entity_Variable: + operand->mode = Addressing_Variable; + break; + case Entity_TypeName: + operand->mode = Addressing_Type; + break; + case Entity_Procedure: + operand->mode = Addressing_Value; + break; + case Entity_Builtin: + operand->mode = Addressing_Builtin; + operand->builtin_id = entity->Builtin.id; + break; + } + + return entity; + +error: + operand->mode = Addressing_Invalid; + operand->expr = node; return NULL; } @@ -3202,7 +3252,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(se, SelectorExpr, node); - check_expr_base(c, o, se->expr); check_selector(c, o, node); case_end; diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 79d4266fd..d97b68d14 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -171,7 +171,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { b32 used = false; if (node->kind == AstNode_Ident) { ast_node(i, Ident, node); - e = scope_lookup_entity(c, c->context.scope, i->string); + e = scope_lookup_entity(c->context.scope, i->string); if (e != NULL && e->kind == Entity_Variable) { used = e->Variable.used; // TODO(bill): Make backup just in case } @@ -374,9 +374,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle gb_array_free(local_cycle_checker.path); }); - check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e)); - - + Type *base_type = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e)); + named->Named.base = base_type; named->Named.base = get_base_type(named->Named.base); if (named->Named.base == t_invalid) { // gb_printf("check_type_decl: %s\n", type_to_string(named)); @@ -562,22 +561,41 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) { - if (e->type != NULL) - return; + if (e->type != NULL) { + if (e->type->kind == Type_Named && e->type->Named.base == NULL) { + // NOTE(bill): Some weird declaration error from Entity_ImportName + } else { + return; + } + } + + if (d == NULL) { + DeclInfo **found = map_get(&c->info.entities, hash_pointer(e)); + if (found) { + d = *found; + } else { + GB_PANIC("`%.*s` should been declared!", LIT(e->token.string)); + } + } + switch (e->kind) { case Entity_Constant: { Scope *prev = c->context.scope; c->context.scope = d->scope; - defer (c->context.scope = prev); c->context.decl = d; + check_const_decl(c, e, d->type_expr, d->init_expr); + + c->context.scope = prev; } break; case Entity_Variable: { Scope *prev = c->context.scope; c->context.scope = d->scope; - defer (c->context.scope = prev); c->context.decl = d; + check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr); + + c->context.scope = prev; } break; case Entity_TypeName: { CycleChecker local_cycle_checker = {}; @@ -1234,7 +1252,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { AstNode *expr = unparen_expr(es->expr); if (expr->kind == AstNode_Ident) { String name = expr->Ident.string; - e = scope_lookup_entity(c, c->context.scope, name); + e = scope_lookup_entity(c->context.scope, name); } else if (expr->kind == AstNode_SelectorExpr) { Operand o = {}; check_expr_base(c, &o, expr->SelectorExpr.expr); @@ -1285,6 +1303,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { } } break; + case Entity_ImportName: { + Scope *scope = e->ImportName.scope; + gb_for_array(i, scope->elements.entries) { + Entity *decl = scope->elements.entries[i].value; + Entity *found = scope_insert_entity(c->context.scope, decl); + if (found != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + return; + } + } + } break; + case Entity_Constant: error(&c->error_collector, us->token, "`using` cannot be applied to a constant"); break; @@ -1334,7 +1364,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { AstNode *item = vd->names[name_index]; ast_node(i, Ident, item); String name = i->string; - Entity *e = scope_lookup_entity(c, c->context.scope, name); + Entity *e = scope_lookup_entity(c->context.scope, name); Type *t = get_base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 43f894fb4..f45c852c8 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -84,6 +84,7 @@ void ssa_gen_tree(ssaGen *s) { if (str[i] == '\\') { str[i] = '/'; } + } char const *base = gb_path_base_name(str); char const *ext = gb_path_extension(base); diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 7ec3b369d..1015207c4 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -744,7 +744,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) { if (proc->body == NULL) { - ssa_fprintf(f, "\ndeclare "); + ssa_fprintf(f, "declare "); } else { ssa_fprintf(f, "\ndefine "); } @@ -844,47 +844,64 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) { gb_for_array(member_index, m->members.entries) { auto *entry = &m->members.entries[member_index]; ssaValue *v = entry->value; - switch (v->kind) { - case ssaValue_TypeName: - ssa_print_type_name(f, m, v); - break; + if (v->kind != ssaValue_TypeName) { + continue; + } + ssa_print_type_name(f, m, v); + } + + gb_for_array(member_index, m->members.entries) { + auto *entry = &m->members.entries[member_index]; + ssaValue *v = entry->value; + if (v->kind != ssaValue_Proc) { + continue; + } + if (v->Proc.body == NULL) { + ssa_print_proc(f, m, &v->Proc); } } gb_for_array(member_index, m->members.entries) { auto *entry = &m->members.entries[member_index]; ssaValue *v = entry->value; - switch (v->kind) { - case ssaValue_Global: { - auto *g = &v->Global; - ssa_print_encoded_global(f, g->entity->token.string); - ssa_fprintf(f, " = "); - if (g->is_thread_local) { - ssa_fprintf(f, "thread_local "); - } - if (g->is_constant) { - if (g->is_private) { - ssa_fprintf(f, "private "); - } - ssa_fprintf(f, "constant "); - } else { - ssa_fprintf(f, "global "); - } - - - ssa_print_type(f, m->sizes, g->entity->type); - ssa_fprintf(f, " "); - if (g->value != NULL) { - ssa_print_value(f, m, g->value, g->entity->type); - } else { - ssa_fprintf(f, "zeroinitializer"); - } - ssa_fprintf(f, "\n"); - } break; - - case ssaValue_Proc: { + if (v->kind != ssaValue_Proc) { + continue; + } + if (v->Proc.body != NULL) { ssa_print_proc(f, m, &v->Proc); - } break; } } + + + gb_for_array(member_index, m->members.entries) { + auto *entry = &m->members.entries[member_index]; + ssaValue *v = entry->value; + if (v->kind != ssaValue_Global) { + continue; + } + auto *g = &v->Global; + ssa_print_encoded_global(f, g->entity->token.string); + ssa_fprintf(f, " = "); + if (g->is_thread_local) { + ssa_fprintf(f, "thread_local "); + } + if (g->is_constant) { + if (g->is_private) { + ssa_fprintf(f, "private "); + } + ssa_fprintf(f, "constant "); + } else { + ssa_fprintf(f, "global "); + } + + + ssa_print_type(f, m->sizes, g->entity->type); + ssa_fprintf(f, " "); + if (g->value != NULL) { + ssa_print_value(f, m, g->value, g->entity->type); + } else { + ssa_fprintf(f, "zeroinitializer"); + } + ssa_fprintf(f, "\n"); + } } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 89443a1dd..268778493 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -927,6 +927,11 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) { ssaValue *v = ssa_emit_load(proc, lval.addr); return ssa_emit(proc, ssa_make_instr_extract_element(proc, v, lval.index)); } + // HACK(bill): Imported procedures don't require a load + Type *t = get_base_type(ssa_type(lval.addr)); + if (t->kind == Type_Proc) { + return lval.addr; + } return ssa_emit_load(proc, lval.addr); } GB_PANIC("Illegal lvalue load"); @@ -2519,13 +2524,20 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(se, SelectorExpr, expr); ssa_emit_comment(proc, make_string("SelectorExpr")); Type *type = get_base_type(type_of_expr(proc->module->info, se->expr)); + String selector = unparen_expr(se->selector)->Ident.string; + if (type == t_invalid) { + Entity *imp = entity_of_ident(proc->module->info, se->expr); + GB_ASSERT(imp->kind == Entity_ImportName); + // Entity *e = scope_lookup_entity(e->ImportName.scope, selector); + return ssa_build_addr(proc, unparen_expr(se->selector)); + } else { + Selection sel = lookup_field(type, selector, false); + GB_ASSERT(sel.entity != NULL); - Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.string, false); - GB_ASSERT(sel.entity != NULL); - - ssaValue *e = ssa_build_addr(proc, se->expr).addr; - e = ssa_emit_deep_field_gep(proc, type, e, sel); - return ssa_make_addr(e, expr); + ssaValue *e = ssa_build_addr(proc, se->expr).addr; + e = ssa_emit_deep_field_gep(proc, type, e, sel); + return ssa_make_addr(e, expr); + } case_end; case_ast_node(ue, UnaryExpr, expr); diff --git a/src/parser.cpp b/src/parser.cpp index 7f4e842ae..57f5f8eff 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -43,11 +43,15 @@ struct AstFile { TokenPos fix_prev_pos; }; +struct ImportedFile { + String path; + TokenPos pos; // #import +}; struct Parser { String init_fullpath; gbArray(AstFile) files; - gbArray(String) imports; + gbArray(ImportedFile) imports; gbArray(String) libraries; gbArray(String) system_libraries; isize load_index; @@ -232,7 +236,8 @@ AST_NODE_KIND(_DeclBegin, "", struct{}) \ AST_NODE_KIND(TypeDecl, "type declaration", struct { Token token; AstNode *name, *type; }) \ AST_NODE_KIND(ImportDecl, "import declaration", struct { \ Token token, relpath; \ - String fullpath; \ + String fullpath; \ + Token import_name; \ }) \ AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \ AST_NODE_KIND(_DeclEnd, "", struct{}) \ @@ -883,10 +888,11 @@ gb_inline AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNod return result; } -gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath) { +gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath, Token import_name) { AstNode *result = make_node(f, AstNode_ImportDecl); result->ImportDecl.token = token; result->ImportDecl.relpath = relpath; + result->ImportDecl.import_name = import_name; return result; } @@ -2541,9 +2547,13 @@ AstNode *parse_stmt(AstFile *f) { ast_file_err(f, token, "You cannot use #global_scope within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, f->cursor[0]); } else if (are_strings_equal(tag, make_string("import"))) { + // TODO(bill): better error messages Token file_path = expect_token(f, Token_String); + Token as = expect_token(f, Token_as); + Token import_name = expect_token(f, Token_Identifier); + if (f->curr_proc == NULL) { - return make_import_decl(f, s->TagStmt.token, file_path); + return make_import_decl(f, s->TagStmt.token, file_path, import_name); } ast_file_err(f, token, "You cannot use #import within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); @@ -2695,15 +2705,18 @@ void destroy_parser(Parser *p) { } // NOTE(bill): Returns true if it's added -b32 try_add_import_path(Parser *p, String import_file, AstNode *node) { +b32 try_add_import_path(Parser *p, String path, TokenPos pos) { gb_for_array(i, p->imports) { - String import = p->imports[i]; - if (are_strings_equal(import, import_file)) { + String import = p->imports[i].path; + if (are_strings_equal(import, path)) { return false; } } - gb_array_append(p->imports, import_file); + ImportedFile item; + item.path = path; + item.pos = pos; + gb_array_append(p->imports, item); return true; } @@ -2799,7 +2812,7 @@ void parse_file(Parser *p, AstFile *f) { String import_file = make_string(path_str); id->fullpath = import_file; - if (!try_add_import_path(p, import_file, node)) { + if (!try_add_import_path(p, import_file, ast_node_token(node).pos)) { // gb_free(gb_heap_allocator(), import_file.text); } } else if (node->kind == AstNode_ForeignSystemLibrary) { @@ -2821,14 +2834,20 @@ void parse_file(Parser *p, AstFile *f) { ParseFileError parse_files(Parser *p, char *init_filename) { char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename); String init_fullpath = make_string(fullpath_str); - gb_array_append(p->imports, init_fullpath); + TokenPos init_pos = {}; + ImportedFile init_imported_file = {init_fullpath, init_pos}; + gb_array_append(p->imports, init_imported_file); p->init_fullpath = init_fullpath; gb_for_array(i, p->imports) { - String import_path = p->imports[i]; + String import_path = p->imports[i].path; + TokenPos pos = p->imports[i].pos; AstFile file = {}; ParseFileError err = init_ast_file(&file, import_path); if (err != ParseFile_None) { + if (pos.line != 0) { + gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column); + } gb_printf_err("Failed to parse file: %.*s\n", LIT(import_path)); switch (err) { case ParseFile_WrongExtension: