Browse Source

Begin work on modules - No codegen!!!

Ginger Bill 9 years ago
parent
commit
a60e6bedd9
9 changed files with 287 additions and 173 deletions
  1. 4 1
      code/demo.odin
  2. 1 1
      code/file.odin
  3. 3 3
      code/print.odin
  4. 6 2
      code/runtime.odin
  5. 18 19
      code/win32.odin
  6. 162 117
      src/checker/checker.cpp
  7. 17 7
      src/checker/stmt.cpp
  8. 1 1
      src/main.cpp
  9. 75 22
      src/parser.cpp

+ 4 - 1
code/demo.odin

@@ -1,4 +1,7 @@
-#load "basic.odin"
+// #load "basic.odin"
+#import "runtime.odin"
+#import "print.odin"
+
 
 
 main :: proc() {
 main :: proc() {
 	println("% % % %", "Hellope", true, 6.28, {4}int{1, 2, 3, 4})
 	println("% % % %", "Hellope", true, 6.28, {4}int{1, 2, 3, 4})

+ 1 - 1
code/file.odin

@@ -1,4 +1,4 @@
-#load "win32.odin"
+#import "win32.odin"
 
 
 File :: type struct {
 File :: type struct {
 	Handle :: type HANDLE
 	Handle :: type HANDLE

+ 3 - 3
code/print.odin

@@ -1,6 +1,6 @@
-#load "runtime.odin"
-#load "win32.odin"
-#load "file.odin"
+#import "runtime.odin"
+#import "win32.odin"
+#import "file.odin"
 
 
 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 {

+ 6 - 2
code/runtime.odin

@@ -1,5 +1,9 @@
-#load "win32.odin"
-#load "print.odin"
+#global_scope
+
+// TODO(bill): Remove #import in runtime.odin
+#import "win32.odin"
+#import "file.odin"
+#import "print.odin"
 
 
 // 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

+ 18 - 19
code/win32.odin

@@ -1,6 +1,24 @@
 #foreign_system_library "user32"
 #foreign_system_library "user32"
 #foreign_system_library "gdi32"
 #foreign_system_library "gdi32"
 
 
+HANDLE    :: type rawptr
+HWND      :: type HANDLE
+HDC       :: type HANDLE
+HINSTANCE :: type HANDLE
+HICON     :: type HANDLE
+HCURSOR   :: type HANDLE
+HMENU     :: type HANDLE
+HBRUSH    :: type HANDLE
+WPARAM    :: type uint
+LPARAM    :: type int
+LRESULT   :: type int
+ATOM      :: type i16
+BOOL      :: type i32
+POINT     :: type struct { x, y: i32 }
+WNDPROC   :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
+
+INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
+
 CS_VREDRAW    :: 1
 CS_VREDRAW    :: 1
 CS_HREDRAW    :: 2
 CS_HREDRAW    :: 2
 CW_USEDEFAULT :: 0x80000000
 CW_USEDEFAULT :: 0x80000000
@@ -23,25 +41,6 @@ PM_REMOVE :: 1
 COLOR_BACKGROUND :: 1 as HBRUSH
 COLOR_BACKGROUND :: 1 as HBRUSH
 
 
 
 
-HANDLE    :: type rawptr
-HWND      :: type HANDLE
-HDC       :: type HANDLE
-HINSTANCE :: type HANDLE
-HICON     :: type HANDLE
-HCURSOR   :: type HANDLE
-HMENU     :: type HANDLE
-HBRUSH    :: type HANDLE
-WPARAM    :: type uint
-LPARAM    :: type int
-LRESULT   :: type int
-ATOM      :: type i16
-BOOL      :: type i32
-POINT     :: type struct { x, y: i32 }
-
-INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
-
-WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
-
 WNDCLASSEXA :: struct #ordered {
 WNDCLASSEXA :: struct #ordered {
 	size, style:           u32
 	size, style:           u32
 	wnd_proc:              WNDPROC
 	wnd_proc:              WNDPROC

+ 162 - 117
src/checker/checker.cpp

@@ -107,11 +107,16 @@ struct ProcedureInfo {
 };
 };
 
 
 struct Scope {
 struct Scope {
-	b32 is_proc;
 	Scope *parent;
 	Scope *parent;
 	Scope *prev, *next;
 	Scope *prev, *next;
 	Scope *first_child, *last_child;
 	Scope *first_child, *last_child;
 	Map<Entity *> elements; // Key: String
 	Map<Entity *> elements; // Key: String
+
+	gbArray(Scope *) shared;
+	gbArray(Scope *) imported;
+	b32 is_proc;
+	b32 is_global;
+	b32 is_file;
 };
 };
 
 
 enum ExprKind {
 enum ExprKind {
@@ -253,7 +258,9 @@ CycleChecker *cycle_checker_add(CycleChecker *cc, Entity *e) {
 Scope *make_scope(Scope *parent, gbAllocator allocator) {
 Scope *make_scope(Scope *parent, gbAllocator allocator) {
 	Scope *s = gb_alloc_item(allocator, Scope);
 	Scope *s = gb_alloc_item(allocator, Scope);
 	s->parent = parent;
 	s->parent = parent;
-	map_init(&s->elements, gb_heap_allocator());
+	map_init(&s->elements,     gb_heap_allocator());
+	gb_array_init(s->shared,   gb_heap_allocator());
+	gb_array_init(s->imported, gb_heap_allocator());
 	if (parent != NULL && parent != universal_scope) {
 	if (parent != NULL && parent != universal_scope) {
 		DLIST_APPEND(parent->first_child, parent->last_child, s);
 		DLIST_APPEND(parent->first_child, parent->last_child, s);
 	}
 	}
@@ -277,6 +284,9 @@ void destroy_scope(Scope *scope) {
 	}
 	}
 
 
 	map_destroy(&scope->elements);
 	map_destroy(&scope->elements);
+	gb_array_free(scope->shared);
+	gb_array_free(scope->imported);
+
 	// NOTE(bill): No need to free scope as it "should" be allocated in an arena (except for the global scope)
 	// NOTE(bill): No need to free scope as it "should" be allocated in an arena (except for the global scope)
 }
 }
 
 
@@ -287,11 +297,14 @@ void add_scope(Checker *c, AstNode *node, Scope *scope) {
 }
 }
 
 
 
 
-void check_open_scope(Checker *c, AstNode *stmt) {
-	GB_ASSERT(is_ast_node_stmt(stmt) || is_ast_node_type(stmt));
+void check_open_scope(Checker *c, AstNode *node) {
+	GB_ASSERT(node != NULL);
+	GB_ASSERT(node->kind == AstNode_Invalid ||
+	          is_ast_node_stmt(node) ||
+	          is_ast_node_type(node));
 	Scope *scope = make_scope(c->context.scope, c->allocator);
 	Scope *scope = make_scope(c->context.scope, c->allocator);
-	add_scope(c, stmt, scope);
-	if (stmt->kind == AstNode_ProcType) {
+	add_scope(c, node, scope);
+	if (node->kind == AstNode_ProcType) {
 		scope->is_proc = true;
 		scope->is_proc = true;
 	}
 	}
 	c->context.scope = scope;
 	c->context.scope = scope;
@@ -301,31 +314,55 @@ 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 *s, String name, Scope **scope, Entity **entity) {
+void scope_lookup_parent_entity(Checker *c, 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 (; s != NULL; s = s->parent) {
-
+	for (Scope *s = scope; s != NULL; s = s->parent) {
 		Entity **found = map_get(&s->elements, key);
 		Entity **found = map_get(&s->elements, key);
 		if (found) {
 		if (found) {
 			Entity *e = *found;
 			Entity *e = *found;
 			if (gone_thru_proc) {
 			if (gone_thru_proc) {
-				if (e->kind == Entity_Variable && e->scope != c->global_scope) {
+				if (e->kind == Entity_Variable &&
+				    !e->scope->is_file &&
+				    !e->scope->is_global) {
 					continue;
 					continue;
 				}
 				}
 			}
 			}
 
 
-			if (entity) *entity = e;
-			if (scope) *scope = s;
+			if (entity_) *entity_ = e;
+			if (scope_) *scope_ = s;
 			return;
 			return;
 		}
 		}
 
 
 		if (s->is_proc) {
 		if (s->is_proc) {
 			gone_thru_proc = true;
 			gone_thru_proc = true;
+		} else {
+			// Check shared scopes - i.e. other files @ global scope
+			gb_for_array(i, s->shared) {
+				Scope *shared = s->shared[i];
+				Entity **found = map_get(&shared->elements, key);
+				if (found) {
+					Entity *e = *found;
+					if (e->kind == Entity_Variable &&
+					    !e->scope->is_file &&
+					    !e->scope->is_global) {
+						continue;
+					}
+
+					if (e->scope == shared) {
+						// Do not return imported entities
+						if (entity_) *entity_ = e;
+						if (scope_) *scope_ = shared;
+						return;
+					}
+				}
+			}
 		}
 		}
 	}
 	}
-	if (entity) *entity = NULL;
-	if (scope) *scope = NULL;
+
+
+	if (entity_) *entity_ = NULL;
+	if (scope_) *scope_ = NULL;
 }
 }
 
 
 Entity *scope_lookup_entity(Checker *c, Scope *s, String name) {
 Entity *scope_lookup_entity(Checker *c, Scope *s, String name) {
@@ -337,8 +374,15 @@ Entity *scope_lookup_entity(Checker *c, Scope *s, String name) {
 Entity *current_scope_lookup_entity(Scope *s, String name) {
 Entity *current_scope_lookup_entity(Scope *s, String name) {
 	HashKey key = hash_string(name);
 	HashKey key = hash_string(name);
 	Entity **found = map_get(&s->elements, key);
 	Entity **found = map_get(&s->elements, key);
-	if (found)
+	if (found) {
 		return *found;
 		return *found;
+	}
+	gb_for_array(i, s->shared) {
+		Entity **found = map_get(&s->shared[i]->elements, key);
+		if (found) {
+			return *found;
+		}
+	}
 	return NULL;
 	return NULL;
 }
 }
 
 
@@ -570,7 +614,6 @@ b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
 				      LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
 				      LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
 				return false;
 				return false;
 			} else {
 			} else {
-				gb_printf_err("!!Here\n");
 				error(&c->error_collector, entity->token,
 				error(&c->error_collector, entity->token,
 				      "Redeclararation of `%.*s` in this scope\n"
 				      "Redeclararation of `%.*s` in this scope\n"
 				      "\tat %.*s(%td:%td)",
 				      "\tat %.*s(%td:%td)",
@@ -580,82 +623,11 @@ b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
 			}
 			}
 		}
 		}
 	}
 	}
-	if (identifier != NULL)
+	if (identifier != NULL) {
 		add_entity_definition(&c->info, identifier, entity);
 		add_entity_definition(&c->info, identifier, entity);
-	return true;
-}
-
-
-/*
-b32 add_proc_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
-	GB_ASSERT(entity->kind == Entity_Procedure);
-
-	auto error_proc_redecl = [](Checker *c, Token token, Entity *other_entity, char *extra_msg) {
-		error(&c->error_collector, token,
-		      "Redeclararation of `%.*s` in this scope %s\n"
-		      "\tat %.*s(%td:%td)",
-		      LIT(other_entity->token.string),
-		      extra_msg,
-		      LIT(other_entity->token.pos.file), other_entity->token.pos.line, other_entity->token.pos.column);
-	};
-
-	String name = entity->token.string;
-	HashKey key = hash_string(name);
-
-	b32 insert_overload = false;
-
-	if (!are_strings_equal(name, make_string("_"))) {
-		Entity *insert_entity = scope_insert_entity(scope, entity);
-		if (insert_entity != NULL) {
-			if (insert_entity != entity) {
-				isize count = multi_map_count(&scope->elements, key);
-				GB_ASSERT(count > 0);
-				Entity **entities = gb_alloc_array(gb_heap_allocator(), Entity *, count);
-				defer (gb_free(gb_heap_allocator(), entities));
-				multi_map_get_all(&scope->elements, key, entities);
-
-				for (isize i = 0; i < count; i++) {
-					Entity *e = entities[i];
-					if (e == entity) {
-						continue;
-					}
-					if (e->kind == Entity_Procedure) {
-						Type *proc_type = entity->type;
-						Type *other_proc_type = e->type;
-						// gb_printf_err("%s == %s\n", type_to_string(proc_type), type_to_string(other_proc_type));
-						if (are_types_identical(proc_type, other_proc_type)) {
-							error_proc_redecl(c, entity->token, e, "with identical types");
-							return false;
-						}
-
-						if (proc_type != NULL && other_proc_type != NULL) {
-							Type *params = proc_type->Proc.params;
-							Type *other_params = other_proc_type->Proc.params;
-
-							if (are_types_identical(params, other_params)) {
-								error_proc_redecl(c, entity->token, e, "with 2identical parameters");
-								return false;
-							}
-						}
-					} else {
-						error_proc_redecl(c, entity->token, e, "");
-						return false;
-					}
-				}
-				insert_overload = true;
-			}
-		}
-	}
-
-	if (insert_overload) {
-		multi_map_insert(&scope->elements, key, entity);
 	}
 	}
-
-	if (identifier != NULL)
-		add_entity_definition(&c->info, identifier, entity);
 	return true;
 	return true;
 }
 }
-*/
 
 
 void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
 void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
 	GB_ASSERT(identifier != NULL);
 	GB_ASSERT(identifier != NULL);
@@ -665,10 +637,9 @@ void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
 }
 }
 
 
 
 
-void add_file_entity(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) {
+void add_file_entity(Checker *c, Scope *file_scope, AstNode *identifier, Entity *e, DeclInfo *d) {
 	GB_ASSERT(are_strings_equal(identifier->Ident.string, e->token.string));
 	GB_ASSERT(are_strings_equal(identifier->Ident.string, e->token.string));
-
-	add_entity(c, c->global_scope, identifier, e);
+	add_entity(c, file_scope, identifier, e);
 	map_set(&c->info.entities, hash_pointer(e), d);
 	map_set(&c->info.entities, hash_pointer(e), d);
 }
 }
 
 
@@ -763,12 +734,9 @@ void add_type_info_type(Checker *c, Type *t) {
 		add_type_info_type(c, bt->Proc.results);
 		add_type_info_type(c, bt->Proc.results);
 		break;
 		break;
 	}
 	}
-
 }
 }
 
 
 
 
-
-
 void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body) {
 void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body) {
 	ProcedureInfo info = {};
 	ProcedureInfo info = {};
 	info.file = file;
 	info.file = file;
@@ -835,18 +803,56 @@ void check_type_name_cycles(Checker *c, CycleCheck *cc, Entity *e) {
 
 
 
 
 void check_parsed_files(Checker *c) {
 void check_parsed_files(Checker *c) {
+
+	gbArray(AstNode *) import_decls;
+	gb_array_init(import_decls, gb_heap_allocator());
+	defer (gb_array_free(import_decls));
+
+	Map<Scope *> file_scopes; // Key: String (fullpath)
+	map_init(&file_scopes, gb_heap_allocator());
+	defer (map_destroy(&file_scopes));
+
+	// Map full filepaths to Scopes
+	gb_for_array(i, c->parser->files) {
+		AstFile *f = &c->parser->files[i];
+		Scope *scope = NULL;
+		scope = make_scope(c->global_scope, c->allocator);
+		scope->is_global = f->is_global_scope;
+		scope->is_file   = true;
+
+		if (scope->is_global) {
+			gb_array_append(c->global_scope->shared, scope);
+		}
+
+		f->scope = scope;
+		map_set(&file_scopes, hash_string(f->tokenizer.fullpath), scope);
+	}
+
 	// Collect Entities
 	// Collect Entities
 	gb_for_array(i, c->parser->files) {
 	gb_for_array(i, c->parser->files) {
 		AstFile *f = &c->parser->files[i];
 		AstFile *f = &c->parser->files[i];
 		add_curr_ast_file(c, f);
 		add_curr_ast_file(c, f);
+
+		Scope *file_scope = f->scope;
+
 		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];
-			if (!is_ast_node_decl(decl))
+			if (!is_ast_node_decl(decl)) {
 				continue;
 				continue;
+			}
 
 
 			switch (decl->kind) {
 			switch (decl->kind) {
 			case_ast_node(bd, BadDecl, decl);
 			case_ast_node(bd, BadDecl, decl);
 			case_end;
 			case_end;
+			case_ast_node(ld, LoadDecl, decl);
+				// NOTE(bill): ignore
+			case_end;
+			case_ast_node(id, ImportDecl, decl);
+				// NOTE(bill): Handle later
+			case_end;
+			case_ast_node(fsl, ForeignSystemLibrary, decl);
+				// NOTE(bill): ignore
+			case_end;
 
 
 			case_ast_node(vd, VarDecl, decl);
 			case_ast_node(vd, VarDecl, decl);
 				switch (vd->kind) {
 				switch (vd->kind) {
@@ -855,11 +861,11 @@ void check_parsed_files(Checker *c) {
 						AstNode *name = vd->names[i];
 						AstNode *name = vd->names[i];
 						AstNode *value = vd->values[i];
 						AstNode *value = vd->values[i];
 						ExactValue v = {ExactValue_Invalid};
 						ExactValue v = {ExactValue_Invalid};
-						Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
-						DeclInfo *di = make_declaration_info(c->allocator, c->global_scope);
+						Entity *e = make_entity_constant(c->allocator, file_scope, name->Ident, NULL, v);
+						DeclInfo *di = make_declaration_info(c->allocator, file_scope);
 						di->type_expr = vd->type;
 						di->type_expr = vd->type;
 						di->init_expr = value;
 						di->init_expr = value;
-						add_file_entity(c, name, e, di);
+						add_file_entity(c, file_scope, name, e, di);
 					}
 					}
 
 
 					isize lhs_count = gb_array_count(vd->names);
 					isize lhs_count = gb_array_count(vd->names);
@@ -878,7 +884,7 @@ void check_parsed_files(Checker *c) {
 					Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
 					Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
 					DeclInfo *di = NULL;
 					DeclInfo *di = NULL;
 					if (gb_array_count(vd->values) > 0) {
 					if (gb_array_count(vd->values) > 0) {
-						di = make_declaration_info(gb_heap_allocator(), c->global_scope);
+						di = make_declaration_info(gb_heap_allocator(), file_scope);
 						di->entities = entities;
 						di->entities = entities;
 						di->entity_count = entity_count;
 						di->entity_count = entity_count;
 						di->type_expr = vd->type;
 						di->type_expr = vd->type;
@@ -891,19 +897,19 @@ void check_parsed_files(Checker *c) {
 						if (i < gb_array_count(vd->values)) {
 						if (i < gb_array_count(vd->values)) {
 							value = vd->values[i];
 							value = vd->values[i];
 						}
 						}
-						Entity *e = make_entity_variable(c->allocator, c->global_scope, name->Ident, NULL);
+						Entity *e = make_entity_variable(c->allocator, file_scope, name->Ident, NULL);
 						entities[entity_index++] = e;
 						entities[entity_index++] = e;
 
 
 						DeclInfo *d = di;
 						DeclInfo *d = di;
 						if (d == NULL) {
 						if (d == NULL) {
 							AstNode *init_expr = value;
 							AstNode *init_expr = value;
-							d = make_declaration_info(gb_heap_allocator(), c->global_scope);
+							d = make_declaration_info(gb_heap_allocator(), file_scope);
 							d->type_expr = vd->type;
 							d->type_expr = vd->type;
 							d->init_expr = init_expr;
 							d->init_expr = init_expr;
 							d->var_decl_tags = vd->tags;
 							d->var_decl_tags = vd->tags;
 						}
 						}
 
 
-						add_file_entity(c, name, e, d);
+						add_file_entity(c, file_scope, name, e, d);
 					}
 					}
 				} break;
 				} break;
 				}
 				}
@@ -911,29 +917,21 @@ void check_parsed_files(Checker *c) {
 
 
 			case_ast_node(td, TypeDecl, decl);
 			case_ast_node(td, TypeDecl, decl);
 				ast_node(n, Ident, td->name);
 				ast_node(n, Ident, td->name);
-				Entity *e = make_entity_type_name(c->allocator, c->global_scope, *n, NULL);
+				Entity *e = make_entity_type_name(c->allocator, file_scope, *n, NULL);
 				DeclInfo *d = make_declaration_info(c->allocator, e->scope);
 				DeclInfo *d = make_declaration_info(c->allocator, e->scope);
 				d->type_expr = td->type;
 				d->type_expr = td->type;
-				add_file_entity(c, td->name, e, d);
+				add_file_entity(c, file_scope, td->name, e, d);
 			case_end;
 			case_end;
 
 
 			case_ast_node(pd, ProcDecl, decl);
 			case_ast_node(pd, ProcDecl, decl);
 				ast_node(n, Ident, pd->name);
 				ast_node(n, Ident, pd->name);
 				Token token = *n;
 				Token token = *n;
-				Entity *e = make_entity_procedure(c->allocator, c->global_scope, token, NULL);
+				Entity *e = make_entity_procedure(c->allocator, file_scope, token, NULL);
 				DeclInfo *d = make_declaration_info(c->allocator, e->scope);
 				DeclInfo *d = make_declaration_info(c->allocator, e->scope);
 				d->proc_decl = decl;
 				d->proc_decl = decl;
-				map_set(&c->info.entities, hash_pointer(e), d);
-			case_end;
-
-			case_ast_node(ld, LoadDecl, decl);
-				// NOTE(bill): ignore
-			case_end;
-			case_ast_node(fsl, ForeignSystemLibrary, decl);
-				// NOTE(bill): ignore
+				add_file_entity(c, file_scope, pd->name, e, d);
 			case_end;
 			case_end;
 
 
-
 			default:
 			default:
 				error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");
 				error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");
 				break;
 				break;
@@ -941,6 +939,47 @@ void check_parsed_files(Checker *c) {
 		}
 		}
 	}
 	}
 
 
+	gb_for_array(i, c->parser->files) {
+		AstFile *f = &c->parser->files[i];
+		add_curr_ast_file(c, f);
+
+		Scope *file_scope = f->scope;
+
+		gb_for_array(decl_index, f->decls) {
+			AstNode *decl = f->decls[decl_index];
+			if (decl->kind != AstNode_ImportDecl) {
+				continue;
+			}
+	#if 1
+			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);
+			}
+
+			// 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) {
+					add_entity(c, file_scope, NULL, e);
+				}
+			}
+	#endif
+		}
+	}
 
 
 	auto check_global_entity = [](Checker *c, EntityKind kind) {
 	auto check_global_entity = [](Checker *c, EntityKind kind) {
 		gb_for_array(i, c->info.entities.entries) {
 		gb_for_array(i, c->info.entities.entries) {
@@ -948,6 +987,11 @@ void check_parsed_files(Checker *c) {
 			Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
 			Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
 			if (e->kind == kind) {
 			if (e->kind == kind) {
 				DeclInfo *d = entry->value;
 				DeclInfo *d = entry->value;
+
+				Scope *prev_scope = c->context.scope;
+				c->context.scope = d->scope;
+				defer (c->context.scope = prev_scope);
+
 				check_entity_decl(c, e, d, NULL);
 				check_entity_decl(c, e, d, NULL);
 			}
 			}
 		}
 		}
@@ -955,11 +999,11 @@ void check_parsed_files(Checker *c) {
 
 
 	check_global_entity(c, Entity_TypeName);
 	check_global_entity(c, Entity_TypeName);
 
 
+#if 1
 	if (t_type_info == NULL) {
 	if (t_type_info == NULL) {
 		String type_info_str = make_string("Type_Info");
 		String type_info_str = make_string("Type_Info");
-		Entity **found = map_get(&c->global_scope->elements, hash_string(type_info_str));
-		GB_ASSERT_MSG(found != NULL, "Internal Compiler Error: Could not find type declaration for `Type_Info`");
-		Entity *e = *found;
+		Entity *e = current_scope_lookup_entity(c->global_scope, type_info_str);
+		GB_ASSERT_MSG(e != NULL, "Internal Compiler Error: Could not find type declaration for `Type_Info`");
 		t_type_info = e->type;
 		t_type_info = e->type;
 		t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
 		t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
 
 
@@ -1011,6 +1055,7 @@ void check_parsed_files(Checker *c) {
 			add_type_and_value(&c->info, expr, info->mode, info->type, info->value);
 			add_type_and_value(&c->info, expr, info->mode, info->type, info->value);
 		}
 		}
 	}
 	}
+#endif
 }
 }
 
 
 
 

+ 17 - 7
src/checker/stmt.cpp

@@ -351,8 +351,9 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
 	}
 	}
 
 
 	Operand operand = {};
 	Operand operand = {};
-	if (init_expr)
+	if (init_expr) {
 		check_expr(c, &operand, init_expr);
 		check_expr(c, &operand, init_expr);
+	}
 	check_init_constant(c, e, &operand);
 	check_init_constant(c, e, &operand);
 }
 }
 
 
@@ -378,7 +379,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle
 
 
 	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("%s\n", type_to_string(named));
+		// gb_printf("check_type_decl: %s\n", type_to_string(named));
 	}
 	}
 }
 }
 
 
@@ -444,7 +445,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
 	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);
 	// add_proc_entity(c, d->scope, pd->name, e);
-	add_entity(c, d->scope, pd->name, e);
+	if (d->scope->is_proc) {
+		// Nested procedures
+		add_entity(c, d->scope, pd->name, e);
+	}
 
 
 
 
 
 
@@ -561,14 +565,20 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
 	if (e->type != NULL)
 	if (e->type != NULL)
 		return;
 		return;
 	switch (e->kind) {
 	switch (e->kind) {
-	case Entity_Constant:
+	case Entity_Constant: {
+		Scope *prev = c->context.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);
-		break;
-	case Entity_Variable:
+	} break;
+	case Entity_Variable: {
+		Scope *prev = c->context.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);
-		break;
+	} break;
 	case Entity_TypeName: {
 	case Entity_TypeName: {
 		CycleChecker local_cycle_checker = {};
 		CycleChecker local_cycle_checker = {};
 		if (cycle_checker == NULL) {
 		if (cycle_checker == NULL) {

+ 1 - 1
src/main.cpp

@@ -103,7 +103,7 @@ int main(int argc, char **argv) {
 
 
 	PRINT_TIMER("Semantic Checker");
 	PRINT_TIMER("Semantic Checker");
 #endif
 #endif
-#if 1
+#if 0
 	ssaGen ssa = {};
 	ssaGen ssa = {};
 	if (!ssa_gen_init(&ssa, &checker))
 	if (!ssa_gen_init(&ssa, &checker))
 		return 1;
 		return 1;

+ 75 - 22
src/parser.cpp

@@ -1,4 +1,5 @@
 struct AstNode;
 struct AstNode;
+struct Scope;
 
 
 enum ParseFileError {
 enum ParseFileError {
 	ParseFile_None,
 	ParseFile_None,
@@ -27,9 +28,11 @@ struct AstFile {
 	isize expr_level;
 	isize expr_level;
 
 
 	AstNodeArray decls;
 	AstNodeArray decls;
+	b32 is_global_scope;
 
 
 	AstNode *curr_proc;
 	AstNode *curr_proc;
-	isize scope_level;
+	isize    scope_level;
+	Scope *  scope; // NOTE(bill): Created in checker
 
 
 	ErrorCollector error_collector;
 	ErrorCollector error_collector;
 
 
@@ -44,7 +47,7 @@ struct AstFile {
 struct Parser {
 struct Parser {
 	String init_fullpath;
 	String init_fullpath;
 	gbArray(AstFile) files;
 	gbArray(AstFile) files;
-	gbArray(String) loads;
+	gbArray(String) imports;
 	gbArray(String) libraries;
 	gbArray(String) libraries;
 	gbArray(String) system_libraries;
 	gbArray(String) system_libraries;
 	isize load_index;
 	isize load_index;
@@ -226,8 +229,12 @@ AST_NODE_KIND(_DeclBegin,      "", struct{}) \
 			u64     tags;         \
 			u64     tags;         \
 			String  foreign_name; \
 			String  foreign_name; \
 		}) \
 		}) \
-	AST_NODE_KIND(TypeDecl, "type declaration", struct { Token token; AstNode *name, *type; }) \
-	AST_NODE_KIND(LoadDecl, "load declaration", struct { Token token, filepath; }) \
+	AST_NODE_KIND(TypeDecl,   "type declaration",   struct { Token token; AstNode *name, *type; }) \
+	AST_NODE_KIND(LoadDecl,   "load declaration",   struct { Token token, filepath; }) \
+	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
+		Token token, relpath; \
+		String fullpath; \
+	}) \
 	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{}) \
 AST_NODE_KIND(_TypeBegin, "", struct{}) \
 AST_NODE_KIND(_TypeBegin, "", struct{}) \
@@ -405,6 +412,8 @@ Token ast_node_token(AstNode *node) {
 		return node->TypeDecl.token;
 		return node->TypeDecl.token;
 	case AstNode_LoadDecl:
 	case AstNode_LoadDecl:
 		return node->LoadDecl.token;
 		return node->LoadDecl.token;
+	case AstNode_ImportDecl:
+		return node->ImportDecl.token;
 	case AstNode_ForeignSystemLibrary:
 	case AstNode_ForeignSystemLibrary:
 		return node->ForeignSystemLibrary.token;
 		return node->ForeignSystemLibrary.token;
 	case AstNode_Field: {
 	case AstNode_Field: {
@@ -884,6 +893,14 @@ gb_inline AstNode *make_load_decl(AstFile *f, Token token, Token filepath) {
 	return result;
 	return result;
 }
 }
 
 
+
+gb_inline AstNode *make_import_decl(AstFile *f, Token token, Token relpath) {
+	AstNode *result = make_node(f, AstNode_ImportDecl);
+	result->ImportDecl.token = token;
+	result->ImportDecl.relpath = relpath;
+	return result;
+}
+
 gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) {
 gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) {
 	AstNode *result = make_node(f, AstNode_ForeignSystemLibrary);
 	AstNode *result = make_node(f, AstNode_ForeignSystemLibrary);
 	result->ForeignSystemLibrary.token = token;
 	result->ForeignSystemLibrary.token = token;
@@ -2527,14 +2544,27 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_Hash: {
 	case Token_Hash: {
 		s = parse_tag_stmt(f, NULL);
 		s = parse_tag_stmt(f, NULL);
 		String tag = s->TagStmt.name.string;
 		String tag = s->TagStmt.name.string;
-
-		if (are_strings_equal(tag, make_string("load"))) {
+		if (are_strings_equal(tag, make_string("global_scope"))) {
+			if (f->curr_proc == NULL) {
+				f->is_global_scope = true;
+				return make_empty_stmt(f, f->cursor[0]);
+			}
+			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("load"))) {
 			Token file_path = expect_token(f, Token_String);
 			Token file_path = expect_token(f, Token_String);
 			if (f->curr_proc == NULL) {
 			if (f->curr_proc == NULL) {
 				return make_load_decl(f, s->TagStmt.token, file_path);
 				return make_load_decl(f, s->TagStmt.token, file_path);
 			}
 			}
 			ast_file_err(f, token, "You cannot use #load within a procedure. This must be done at the file scope.");
 			ast_file_err(f, token, "You cannot use #load 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);
+		} else if (are_strings_equal(tag, make_string("import"))) {
+			Token file_path = expect_token(f, Token_String);
+			if (f->curr_proc == NULL) {
+				return make_import_decl(f, s->TagStmt.token, file_path);
+			}
+			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);
 		} else if (are_strings_equal(tag, make_string("foreign_system_library"))) {
 		} else if (are_strings_equal(tag, make_string("foreign_system_library"))) {
 			Token file_path = expect_token(f, Token_String);
 			Token file_path = expect_token(f, Token_String);
 			if (f->curr_proc == NULL) {
 			if (f->curr_proc == NULL) {
@@ -2660,7 +2690,7 @@ void destroy_ast_file(AstFile *f) {
 
 
 b32 init_parser(Parser *p) {
 b32 init_parser(Parser *p) {
 	gb_array_init(p->files, gb_heap_allocator());
 	gb_array_init(p->files, gb_heap_allocator());
-	gb_array_init(p->loads, gb_heap_allocator());
+	gb_array_init(p->imports, gb_heap_allocator());
 	gb_array_init(p->libraries, gb_heap_allocator());
 	gb_array_init(p->libraries, gb_heap_allocator());
 	gb_array_init(p->system_libraries, gb_heap_allocator());
 	gb_array_init(p->system_libraries, gb_heap_allocator());
 	return true;
 	return true;
@@ -2672,26 +2702,26 @@ void destroy_parser(Parser *p) {
 		destroy_ast_file(&p->files[i]);
 		destroy_ast_file(&p->files[i]);
 	}
 	}
 #if 1
 #if 1
-	gb_for_array(i, p->loads) {
-		// gb_free(gb_heap_allocator(), p->loads[i].text);
+	gb_for_array(i, p->imports) {
+		// gb_free(gb_heap_allocator(), p->imports[i].text);
 	}
 	}
 #endif
 #endif
 	gb_array_free(p->files);
 	gb_array_free(p->files);
-	gb_array_free(p->loads);
+	gb_array_free(p->imports);
 	gb_array_free(p->libraries);
 	gb_array_free(p->libraries);
 	gb_array_free(p->system_libraries);
 	gb_array_free(p->system_libraries);
 }
 }
 
 
 // NOTE(bill): Returns true if it's added
 // NOTE(bill): Returns true if it's added
-b32 try_add_load_path(Parser *p, String import_file) {
-	gb_for_array(i, p->loads) {
-		String import = p->loads[i];
+b32 try_add_import_path(Parser *p, String import_file, AstNode *node) {
+	gb_for_array(i, p->imports) {
+		String import = p->imports[i];
 		if (are_strings_equal(import, import_file)) {
 		if (are_strings_equal(import, import_file)) {
 			return false;
 			return false;
 		}
 		}
 	}
 	}
 
 
-	gb_array_append(p->loads, import_file);
+	gb_array_append(p->imports, import_file);
 	return true;
 	return true;
 }
 }
 
 
@@ -2716,7 +2746,7 @@ gb_global Rune illegal_import_runes[] = {
 	'|', ',',  '<', '>', '?',
 	'|', ',',  '<', '>', '?',
 };
 };
 
 
-b32 is_load_path_valid(String path) {
+b32 is_import_path_valid(String path) {
 	if (path.len > 0) {
 	if (path.len > 0) {
 		u8 *start = path.text;
 		u8 *start = path.text;
 		u8 *end = path.text + path.len;
 		u8 *end = path.text + path.len;
@@ -2770,12 +2800,11 @@ void parse_file(Parser *p, AstFile *f) {
 				auto *id = &node->LoadDecl;
 				auto *id = &node->LoadDecl;
 				String file_str = id->filepath.string;
 				String file_str = id->filepath.string;
 
 
-				if (!is_load_path_valid(file_str)) {
+				if (!is_import_path_valid(file_str)) {
 					ast_file_err(f, ast_node_token(node), "Invalid `load` path");
 					ast_file_err(f, ast_node_token(node), "Invalid `load` path");
 					continue;
 					continue;
 				}
 				}
 
 
-
 				isize str_len = base_dir.len+file_str.len;
 				isize str_len = base_dir.len+file_str.len;
 				u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
 				u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
 				defer (gb_free(gb_heap_allocator(), str));
 				defer (gb_free(gb_heap_allocator(), str));
@@ -2786,14 +2815,38 @@ void parse_file(Parser *p, AstFile *f) {
 				char *path_str = gb_path_get_full_name(gb_heap_allocator(), cast(char *)str);
 				char *path_str = gb_path_get_full_name(gb_heap_allocator(), cast(char *)str);
 				String import_file = make_string(path_str);
 				String import_file = make_string(path_str);
 
 
-				if (!try_add_load_path(p, import_file)) {
+				if (!try_add_import_path(p, import_file, node)) {
 					gb_free(gb_heap_allocator(), import_file.text);
 					gb_free(gb_heap_allocator(), import_file.text);
 				}
 				}
+			} else if (node->kind == AstNode_ImportDecl) {
+				auto *id = &node->ImportDecl;
+				String file_str = id->relpath.string;
+
+				if (!is_import_path_valid(file_str)) {
+					ast_file_err(f, ast_node_token(node), "Invalid `load` path");
+					continue;
+				}
+
+				isize str_len = base_dir.len+file_str.len;
+				u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
+				defer (gb_free(gb_heap_allocator(), str));
+
+				gb_memcopy(str, base_dir.text, base_dir.len);
+				gb_memcopy(str+base_dir.len, file_str.text, file_str.len);
+				str[str_len] = '\0';
+				// HACK(bill): memory leak
+				char *path_str = gb_path_get_full_name(gb_heap_allocator(), cast(char *)str);
+				String import_file = make_string(path_str);
+
+				id->fullpath = import_file;
+				if (!try_add_import_path(p, import_file, node)) {
+					// gb_free(gb_heap_allocator(), import_file.text);
+				}
 			} else if (node->kind == AstNode_ForeignSystemLibrary) {
 			} else if (node->kind == AstNode_ForeignSystemLibrary) {
 				auto *id = &node->ForeignSystemLibrary;
 				auto *id = &node->ForeignSystemLibrary;
 				String file_str = id->filepath.string;
 				String file_str = id->filepath.string;
 
 
-				if (!is_load_path_valid(file_str)) {
+				if (!is_import_path_valid(file_str)) {
 					ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path");
 					ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path");
 					continue;
 					continue;
 				}
 				}
@@ -2808,11 +2861,11 @@ 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->loads, init_fullpath);
+	gb_array_append(p->imports, init_fullpath);
 	p->init_fullpath = init_fullpath;
 	p->init_fullpath = init_fullpath;
 
 
-	gb_for_array(i, p->loads) {
-		String import_path = p->loads[i];
+	gb_for_array(i, p->imports) {
+		String import_path = p->imports[i];
 		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) {