Browse Source

Call expression, either handle all or ignore all results.

Ginger Bill 9 years ago
parent
commit
968de5aae8
11 changed files with 226 additions and 86 deletions
  1. 18 6
      code/demo.odin
  2. 4 4
      code/game.odin
  3. 25 19
      code/runtime.odin
  4. 11 9
      code/win32.odin
  5. 3 1
      src/checker/checker.cpp
  6. 10 1
      src/checker/entity.cpp
  7. 28 20
      src/checker/expr.cpp
  8. 51 11
      src/checker/stmt.cpp
  9. 39 7
      src/codegen/ssa.cpp
  10. 4 4
      src/main.cpp
  11. 33 4
      src/parser.cpp

+ 18 - 6
code/demo.odin

@@ -1,16 +1,28 @@
-#import "runtime.odin" as _
-#import "punity.odin" as punity
+#import "punity.odin" as pn
+#import "fmt.odin" as fmt
 
 
+test :: proc() {
+	thing :: proc() {
+		thing :: proc() {
+			fmt.println("Hello1")
+		}
 
 
+		fmt.println("Hello")
+	}
+}
 
 
 main :: proc() {
 main :: proc() {
-	init :: proc() {
+	test()
 
 
-	}
+	init :: proc(c: ^pn.Core) {
 
 
-	step :: proc() {
+	}
 
 
+	step :: proc(c: ^pn.Core) {
+		if pn.key_down(pn.Key.ESCAPE) {
+			c.running = false
+		}
 	}
 	}
 
 
-	punity.run(init, step)
+	pn.run(init, step)
 }
 }

+ 4 - 4
code/game.odin

@@ -10,7 +10,7 @@ time_now :: proc() -> f64 {
 	assert(win32_perf_count_freq != 0)
 	assert(win32_perf_count_freq != 0)
 
 
 	counter: i64
 	counter: i64
-	_ = win32.QueryPerformanceCounter(^counter)
+	win32.QueryPerformanceCounter(^counter)
 	result := counter as f64 / win32_perf_count_freq as f64
 	result := counter as f64 / win32_perf_count_freq as f64
 	return result
 	return result
 }
 }
@@ -24,7 +24,7 @@ win32_print_last_error :: proc() {
 // Yuk!
 // Yuk!
 to_c_string :: proc(s: string) -> []u8 {
 to_c_string :: proc(s: string) -> []u8 {
 	c_str := new_slice(u8, s.count+1)
 	c_str := new_slice(u8, s.count+1)
-	_ = copy(c_str, s as []byte)
+	copy(c_str, s as []byte)
 	c_str[s.count] = 0
 	c_str[s.count] = 0
 	return c_str
 	return c_str
 }
 }
@@ -157,8 +157,8 @@ run :: proc() {
 			if msg.message == WM_QUIT {
 			if msg.message == WM_QUIT {
 				running = false
 				running = false
 			}
 			}
-			_ = TranslateMessage(^msg)
-			_ = DispatchMessageA(^msg)
+			TranslateMessage(^msg)
+			DispatchMessageA(^msg)
 		}
 		}
 
 
 		if is_key_down(Key_Code.ESCAPE) {
 		if is_key_down(Key_Code.ESCAPE) {

+ 25 - 19
code/runtime.odin

@@ -1,10 +1,5 @@
 #shared_global_scope
 #shared_global_scope
 
 
-// TODO(bill): Create a standard library "location" so I don't have to manually import "runtime.odin"
-#import "win32.odin" as win32
-#import "os.odin"    as os
-#import "fmt.odin"   as fmt
-
 // 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
 Type_Info :: union {
 Type_Info :: union {
@@ -80,20 +75,22 @@ byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
 byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
 byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
 byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
 byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
 
 
-fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
-fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
+fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
+fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
-heap_alloc   :: proc(len: int) -> rawptr {
-	return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, len)
+heap_alloc :: proc(len: int) -> rawptr {
+	c_malloc :: proc(len: int) -> rawptr #foreign "malloc"
+	return c_malloc(len)
 }
 }
 
 
 heap_free :: proc(ptr: rawptr) {
 heap_free :: proc(ptr: rawptr) {
-	_ = win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
+	c_free :: proc(ptr: rawptr) #foreign "free"
+	c_free(ptr)
 }
 }
 
 
 current_thread_id :: proc() -> int {
 current_thread_id :: proc() -> int {
-	id := win32.GetCurrentThreadId()
-	return id as int
+	GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
+	return GetCurrentThreadId() as int
 }
 }
 
 
 memory_zero :: proc(data: rawptr, len: int) {
 memory_zero :: proc(data: rawptr, len: int) {
@@ -168,10 +165,16 @@ __string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
 __string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
 __string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
 __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
 __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
 
 
+__print_err_str :: proc(s: string) {
+
+}
+__print_err_int :: proc(i: int) {
 
 
+}
 
 
 __assert :: proc(msg: string) {
 __assert :: proc(msg: string) {
-	_ = os.write(os.get_standard_file(os.File_Standard.ERROR), msg as []byte)
+	// TODO(bill): Write message
+	__print_err_str(msg)
 	__debug_trap()
 	__debug_trap()
 }
 }
 
 
@@ -180,9 +183,10 @@ __bounds_check_error :: proc(file: string, line, column: int,
 	if 0 <= index && index < count {
 	if 0 <= index && index < count {
 		return
 		return
 	}
 	}
+	// TODO(bill): Write message
 	// TODO(bill): Probably reduce the need for `print` in the runtime if possible
 	// TODO(bill): Probably reduce the need for `print` in the runtime if possible
-	fmt.println_err("%(%:%) Index % is out of bounds range [0, %)",
-	                file, line, column, index, count)
+	// fmt.println_err("%(%:%) Index % is out of bounds range [0, %)",
+	//                 file, line, column, index, count)
 	__debug_trap()
 	__debug_trap()
 }
 }
 
 
@@ -191,8 +195,9 @@ __slice_expr_error :: proc(file: string, line, column: int,
 	if 0 <= low && low <= high && high <= max {
 	if 0 <= low && low <= high && high <= max {
 		return
 		return
 	}
 	}
-	fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]",
-	                file, line, column, low, high, max)
+	// TODO(bill): Write message
+	// fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]",
+	//                 file, line, column, low, high, max)
 	__debug_trap()
 	__debug_trap()
 }
 }
 __substring_expr_error :: proc(file: string, line, column: int,
 __substring_expr_error :: proc(file: string, line, column: int,
@@ -200,8 +205,9 @@ __substring_expr_error :: proc(file: string, line, column: int,
 	if 0 <= low && low <= high {
 	if 0 <= low && low <= high {
 		return
 		return
 	}
 	}
-	fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]",
-	                file, line, column, low, high)
+	// TODO(bill): Write message
+	// fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]",
+	//                 file, line, column, low, high)
 	__debug_trap()
 	__debug_trap()
 }
 }
 
 

+ 11 - 9
code/win32.odin

@@ -83,14 +83,15 @@ RECT :: struct #ordered {
 }
 }
 
 
 
 
-GetLastError     :: proc() -> i32                       #foreign #dll_import
-ExitProcess      :: proc(exit_code: u32)                #foreign #dll_import
-GetDesktopWindow :: proc() -> HWND                      #foreign #dll_import
-GetCursorPos     :: proc(p: ^POINT) -> i32              #foreign #dll_import
-ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32     #foreign #dll_import
-GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
-GetStockObject   :: proc(fn_object: i32) -> HGDIOBJ     #foreign #dll_import
-PostQuitMessage  :: proc(exit_code: i32)                #foreign #dll_import
+GetLastError     :: proc() -> i32                           #foreign #dll_import
+ExitProcess      :: proc(exit_code: u32)                    #foreign #dll_import
+GetDesktopWindow :: proc() -> HWND                          #foreign #dll_import
+GetCursorPos     :: proc(p: ^POINT) -> i32                  #foreign #dll_import
+ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32         #foreign #dll_import
+GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE     #foreign #dll_import
+GetStockObject   :: proc(fn_object: i32) -> HGDIOBJ         #foreign #dll_import
+PostQuitMessage  :: proc(exit_code: i32)                    #foreign #dll_import
+SetWindowTextA   :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
 
 
 QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
 QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
 QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign #dll_import
 QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign #dll_import
@@ -122,7 +123,7 @@ AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #
 
 
 GetQueryPerformanceFrequency :: proc() -> i64 {
 GetQueryPerformanceFrequency :: proc() -> i64 {
 	r: i64
 	r: i64
-	_ = QueryPerformanceFrequency(^r)
+	QueryPerformanceFrequency(^r)
 	return r
 	return r
 }
 }
 
 
@@ -287,6 +288,7 @@ wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
 
 
 
 
 
 
+GetKeyState      :: proc(v_key: i32) -> i16 #foreign #dll_import
 GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
 GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
 
 
 is_key_down :: proc(key: Key_Code) -> bool {
 is_key_down :: proc(key: Key_Code) -> bool {

+ 3 - 1
src/checker/checker.cpp

@@ -1034,7 +1034,9 @@ void check_parsed_files(Checker *c) {
 					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 && e->kind != Entity_ImportName) {
 					if (e->scope == scope && e->kind != Entity_ImportName) {
-						add_entity(c, file_scope, NULL, e);
+						if (is_entity_exported(e)) {
+							add_entity(c, file_scope, NULL, e);
+						}
 					}
 					}
 				}
 				}
 			} else {
 			} else {

+ 10 - 1
src/checker/entity.cpp

@@ -51,7 +51,7 @@ struct Entity {
 			b8  is_field;    // Is struct field
 			b8  is_field;    // Is struct field
 		} Variable;
 		} Variable;
 		struct {
 		struct {
-			struct DeclInfo *decl; // Usually NULL
+			// struct DeclInfo *decl; // Usually NULL
 		} TypeName;
 		} TypeName;
 		struct {
 		struct {
 			b8 pure;
 			b8 pure;
@@ -66,6 +66,15 @@ struct Entity {
 	};
 	};
 };
 };
 
 
+b32 is_entity_exported(Entity *e) {
+	// TODO(bill): Do I really want non-exported entities?
+	// if (e->token.string.len >= 1 &&
+	    // e->token.string.text[0] == '_') {
+		// return false;
+	// }
+	return true;
+}
+
 gb_global gbAtomic64 entity_guid_counter = {0};
 gb_global gbAtomic64 entity_guid_counter = {0};
 
 
 EntityGuid next_entity_guid(void) {
 EntityGuid next_entity_guid(void) {

+ 28 - 20
src/checker/expr.cpp

@@ -835,27 +835,28 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
 }
 }
 
 
 i64 check_array_count(Checker *c, AstNode *e) {
 i64 check_array_count(Checker *c, AstNode *e) {
-	if (e) {
-		Operand o = {};
-		check_expr(c, &o, e);
-		if (o.mode != Addressing_Constant) {
-			if (o.mode != Addressing_Invalid) {
-				error(&c->error_collector, ast_node_token(e), "Array count must be a constant");
-			}
+	if (e == NULL) {
+		return 0;
+	}
+	Operand o = {};
+	check_expr(c, &o, e);
+	if (o.mode != Addressing_Constant) {
+		if (o.mode != Addressing_Invalid) {
+			error(&c->error_collector, ast_node_token(e), "Array count must be a constant");
+		}
+		return 0;
+	}
+	if (is_type_untyped(o.type) || is_type_integer(o.type)) {
+		if (o.value.kind == ExactValue_Integer) {
+			i64 count = o.value.value_integer;
+			if (count >= 0)
+				return count;
+			error(&c->error_collector, ast_node_token(e), "Invalid array count");
 			return 0;
 			return 0;
 		}
 		}
-		if (is_type_untyped(o.type) || is_type_integer(o.type)) {
-			if (o.value.kind == ExactValue_Integer) {
-				i64 count = o.value.value_integer;
-				if (count >= 0)
-					return count;
-				error(&c->error_collector, ast_node_token(e), "Invalid array count");
-				return 0;
-			}
-		}
-
-		error(&c->error_collector, ast_node_token(e), "Array count must be an integer");
 	}
 	}
+
+	error(&c->error_collector, ast_node_token(e), "Array count must be an integer");
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2001,17 +2002,24 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
 		if (e != NULL && e->kind == Entity_ImportName) {
 		if (e != NULL && e->kind == Entity_ImportName) {
 			check_op_expr = false;
 			check_op_expr = false;
 			entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string);
 			entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string);
-			add_entity_use(&c->info, selector, entity);
 			if (entity == NULL) {
 			if (entity == NULL) {
 				gbString sel_str = expr_to_string(selector);
 				gbString sel_str = expr_to_string(selector);
 				defer (gb_string_free(sel_str));
 				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));
+				error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared by `%.*s`", sel_str, LIT(name));
 				goto error;
 				goto error;
 			}
 			}
 			if (entity->type == NULL) { // Not setup yet
 			if (entity->type == NULL) { // Not setup yet
 				check_entity_decl(c, entity, NULL, NULL);
 				check_entity_decl(c, entity, NULL, NULL);
 			}
 			}
 			GB_ASSERT(entity->type != NULL);
 			GB_ASSERT(entity->type != NULL);
+			if (!is_entity_exported(entity)) {
+				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 exported by `%.*s`", sel_str, LIT(name));
+				// NOTE(bill): Not really an error so don't goto error
+			}
+
+			add_entity_use(&c->info, selector, entity);
 		}
 		}
 	}
 	}
 	if (check_op_expr) {
 	if (check_op_expr) {

+ 51 - 11
src/checker/stmt.cpp

@@ -8,6 +8,7 @@ enum StmtFlag : u32 {
 
 
 
 
 void check_stmt(Checker *c, AstNode *node, u32 flags);
 void check_stmt(Checker *c, AstNode *node, u32 flags);
+void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later);
 
 
 void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
 void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
 	b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
 	b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
@@ -437,6 +438,44 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
 	check_scope_usage(c, c->context.scope);
 	check_scope_usage(c, c->context.scope);
 }
 }
 
 
+b32 are_signatures_similar_enough(Type *a_, Type *b_) {
+	GB_ASSERT(a_->kind == Type_Proc);
+	GB_ASSERT(b_->kind == Type_Proc);
+	auto *a = &a_->Proc;
+	auto *b = &b_->Proc;
+
+	if (a->param_count != b->param_count) {
+		return false;
+	}
+	if (a->result_count != b->result_count) {
+		return false;
+	}
+	for (isize i = 0; i < a->param_count; i++) {
+		Type *x = get_base_type(a->params->Tuple.variables[i]->type);
+		Type *y = get_base_type(b->params->Tuple.variables[i]->type);
+		if (is_type_pointer(x) && is_type_pointer(y)) {
+			continue;
+		}
+
+		if (!are_types_identical(x, y)) {
+			return false;
+		}
+	}
+	for (isize i = 0; i < a->result_count; i++) {
+		Type *x = get_base_type(a->results->Tuple.variables[i]->type);
+		Type *y = get_base_type(b->results->Tuple.variables[i]->type);
+		if (is_type_pointer(x) && is_type_pointer(y)) {
+			continue;
+		}
+
+		if (!are_types_identical(x, y)) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
 void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 	GB_ASSERT(e->type == NULL);
 	GB_ASSERT(e->type == NULL);
 
 
@@ -446,13 +485,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 	check_open_scope(c, pd->type);
 	check_open_scope(c, pd->type);
 	defer (check_close_scope(c));
 	defer (check_close_scope(c));
 	check_procedure_type(c, proc_type, pd->type);
 	check_procedure_type(c, proc_type, pd->type);
-	// add_proc_entity(c, d->scope, pd->name, e);
-	if (d->scope->is_proc) {
-		// Nested procedures
-		add_entity(c, d->scope->parent, pd->name, e);
-	}
-
-
 
 
 
 
 	b32 is_foreign   = (pd->tags & ProcTag_foreign)   != 0;
 	b32 is_foreign   = (pd->tags & ProcTag_foreign)   != 0;
@@ -460,8 +492,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 	b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
 	b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
 
 
 
 
-
-	if (d->scope == c->global_scope &&
+	if ((d->scope->is_file || d->scope->is_global) &&
 	    are_strings_equal(e->token.string, make_string("main"))) {
 	    are_strings_equal(e->token.string, make_string("main"))) {
 		if (proc_type != NULL) {
 		if (proc_type != NULL) {
 			auto *pt = &proc_type->Proc;
 			auto *pt = &proc_type->Proc;
@@ -511,7 +542,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 			TokenPos pos = f->token.pos;
 			TokenPos pos = f->token.pos;
 			Type *this_type = get_base_type(e->type);
 			Type *this_type = get_base_type(e->type);
 			Type *other_type = get_base_type(f->type);
 			Type *other_type = get_base_type(f->type);
-			if (!are_types_identical(this_type, other_type)) {
+			if (!are_signatures_similar_enough(this_type, other_type)) {
 				error(&c->error_collector, ast_node_token(d->proc_decl),
 				error(&c->error_collector, ast_node_token(d->proc_decl),
 				      "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
 				      "Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
 				      "\tat %.*s(%td:%td)",
 				      "\tat %.*s(%td:%td)",
@@ -577,7 +608,10 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
 		}
 		}
 	}
 	}
 
 
-	c->context.decl = d;
+	// c->context.decl = d;
+	// Scope *prev = c->context.scope;
+	// c->context.scope = d->scope;
+	// defer (c->context.scope = prev);
 
 
 	if (e->kind == Entity_Procedure) {
 	if (e->kind == Entity_Procedure) {
 		check_proc_decl(c, e, d, true);
 		check_proc_decl(c, e, d, true);
@@ -759,6 +793,12 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 		default: {
 		default: {
 			gbString expr_str = expr_to_string(operand.expr);
 			gbString expr_str = expr_to_string(operand.expr);
 			defer (gb_string_free(expr_str));
 			defer (gb_string_free(expr_str));
+			if (kind == Expr_Stmt) {
+				return;
+			}
+			if (operand.expr->kind == AstNode_CallExpr) {
+				return;
+			}
 
 
 			error(&c->error_collector, ast_node_token(node), "Expression is not used: `%s`", expr_str);
 			error(&c->error_collector, ast_node_token(node), "Expression is not used: `%s`", expr_str);
 		} break;
 		} break;

+ 39 - 7
src/codegen/ssa.cpp

@@ -2535,6 +2535,23 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		}
 		}
 
 
 		Entity *e = entity_of_ident(proc->module->info, expr);
 		Entity *e = entity_of_ident(proc->module->info, expr);
+
+		if (e->kind == Entity_Constant) {
+			if (get_base_type(e->type) == t_string) {
+				// HACK TODO(bill): This is lazy but it works
+				String str = e->Constant.value.value_string;
+				ssaValue *global_array = ssa_add_global_string_array(proc->module, str);
+				ssaValue *elem = ssa_array_elem(proc, global_array);
+				ssaValue *len =  ssa_make_const_int(proc->module->allocator, str.len);
+				ssaValue *v = ssa_add_local_generated(proc, e->type);
+				ssaValue *str_elem = ssa_emit_struct_gep(proc, v, v_zero32, ssa_type(elem));
+				ssaValue *str_len = ssa_emit_struct_gep(proc, v, v_one32, t_int);
+				ssa_emit_store(proc, str_elem, elem);
+				ssa_emit_store(proc, str_len, len);
+				return ssa_make_addr(v, expr);
+			}
+		}
+
 		ssaValue *v = NULL;
 		ssaValue *v = NULL;
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
 		ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
 		if (found) {
 		if (found) {
@@ -2555,20 +2572,35 @@ 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));
 		String selector = unparen_expr(se->selector)->Ident.string;
 		String selector = unparen_expr(se->selector)->Ident.string;
+		Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
+
+
 		if (type == t_invalid) {
 		if (type == t_invalid) {
+			// Imports
 			Entity *imp = entity_of_ident(proc->module->info, se->expr);
 			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);
+			if (imp != NULL) {
+				GB_ASSERT(imp->kind == Entity_ImportName);
+			}
 			return ssa_build_addr(proc, unparen_expr(se->selector));
 			return ssa_build_addr(proc, unparen_expr(se->selector));
-		} else {
+		} /* else if (type == t_string) {
+			Selection sel = lookup_field(type, selector, false);
+			GB_ASSERT(sel.entity != NULL);
+
+			// NOTE(bill): This could a constant and the only non constant
+			// selector is the `.data`, so build the expression instead
+			ssaValue *e = ssa_build_expr(proc, se->expr);
+			ssaValue *a = ssa_build_addr(proc, se->expr).addr;
+
+			a = ssa_emit_deep_field_gep(proc, type, a, sel);
+			return ssa_make_addr(a, expr);
+		}  */else {
 			Selection sel = lookup_field(type, selector, false);
 			Selection sel = lookup_field(type, selector, false);
 			GB_ASSERT(sel.entity != NULL);
 			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 *a = ssa_build_addr(proc, se->expr).addr;
+			a = ssa_emit_deep_field_gep(proc, type, a, sel);
+			return ssa_make_addr(a, expr);
 		}
 		}
 	case_end;
 	case_end;
 
 

+ 4 - 4
src/main.cpp

@@ -128,10 +128,10 @@ int main(int argc, char **argv) {
 	exit_code = win32_exec_command_line_app(
 	exit_code = win32_exec_command_line_app(
 		// "../misc/llvm-bin/opt %s -o %.*s.bc "
 		// "../misc/llvm-bin/opt %s -o %.*s.bc "
 		"opt %s -o %.*s.bc "
 		"opt %s -o %.*s.bc "
-		// "-memcpyopt "
-		// "-mem2reg "
-		// "-die -dse "
-		// "-dce "
+		"-memcpyopt "
+		"-mem2reg "
+		"-die -dse "
+		"-dce "
 		// "-S "
 		// "-S "
 		// "-debug-pass=Arguments "
 		// "-debug-pass=Arguments "
 		"",
 		"",

+ 33 - 4
src/parser.cpp

@@ -45,6 +45,7 @@ struct AstFile {
 
 
 struct ImportedFile {
 struct ImportedFile {
 	String path;
 	String path;
+	String rel_path;
 	TokenPos pos; // #import
 	TokenPos pos; // #import
 };
 };
 
 
@@ -2736,7 +2737,7 @@ 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 path, TokenPos pos) {
+b32 try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
 	gb_for_array(i, p->imports) {
 	gb_for_array(i, p->imports) {
 		String import = p->imports[i].path;
 		String import = p->imports[i].path;
 		if (are_strings_equal(import, path)) {
 		if (are_strings_equal(import, path)) {
@@ -2746,6 +2747,7 @@ b32 try_add_import_path(Parser *p, String path, TokenPos pos) {
 
 
 	ImportedFile item;
 	ImportedFile item;
 	item.path = path;
 	item.path = path;
+	item.rel_path = rel_path;
 	item.pos = pos;
 	item.pos = pos;
 	gb_array_append(p->imports, item);
 	gb_array_append(p->imports, item);
 	return true;
 	return true;
@@ -2807,8 +2809,10 @@ void parse_file(Parser *p, AstFile *f) {
 	String filepath = f->tokenizer.fullpath;
 	String filepath = f->tokenizer.fullpath;
 	String base_dir = filepath;
 	String base_dir = filepath;
 	for (isize i = filepath.len-1; i >= 0; i--) {
 	for (isize i = filepath.len-1; i >= 0; i--) {
-		if (base_dir.text[i] == GB_PATH_SEPARATOR)
+		if (base_dir.text[i] == '\\' ||
+		    base_dir.text[i] == '/') {
 			break;
 			break;
+		}
 		base_dir.len--;
 		base_dir.len--;
 	}
 	}
 
 
@@ -2843,7 +2847,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, ast_node_token(node).pos)) {
+				if (!try_add_import_path(p, import_file, file_str, 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) {
@@ -2866,15 +2870,40 @@ 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);
 	TokenPos init_pos = {};
 	TokenPos init_pos = {};
-	ImportedFile init_imported_file = {init_fullpath, init_pos};
+	ImportedFile init_imported_file = {init_fullpath, init_fullpath, init_pos};
 	gb_array_append(p->imports, init_imported_file);
 	gb_array_append(p->imports, init_imported_file);
 	p->init_fullpath = init_fullpath;
 	p->init_fullpath = init_fullpath;
 
 
+	// {
+	// 	// IMPORTANT TODO(bill): Don't embed this, do it relative to the .exe
+	// 	char *path = gb_path_get_full_name(gb_heap_allocator(), "W:/Odin/core/__runtime.odin");
+	// 	String s = make_string(path);
+	// 	ImportedFile runtime_file = {s, s, init_pos};
+	// 	gb_array_append(p->imports, runtime_file);
+	// }
+
 	gb_for_array(i, p->imports) {
 	gb_for_array(i, p->imports) {
 		String import_path = p->imports[i].path;
 		String import_path = p->imports[i].path;
+		String import_rel_path = p->imports[i].rel_path;
 		TokenPos pos = p->imports[i].pos;
 		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_NotFound) {
+		// 	// HACK(bill): Check core directory
+		// 	char buf[300] = {};
+		// 	char core[] = "W:/Odin/core/";
+		// 	isize len = gb_size_of(core)-1;
+		// 	gb_memcopy(buf, core, len);
+		// 	gb_memcopy(buf+len, import_rel_path.text, import_rel_path.len);
+		// 	char *path = gb_path_get_full_name(gb_heap_allocator(), buf);
+		// 	gb_printf_err("%s\n", path);
+
+		// 	import_path = make_string(path);
+		// 	err = init_ast_file(&file, import_path);
+		// 	p->imports[i].path = import_path;
+		// }
+
 		if (err != ParseFile_None) {
 		if (err != ParseFile_None) {
 			if (pos.line != 0) {
 			if (pos.line != 0) {
 				gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
 				gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);