Browse Source

#import "" as namespace

Ginger Bill 9 years ago
parent
commit
79f575ae8e
12 changed files with 315 additions and 268 deletions
  1. 1 1
      code/demo.odin
  2. 0 106
      code/file.odin
  3. 10 11
      code/print.odin
  4. 7 7
      code/runtime.odin
  5. 29 21
      src/checker/checker.cpp
  6. 19 1
      src/checker/entity.cpp
  7. 111 62
      src/checker/expr.cpp
  8. 40 10
      src/checker/stmt.cpp
  9. 1 0
      src/codegen/codegen.cpp
  10. 49 32
      src/codegen/print_llvm.cpp
  11. 18 6
      src/codegen/ssa.cpp
  12. 30 11
      src/parser.cpp

+ 1 - 1
code/demo.odin

@@ -1,4 +1,4 @@
-#import "print.odin"
+#import "print.odin" as _
 
 
 test_proc :: proc() {
 test_proc :: proc() {
 	println("Hello?")
 	println("Hello?")

+ 0 - 106
code/file.odin

@@ -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
-}

+ 10 - 11
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) {
 print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
 	if buf.count < buf.capacity {
 	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_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
 	data: [PRINT_BUF_SIZE]byte
 	buf := data[:0]
 	buf := data[:0]
 	print_to_buffer(^buf, fmt, ..args)
 	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
 	data: [PRINT_BUF_SIZE]byte
 	buf := data[:0]
 	buf := data[:0]
 	print_to_buffer(^buf, fmt, ..args)
 	print_to_buffer(^buf, fmt, ..args)
 	print_nl_to_buffer(^buf)
 	print_nl_to_buffer(^buf)
-	file_write(f, buf)
+	os.write(f, buf)
 }
 }
 
 
 
 
 print :: proc(fmt: string, args: ..any) {
 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_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 :: 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_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)
 }
 }

+ 7 - 7
code/runtime.odin

@@ -1,9 +1,9 @@
 #global_scope
 #global_scope
 
 
 // TODO(bill): Remove #import in runtime.odin
 // 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
 // IMPORTANT NOTE(bill): Do not change the order of any of this data
 // The compiler relies upon this _exact_ order
 // 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"
 fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
 heap_alloc   :: proc(len: int) -> rawptr {
 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) {
 heap_free :: proc(ptr: rawptr) {
-	_ = HeapFree(GetProcessHeap(), 0, ptr)
+	_ = win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
 }
 }
 
 
 current_thread_id :: proc() -> int {
 current_thread_id :: proc() -> int {
-	id := GetCurrentThreadId()
+	id := win32.GetCurrentThreadId()
 	return id as int
 	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) {
 __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()
 	__debug_trap()
 }
 }
 
 

+ 29 - 21
src/checker/checker.cpp

@@ -315,7 +315,7 @@ void check_close_scope(Checker *c) {
 	c->context.scope = c->context.scope->parent;
 	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;
 	b32 gone_thru_proc = false;
 	HashKey key = hash_string(name);
 	HashKey key = hash_string(name);
 	for (Scope *s = scope; s != NULL; s = s->parent) {
 	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;
 	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;
 	Entity *entity = NULL;
-	scope_lookup_parent_entity(c, s, name, NULL, &entity);
+	scope_lookup_parent_entity(s, name, NULL, &entity);
 	return entity;
 	return entity;
 }
 }
 
 
@@ -949,33 +949,41 @@ void check_parsed_files(Checker *c) {
 
 
 		gb_for_array(decl_index, f->decls) {
 		gb_for_array(decl_index, f->decls) {
 			AstNode *decl = f->decls[decl_index];
 			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
 				// NOTE(bill): Add imported entities to this file's scope
 				gb_for_array(elem_index, scope->elements.entries) {
 				gb_for_array(elem_index, scope->elements.entries) {
 					Entity *e = scope->elements.entries[elem_index].value;
 					Entity *e = scope->elements.entries[elem_index].value;
 					// NOTE(bill): Do not add other imported entities
 					// 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);
 						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);
 			}
 			}
 		}
 		}
 	}
 	}

+ 19 - 1
src/checker/entity.cpp

@@ -9,6 +9,7 @@ enum BuiltinProcId;
 	ENTITY_KIND(TypeName), \
 	ENTITY_KIND(TypeName), \
 	ENTITY_KIND(Procedure), \
 	ENTITY_KIND(Procedure), \
 	ENTITY_KIND(Builtin), \
 	ENTITY_KIND(Builtin), \
+	ENTITY_KIND(ImportName), \
 	ENTITY_KIND(Count),
 	ENTITY_KIND(Count),
 
 
 
 
@@ -49,11 +50,19 @@ struct Entity {
 			i32 field_index; // Order in source
 			i32 field_index; // Order in source
 			b8  is_field;    // Is struct field
 			b8  is_field;    // Is struct field
 		} Variable;
 		} Variable;
-		struct {} TypeName;
+		struct {
+			struct DeclInfo *decl; // Usually NULL
+		} TypeName;
 		struct {
 		struct {
 			b8 pure;
 			b8 pure;
 		} Procedure;
 		} Procedure;
 		struct { BuiltinProcId id; } Builtin;
 		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;
 	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) {
 Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
 	token.string = make_string("_");
 	token.string = make_string("_");
 	return make_entity_variable(a, file_scope, token, NULL);
 	return make_entity_variable(a, file_scope, token, NULL);

+ 111 - 62
src/checker/expr.cpp

@@ -286,8 +286,9 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 			Token name_token = td->name->Ident;
 			Token name_token = td->name->Ident;
 
 
 			Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
 			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);
 			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);
 			HashKey key = hash_string(name_token.string);
 			if (map_get(&entity_map, key) != NULL) {
 			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);
 	GB_ASSERT(n->kind == AstNode_Ident);
 	o->mode = Addressing_Invalid;
 	o->mode = Addressing_Invalid;
 	o->expr = n;
 	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) {
 	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;
 		return;
 	}
 	}
 	add_entity_use(&c->info, n, e);
 	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);
 		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) {
 	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));
 		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;
 		o->mode = Addressing_Builtin;
 		break;
 		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:
 	default:
 		GB_PANIC("Compiler error: Unknown EntityKind");
 		GB_PANIC("Compiler error: Unknown EntityKind");
 		break;
 		break;
@@ -875,18 +877,30 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
 
 
 	case_ast_node(se, SelectorExpr, e);
 	case_ast_node(se, SelectorExpr, e);
 		Operand o = {};
 		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);
 		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);
 			set_base_type(type, o.type);
 			o.type->flags |= e->type_flags;
 			o.type->flags |= e->type_flags;
 			return o.type;
 			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;
 	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) {
 Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
-	GB_ASSERT(node->kind == AstNode_SelectorExpr);
-
 	ast_node(se, SelectorExpr, node);
 	ast_node(se, SelectorExpr, node);
+
+	b32 check_op_expr = true;
+	Entity *entity = NULL;
+
 	AstNode *op_expr  = se->expr;
 	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);
+	AstNode *selector = unparen_expr(se->selector);
+	if (selector == NULL) {
+		goto error;
+	}
 
 
-		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;
+	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;
 		}
 		}
+	}
 
 
-		return entity;
-	} else {
-		operand->mode = Addressing_Invalid;
-		operand->expr = node;
+	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;
 	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);
 	case_ast_node(se, SelectorExpr, node);
-		check_expr_base(c, o, se->expr);
 		check_selector(c, o, node);
 		check_selector(c, o, node);
 	case_end;
 	case_end;
 
 

+ 40 - 10
src/checker/stmt.cpp

@@ -171,7 +171,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 	b32 used = false;
 	b32 used = false;
 	if (node->kind == AstNode_Ident) {
 	if (node->kind == AstNode_Ident) {
 		ast_node(i, Ident, node);
 		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) {
 		if (e != NULL && e->kind == Entity_Variable) {
 			used = e->Variable.used; // TODO(bill): Make backup just in case
 			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);
 		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);
 	named->Named.base = get_base_type(named->Named.base);
 	if (named->Named.base == t_invalid) {
 	if (named->Named.base == t_invalid) {
 		// gb_printf("check_type_decl: %s\n", type_to_string(named));
 		// 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) {
 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) {
 	switch (e->kind) {
 	case Entity_Constant: {
 	case Entity_Constant: {
 		Scope *prev = c->context.scope;
 		Scope *prev = c->context.scope;
 		c->context.scope = d->scope;
 		c->context.scope = d->scope;
-		defer (c->context.scope = prev);
 		c->context.decl = d;
 		c->context.decl = d;
+
 		check_const_decl(c, e, d->type_expr, d->init_expr);
 		check_const_decl(c, e, d->type_expr, d->init_expr);
+
+		c->context.scope = prev;
 	} break;
 	} break;
 	case Entity_Variable: {
 	case Entity_Variable: {
 		Scope *prev = c->context.scope;
 		Scope *prev = c->context.scope;
 		c->context.scope = d->scope;
 		c->context.scope = d->scope;
-		defer (c->context.scope = prev);
 		c->context.decl = d;
 		c->context.decl = d;
+
 		check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
 		check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
+
+		c->context.scope = prev;
 	} break;
 	} break;
 	case Entity_TypeName: {
 	case Entity_TypeName: {
 		CycleChecker local_cycle_checker = {};
 		CycleChecker local_cycle_checker = {};
@@ -1234,7 +1252,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			AstNode *expr = unparen_expr(es->expr);
 			AstNode *expr = unparen_expr(es->expr);
 			if (expr->kind == AstNode_Ident) {
 			if (expr->kind == AstNode_Ident) {
 				String name = expr->Ident.string;
 				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) {
 			} else if (expr->kind == AstNode_SelectorExpr) {
 				Operand o = {};
 				Operand o = {};
 				check_expr_base(c, &o, expr->SelectorExpr.expr);
 				check_expr_base(c, &o, expr->SelectorExpr.expr);
@@ -1285,6 +1303,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 				}
 				}
 			} break;
 			} 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:
 			case Entity_Constant:
 				error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
 				error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
 				break;
 				break;
@@ -1334,7 +1364,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 				AstNode *item = vd->names[name_index];
 				AstNode *item = vd->names[name_index];
 				ast_node(i, Ident, item);
 				ast_node(i, Ident, item);
 				String name = i->string;
 				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));
 				Type *t = get_base_type(type_deref(e->type));
 				if (is_type_struct(t) || is_type_raw_union(t)) {
 				if (is_type_struct(t) || is_type_raw_union(t)) {
 					Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
 					Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));

+ 1 - 0
src/codegen/codegen.cpp

@@ -84,6 +84,7 @@ void ssa_gen_tree(ssaGen *s) {
 				if (str[i] == '\\') {
 				if (str[i] == '\\') {
 					str[i] = '/';
 					str[i] = '/';
 				}
 				}
+
 			}
 			}
 			char const *base = gb_path_base_name(str);
 			char const *base = gb_path_base_name(str);
 			char const *ext = gb_path_extension(base);
 			char const *ext = gb_path_extension(base);

+ 49 - 32
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) {
 void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	if (proc->body == NULL) {
 	if (proc->body == NULL) {
-		ssa_fprintf(f, "\ndeclare ");
+		ssa_fprintf(f, "declare ");
 	} else {
 	} else {
 		ssa_fprintf(f, "\ndefine ");
 		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) {
 	gb_for_array(member_index, m->members.entries) {
 		auto *entry = &m->members.entries[member_index];
 		auto *entry = &m->members.entries[member_index];
 		ssaValue *v = entry->value;
 		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) {
 	gb_for_array(member_index, m->members.entries) {
 		auto *entry = &m->members.entries[member_index];
 		auto *entry = &m->members.entries[member_index];
 		ssaValue *v = entry->value;
 		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 ");
-			}
+		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;
+		if (v->kind != ssaValue_Proc) {
+			continue;
+		}
+		if (v->Proc.body != NULL) {
+			ssa_print_proc(f, m, &v->Proc);
+		}
+	}
 
 
-			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");
+
+	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, "\n");
-		} break;
+			ssa_fprintf(f, "constant ");
+		} else {
+			ssa_fprintf(f, "global ");
+		}
 
 
-		case ssaValue_Proc: {
-			ssa_print_proc(f, m, &v->Proc);
-		} break;
+
+		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");
 	}
 	}
 }
 }

+ 18 - 6
src/codegen/ssa.cpp

@@ -927,6 +927,11 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) {
 			ssaValue *v = ssa_emit_load(proc, lval.addr);
 			ssaValue *v = ssa_emit_load(proc, lval.addr);
 			return ssa_emit(proc, ssa_make_instr_extract_element(proc, v, lval.index));
 			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);
 		return ssa_emit_load(proc, lval.addr);
 	}
 	}
 	GB_PANIC("Illegal lvalue load");
 	GB_PANIC("Illegal lvalue load");
@@ -2519,13 +2524,20 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 	case_ast_node(se, SelectorExpr, expr);
 	case_ast_node(se, SelectorExpr, expr);
 		ssa_emit_comment(proc, make_string("SelectorExpr"));
 		ssa_emit_comment(proc, make_string("SelectorExpr"));
 		Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
 		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_end;
 
 
 	case_ast_node(ue, UnaryExpr, expr);
 	case_ast_node(ue, UnaryExpr, expr);

+ 30 - 11
src/parser.cpp

@@ -43,11 +43,15 @@ struct AstFile {
 	TokenPos fix_prev_pos;
 	TokenPos fix_prev_pos;
 };
 };
 
 
+struct ImportedFile {
+	String path;
+	TokenPos pos; // #import
+};
 
 
 struct Parser {
 struct Parser {
 	String init_fullpath;
 	String init_fullpath;
 	gbArray(AstFile) files;
 	gbArray(AstFile) files;
-	gbArray(String) imports;
+	gbArray(ImportedFile) imports;
 	gbArray(String) libraries;
 	gbArray(String) libraries;
 	gbArray(String) system_libraries;
 	gbArray(String) system_libraries;
 	isize load_index;
 	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(TypeDecl,   "type declaration",   struct { Token token; AstNode *name, *type; }) \
 	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
 	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
 		Token token, relpath; \
 		Token token, relpath; \
-		String fullpath; \
+		String fullpath;      \
+		Token import_name;    \
 	}) \
 	}) \
 	AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
 	AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
 AST_NODE_KIND(_DeclEnd,   "", struct{}) \
 AST_NODE_KIND(_DeclEnd,   "", struct{}) \
@@ -883,10 +888,11 @@ gb_inline AstNode *make_type_decl(AstFile *f, Token token, AstNode *name, AstNod
 	return result;
 	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);
 	AstNode *result = make_node(f, AstNode_ImportDecl);
 	result->ImportDecl.token = token;
 	result->ImportDecl.token = token;
 	result->ImportDecl.relpath = relpath;
 	result->ImportDecl.relpath = relpath;
+	result->ImportDecl.import_name = import_name;
 	return result;
 	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.");
 			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]);
 			return make_bad_decl(f, token, f->cursor[0]);
 		} else if (are_strings_equal(tag, make_string("import"))) {
 		} else if (are_strings_equal(tag, make_string("import"))) {
+			// TODO(bill): better error messages
 			Token file_path = expect_token(f, Token_String);
 			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) {
 			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.");
 			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);
 			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
 // 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) {
 	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;
 			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;
 	return true;
 }
 }
 
 
@@ -2799,7 +2812,7 @@ void parse_file(Parser *p, AstFile *f) {
 				String import_file = make_string(path_str);
 				String import_file = make_string(path_str);
 
 
 				id->fullpath = import_file;
 				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);
 					// gb_free(gb_heap_allocator(), import_file.text);
 				}
 				}
 			} else if (node->kind == AstNode_ForeignSystemLibrary) {
 			} 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) {
 ParseFileError parse_files(Parser *p, char *init_filename) {
 	char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
 	char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename);
 	String init_fullpath = make_string(fullpath_str);
 	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;
 	p->init_fullpath = init_fullpath;
 
 
 	gb_for_array(i, p->imports) {
 	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 = {};
 		AstFile file = {};
 		ParseFileError err = init_ast_file(&file, import_path);
 		ParseFileError err = init_ast_file(&file, import_path);
 		if (err != ParseFile_None) {
 		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));
 			gb_printf_err("Failed to parse file: %.*s\n", LIT(import_path));
 			switch (err) {
 			switch (err) {
 			case ParseFile_WrongExtension:
 			case ParseFile_WrongExtension: