Browse Source

Add basic package support (no IR support yet)

gingerBill 7 years ago
parent
commit
c067b90403

+ 1 - 4
core/atomics/atomics_windows.odin → core/atomics/atomics_windows_amd64.odin

@@ -3,10 +3,7 @@ package atomics
 // TODO(bill): Use assembly instead here to implement atomics
 // Inline vs external file?
 
-when ODIN_OS == "windows" {
-	import win32 "core:sys/windows.odin"
-}
-#assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
+import "core:sys/win32"
 
 
 yield_thread :: proc() { win32.mm_pause(); }

+ 172 - 172
core/os/os_essence.odin

@@ -1,174 +1,174 @@
 package os
 
-foreign import api "system:api"
-
-Handle    :: distinct int;
-Errno     :: distinct int;
-
-O_RDONLY   :: 0x00001;
-O_WRONLY   :: 0x00002;
-O_RDWR     :: 0x00003;
-O_CREATE   :: 0x00040;
-O_EXCL     :: 0x00080;
-O_TRUNC    :: 0x00200;
-O_APPEND   :: 0x00400;
-
-ERROR_NONE				: Errno : -1 ;
-ERROR_UNKNOWN_OPERATION_FAILURE 	: Errno : -7 ;
-ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME	: Errno : -14;
-ERROR_PATH_NOT_FOUND			: Errno : -15;
-ERROR_FILE_EXISTS			: Errno : -19;
-ERROR_FILE_NOT_FOUND			: Errno : -20;
-ERROR_DRIVE_ERROR_FILE_DAMAGED		: Errno : -21;
-ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS	: Errno : -22;
-ERROR_ACCESS_DENIED			: Errno : -23;
-ERROR_FILE_IN_EXCLUSIVE_USE		: Errno : -24;
-ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE	: Errno : -25;
-ERROR_INCORRECT_NODE_TYPE		: Errno : -26;
-ERROR_EVENT_NOT_SET			: Errno : -27;
-ERROR_TIMEOUT_REACHED			: Errno : -29;
-ERROR_REQUEST_CLOSED_BEFORE_COMPLETE 	: Errno : -30;
-ERROR_NO_CHARACTER_AT_COORDINATE	: Errno : -31;
-ERROR_FILE_ON_READ_ONLY_VOLUME		: Errno : -32;
-ERROR_USER_CANCELED_IO			: Errno : -33;
-ERROR_DRIVE_CONTROLLER_REPORTED		: Errno : -35;
-ERROR_COULD_NOT_ISSUE_PACKET		: Errno : -36;
-
-ERROR_NOT_IMPLEMENTED			: Errno : 1;
-
-OS_Node_Type :: enum i32 {
-	File      = 0,
-	Directory = 1,
-}
-
-OS_Node_Information :: struct {
-	handle:   Handle,
-	id:       [16]byte,
-	ntype:    OS_Node_Type,
-	size:     i64,
-
-	// Our additions...
-	position: i64,
-}
-
-foreign api {
-	@(link_name="OSPrintDirect")    OSPrintDirect      	:: proc(str: ^u8, length: int) ---;
-	@(link_name="malloc")     	OSMalloc     		:: proc(bytes: int) -> rawptr ---;
-	@(link_name="free")         	OSFree         		:: proc(address: rawptr) ---;
-	@(link_name="OSOpenNode")       OSOpenNode         	:: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
-	@(link_name="OSResizeFile")     OSResizeFile       	:: proc(handle: Handle, new_size: u64) -> Errno ---;
-	@(link_name="OSCloseHandle")    OSCloseHandle      	:: proc(handle: Handle) ---;
-	@(link_name="OSWriteFileSync")  OSWriteFileSync   	:: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
-	@(link_name="OSReadFileSync")   OSReadFileSync    	:: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
-	@(link_name="realloc")          OSRealloc   		:: proc(address: rawptr, size: int) -> rawptr ---;
-	@(link_name="OSGetThreadID") 	OSGetThreadID 		:: proc(handle: Handle) -> int ---;
-	@(link_name="OSRefreshNodeInformation") OSRefreshNodeInformation :: proc(information: ^OS_Node_Information) ---;
-}
-
-stdin  := Handle(-1); // Not implemented
-stdout := Handle(0);
-stderr := Handle(0);
-
-current_thread_id :: proc() -> int {
-	return OSGetThreadID(Handle(0x1000));
-}
-
-heap_alloc :: proc(size: int) -> rawptr {
-	return OSMalloc(size);
-}
-
-heap_free :: proc(address: rawptr) {
-	OSFree(address);
-}
-
-heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
-	return OSRealloc(address, new_size);
-}
-
-open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
-	flags : u64 = 0;
-
-	if mode & O_CREATE == O_CREATE {
-		flags = flags | 0x9000; // Fail if found and create directories leading to the file if they don't exist
-	} else {
-		flags = flags | 0x2000; // Fail if not found
-	}
-
-	if mode & O_EXCL == O_EXCL {
-		flags = flags | 0x111; // Block opening the node for any reason
-	}
-
-	if mode & O_RDONLY == O_RDONLY {
-		flags = flags | 0x2; // Read access
-	}
-
-	if mode & O_WRONLY == O_WRONLY {
-		flags = flags | 0x220; // Write and resize access
-	}
-
-	if mode & O_TRUNC == O_TRUNC {
-		flags = flags | 0x200; // Resize access
-	}
-
-	information := new(OS_Node_Information);
-	error := OSOpenNode(&path[0], len(path), flags, information);
-
-	if error < ERROR_NONE {
-		free(information);
-		return 0, error;
-	}
-
-	if mode & O_TRUNC == O_TRUNC {
-		error := OSResizeFile(information.handle, 0);
-		if error < ERROR_NONE do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
-	}
-
-	if mode & O_APPEND == O_APPEND {
-		information.position = information.size;
-	} else {
-		information.position = 0;
-	}
-
-	return Handle(uintptr(information)), ERROR_NONE;
-}
-
-close :: proc(fd: Handle) {
-	information := (^OS_Node_Information)(uintptr(fd));
-	OSCloseHandle(information.handle);
-	free(information);
-}
-
-file_size :: proc(fd: Handle) -> (i64, Errno) {
-	x : OS_Node_Information;
-	OSRefreshNodeInformation(&x);
-	return x.size, ERROR_NONE;
-}
-
-write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
-	if fd == 0 {
-		OSPrintDirect(&data[0], len(data));
-		return len(data), ERROR_NONE;
-	} else if fd == 1 {
-		assert(false);
-		return 0, ERROR_NOT_IMPLEMENTED;
-	}
-
-	information := (^OS_Node_Information)(uintptr(fd));
-	count := OSWriteFileSync(information.handle, information.position, i64(len(data)), &data[0]);
-	if count < 0 do  return 0, 1;
-	information.position += count;
-	return int(count), 0;
-}
-
-read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
-	if (fd == 0 || fd == 1) {
-		assert(false);
-		return 0, ERROR_NOT_IMPLEMENTED;
-	}
-
-	information := (^OS_Node_Information)(uintptr(fd));
-	count := OSReadFileSync(information.handle, information.position, i64(len(data)), &data[0]);
-	if count < 0 do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
-	information.position += count;
-	return int(count), ERROR_NONE;
-}
+// foreign import api "system:api"
+
+// Handle    :: distinct int;
+// Errno     :: distinct int;
+
+// O_RDONLY   :: 0x00001;
+// O_WRONLY   :: 0x00002;
+// O_RDWR     :: 0x00003;
+// O_CREATE   :: 0x00040;
+// O_EXCL     :: 0x00080;
+// O_TRUNC    :: 0x00200;
+// O_APPEND   :: 0x00400;
+
+// ERROR_NONE				: Errno : -1 ;
+// ERROR_UNKNOWN_OPERATION_FAILURE 	: Errno : -7 ;
+// ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME	: Errno : -14;
+// ERROR_PATH_NOT_FOUND			: Errno : -15;
+// ERROR_FILE_EXISTS			: Errno : -19;
+// ERROR_FILE_NOT_FOUND			: Errno : -20;
+// ERROR_DRIVE_ERROR_FILE_DAMAGED		: Errno : -21;
+// ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS	: Errno : -22;
+// ERROR_ACCESS_DENIED			: Errno : -23;
+// ERROR_FILE_IN_EXCLUSIVE_USE		: Errno : -24;
+// ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE	: Errno : -25;
+// ERROR_INCORRECT_NODE_TYPE		: Errno : -26;
+// ERROR_EVENT_NOT_SET			: Errno : -27;
+// ERROR_TIMEOUT_REACHED			: Errno : -29;
+// ERROR_REQUEST_CLOSED_BEFORE_COMPLETE 	: Errno : -30;
+// ERROR_NO_CHARACTER_AT_COORDINATE	: Errno : -31;
+// ERROR_FILE_ON_READ_ONLY_VOLUME		: Errno : -32;
+// ERROR_USER_CANCELED_IO			: Errno : -33;
+// ERROR_DRIVE_CONTROLLER_REPORTED		: Errno : -35;
+// ERROR_COULD_NOT_ISSUE_PACKET		: Errno : -36;
+
+// ERROR_NOT_IMPLEMENTED			: Errno : 1;
+
+// OS_Node_Type :: enum i32 {
+// 	File      = 0,
+// 	Directory = 1,
+// }
+
+// OS_Node_Information :: struct {
+// 	handle:   Handle,
+// 	id:       [16]byte,
+// 	ntype:    OS_Node_Type,
+// 	size:     i64,
+
+// 	// Our additions...
+// 	position: i64,
+// }
+
+// foreign api {
+// 	@(link_name="OSPrintDirect")    OSPrintDirect      	:: proc(str: ^u8, length: int) ---;
+// 	@(link_name="malloc")     	OSMalloc     		:: proc(bytes: int) -> rawptr ---;
+// 	@(link_name="free")         	OSFree         		:: proc(address: rawptr) ---;
+// 	@(link_name="OSOpenNode")       OSOpenNode         	:: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
+// 	@(link_name="OSResizeFile")     OSResizeFile       	:: proc(handle: Handle, new_size: u64) -> Errno ---;
+// 	@(link_name="OSCloseHandle")    OSCloseHandle      	:: proc(handle: Handle) ---;
+// 	@(link_name="OSWriteFileSync")  OSWriteFileSync   	:: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
+// 	@(link_name="OSReadFileSync")   OSReadFileSync    	:: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
+// 	@(link_name="realloc")          OSRealloc   		:: proc(address: rawptr, size: int) -> rawptr ---;
+// 	@(link_name="OSGetThreadID") 	OSGetThreadID 		:: proc(handle: Handle) -> int ---;
+// 	@(link_name="OSRefreshNodeInformation") OSRefreshNodeInformation :: proc(information: ^OS_Node_Information) ---;
+// }
+
+// stdin  := Handle(-1); // Not implemented
+// stdout := Handle(0);
+// stderr := Handle(0);
+
+// current_thread_id :: proc() -> int {
+// 	return OSGetThreadID(Handle(0x1000));
+// }
+
+// heap_alloc :: proc(size: int) -> rawptr {
+// 	return OSMalloc(size);
+// }
+
+// heap_free :: proc(address: rawptr) {
+// 	OSFree(address);
+// }
+
+// heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
+// 	return OSRealloc(address, new_size);
+// }
+
+// open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
+// 	flags : u64 = 0;
+
+// 	if mode & O_CREATE == O_CREATE {
+// 		flags = flags | 0x9000; // Fail if found and create directories leading to the file if they don't exist
+// 	} else {
+// 		flags = flags | 0x2000; // Fail if not found
+// 	}
+
+// 	if mode & O_EXCL == O_EXCL {
+// 		flags = flags | 0x111; // Block opening the node for any reason
+// 	}
+
+// 	if mode & O_RDONLY == O_RDONLY {
+// 		flags = flags | 0x2; // Read access
+// 	}
+
+// 	if mode & O_WRONLY == O_WRONLY {
+// 		flags = flags | 0x220; // Write and resize access
+// 	}
+
+// 	if mode & O_TRUNC == O_TRUNC {
+// 		flags = flags | 0x200; // Resize access
+// 	}
+
+// 	information := new(OS_Node_Information);
+// 	error := OSOpenNode(&path[0], len(path), flags, information);
+
+// 	if error < ERROR_NONE {
+// 		free(information);
+// 		return 0, error;
+// 	}
+
+// 	if mode & O_TRUNC == O_TRUNC {
+// 		error := OSResizeFile(information.handle, 0);
+// 		if error < ERROR_NONE do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
+// 	}
+
+// 	if mode & O_APPEND == O_APPEND {
+// 		information.position = information.size;
+// 	} else {
+// 		information.position = 0;
+// 	}
+
+// 	return Handle(uintptr(information)), ERROR_NONE;
+// }
+
+// close :: proc(fd: Handle) {
+// 	information := (^OS_Node_Information)(uintptr(fd));
+// 	OSCloseHandle(information.handle);
+// 	free(information);
+// }
+
+// file_size :: proc(fd: Handle) -> (i64, Errno) {
+// 	x : OS_Node_Information;
+// 	OSRefreshNodeInformation(&x);
+// 	return x.size, ERROR_NONE;
+// }
+
+// write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+// 	if fd == 0 {
+// 		OSPrintDirect(&data[0], len(data));
+// 		return len(data), ERROR_NONE;
+// 	} else if fd == 1 {
+// 		assert(false);
+// 		return 0, ERROR_NOT_IMPLEMENTED;
+// 	}
+
+// 	information := (^OS_Node_Information)(uintptr(fd));
+// 	count := OSWriteFileSync(information.handle, information.position, i64(len(data)), &data[0]);
+// 	if count < 0 do  return 0, 1;
+// 	information.position += count;
+// 	return int(count), 0;
+// }
+
+// read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+// 	if (fd == 0 || fd == 1) {
+// 		assert(false);
+// 		return 0, ERROR_NOT_IMPLEMENTED;
+// 	}
+
+// 	information := (^OS_Node_Information)(uintptr(fd));
+// 	count := OSReadFileSync(information.handle, information.position, i64(len(data)), &data[0]);
+// 	if count < 0 do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
+// 	information.position += count;
+// 	return int(count), ERROR_NONE;
+// }

+ 1 - 1
core/os/os_windows.odin

@@ -1,7 +1,7 @@
 package os
 
 import "core:sys/win32"
-import "core:mem"
+// import "core:mem"
 
 Handle    :: distinct uintptr;
 File_Time :: distinct u64;

+ 2 - 2
core/sys/win32/wgl.odin

@@ -1,8 +1,8 @@
 package win32
 
-when ODIN_OS == "windows" {
+// when ODIN_OS == "windows" {
 	foreign import "system:opengl32.lib"
-}
+// }
 
 
 CONTEXT_MAJOR_VERSION_ARB             :: 0x2091;

+ 2 - 2
core/sys/win32/windows.odin

@@ -1,12 +1,12 @@
 package win32
 
-when ODIN_OS == "windows" {
+// when ODIN_OS == "windows" {
 	foreign import "system:kernel32.lib"
 	foreign import "system:user32.lib"
 	foreign import "system:gdi32.lib"
 	foreign import "system:winmm.lib"
 	foreign import "system:shell32.lib"
-}
+// }
 
 Handle    :: distinct rawptr;
 Hwnd      :: distinct Handle;

+ 1 - 4
core/thread/thread.odin

@@ -1,10 +1,7 @@
 package thread
 
 #assert(ODIN_OS == "windows");
-
-when ODIN_OS == "windows" {
-	import win32 "core:sys/windows.odin"
-}
+import "core:sys/win32"
 
 Thread_Proc :: #type proc(^Thread) -> int;
 

+ 1 - 1
core/unicode/utf16/utf16.odin

@@ -1,4 +1,4 @@
-package utf8
+package utf16
 
 import "core:unicode/utf8"
 

+ 112 - 3
src/build_settings.cpp

@@ -1,3 +1,38 @@
+enum TargetOsKind {
+	TargetOs_Invalid,
+
+	TargetOs_windows,
+	TargetOs_osx,
+	TargetOs_linux,
+	TargetOs_essence,
+
+	TargetOs_COUNT,
+};
+
+enum TargetArchKind {
+	TargetArch_Invalid,
+
+	TargetArch_amd64,
+	TargetArch_x64,
+
+	TargetArch_COUNT,
+};
+
+String target_os_names[TargetOs_COUNT] = {
+	str_lit(""),
+	str_lit("windows"),
+	str_lit("osx"),
+	str_lit("linux"),
+	str_lit("essence"),
+};
+
+String target_arch_names[TargetArch_COUNT] = {
+	str_lit(""),
+	str_lit("amd64"),
+	str_lit("x86"),
+};
+
+
 // This stores the information for the specify architecture of this build
 struct BuildContext {
 	// Constants
@@ -15,6 +50,9 @@ struct BuildContext {
 
 	String command;
 
+	TargetOsKind   target_os;
+	TargetArchKind target_arch;
+
 	String out_filepath;
 	String resource_filepath;
 	bool   has_resource;
@@ -37,6 +75,72 @@ struct BuildContext {
 gb_global BuildContext build_context = {0};
 
 
+TargetOsKind get_target_os_from_string(String str) {
+	for (isize i = 0; i < TargetOs_COUNT; i++) {
+		if (target_os_names[i] == str) {
+			return cast(TargetOsKind)i;
+		}
+	}
+	return TargetOs_Invalid;
+}
+
+TargetArchKind get_target_arch_from_string(String str) {
+	for (isize i = 0; i < TargetArch_COUNT; i++) {
+		if (target_os_names[i] == str) {
+			return cast(TargetArchKind)i;
+		}
+	}
+	return TargetArch_Invalid;
+}
+
+bool is_excluded_target_filename(String name) {
+	String const ext = str_lit(".odin");
+	GB_ASSERT(string_ends_with(name, ext));
+	name = substring(name, 0, name.len-ext.len);
+
+	String str1 = {};
+	String str2 = {};
+	isize n = 0;
+
+	str1 = name;
+	n = str1.len;
+	for (isize i = str1.len-1; i >= 0 && str1[i] != '_'; i--) {
+		n -= 1;
+	}
+	str1 = substring(str1, n, str1.len);
+
+	str2 = str1;
+	n = str2.len;
+	for (isize i = str2.len-1; i >= 0 && str2[i] != '_'; i--) {
+		n -= 1;
+	}
+	str2 = substring(str2, n, str2.len);
+
+	if (str1 == name) {
+		return false;
+	}
+
+
+	TargetOsKind   os1   = get_target_os_from_string(str1);
+	TargetArchKind arch1 = get_target_arch_from_string(str1);
+	TargetOsKind   os2   = get_target_os_from_string(str2);
+	TargetArchKind arch2 = get_target_arch_from_string(str2);
+
+	if (arch1 != TargetArch_Invalid && os2 != TargetOs_Invalid) {
+		return arch1 != build_context.target_arch || os2 != build_context.target_os;
+	} else if (arch1 != TargetArch_Invalid && os1 != TargetOs_Invalid) {
+		return arch2 != build_context.target_arch || os1 != build_context.target_os;
+	} else if (os1 != TargetOs_Invalid) {
+		return os1 != build_context.target_os;
+	} else if (arch1 != TargetArch_Invalid) {
+		return arch1 != build_context.target_arch;
+	}
+
+	return false;
+}
+
+
+
 struct LibraryCollections {
 	String name;
 	String path;
@@ -327,11 +431,14 @@ void init_build_context(void) {
 	bc->ODIN_ROOT    = odin_root_dir();
 
 #if defined(GB_SYSTEM_WINDOWS)
-	bc->ODIN_OS      = str_lit("windows");
+	bc->ODIN_OS   = str_lit("windows");
+	bc->target_os = TargetOs_windows;
 #elif defined(GB_SYSTEM_OSX)
-	bc->ODIN_OS      = str_lit("osx");
+	bc->ODIN_OS   = str_lit("osx");
+	bc->target_os = TargetOs_osx;
 #else
-	bc->ODIN_OS      = str_lit("linux");
+	bc->ODIN_OS   = str_lit("linux");
+	bc->target_os = TargetOs_linux;
 #endif
 
 	if (cross_compile_target.len) {
@@ -340,8 +447,10 @@ void init_build_context(void) {
 
 #if defined(GB_ARCH_64_BIT)
 	bc->ODIN_ARCH = str_lit("amd64");
+	bc->target_arch = TargetArch_amd64;
 #else
 	bc->ODIN_ARCH = str_lit("x86");
+	bc->target_arch = TargetArch_x86;
 #endif
 
 	{

+ 2 - 2
src/check_decl.cpp

@@ -535,7 +535,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	e->deprecated_message = ac.deprecated_message;
 	ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
 
-	if (d->scope->file != nullptr && e->token.string == "main") {
+	if (d->scope->package != nullptr && e->token.string == "main") {
 		if (pt->param_count != 0 ||
 		    pt->result_count != 0) {
 			gbString str = type_to_string(proc_type);
@@ -583,7 +583,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 
 		GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
 		if (!pt->is_polymorphic) {
-			check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
+			check_procedure_later(c, c->curr_ast_package, e->token, d, proc_type, pl->body, pl->tags);
 		}
 	} else if (!is_foreign) {
 		if (e->Procedure.is_export) {

+ 7 - 6
src/check_expr.cpp

@@ -109,7 +109,7 @@ void error_operand_no_value(Operand *o) {
 
 void check_scope_decls(Checker *c, Array<AstNode *> nodes, isize reserve_size) {
 	Scope *s = c->context.scope;
-	GB_ASSERT(s->file == nullptr);
+	GB_ASSERT(s->package == nullptr);
 
 	check_collect_entities(c, nodes);
 
@@ -342,17 +342,18 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
 	// NOTE(bill): Set the scope afterwards as this is not real overloading
 	entity->scope = scope->parent;
 
-	AstFile *file = nullptr;
+	AstPackage *package = nullptr;
 	{
 		Scope *s = entity->scope;
-		while (s != nullptr && s->file == nullptr) {
-			file = s->file;
+		while (s != nullptr && s->package == nullptr) {
+			package = s->package;
 			s = s->parent;
 		}
 	}
 
 	ProcedureInfo proc_info = {};
-	proc_info.file  = file;
+	// proc_info.file  = file;
+	proc_info.package = package;
 	proc_info.token = token;
 	proc_info.decl  = d;
 	proc_info.type  = final_proc_type;
@@ -5362,7 +5363,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 				return kind;
 			}
 
-			check_procedure_later(c, c->curr_ast_file, empty_token, decl, type, pl->body, pl->tags);
+			check_procedure_later(c, c->curr_ast_package, empty_token, decl, type, pl->body, pl->tags);
 		}
 		check_close_scope(c);
 

+ 4 - 1
src/check_stmt.cpp

@@ -627,7 +627,10 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
 		Token token  = {};
 		token.pos    = ast_node_token(ss->body).pos;
 		token.string = str_lit("true");
-		x.expr       = ast_ident(c->curr_ast_file, token);
+
+		x.expr = gb_alloc_item(c->allocator, AstNode);
+		x.expr->kind = AstNode_Ident;
+		x.expr->Ident.token = token;
 	}
 
 	// NOTE(bill): Check for multiple defaults

File diff suppressed because it is too large
+ 222 - 492
src/checker.cpp


+ 14 - 14
src/checker.hpp

@@ -194,7 +194,8 @@ struct DeclInfo {
 
 // ProcedureInfo stores the information needed for checking a procedure
 struct ProcedureInfo {
-	AstFile *             file;
+	// AstFile *             file;
+	AstPackage *          package;
 	Token                 token;
 	DeclInfo *            decl;
 	Type *                type; // Type_Procedure
@@ -204,6 +205,7 @@ struct ProcedureInfo {
 };
 
 
+
 struct Scope {
 	AstNode *        node;
 	Scope *          parent;
@@ -214,17 +216,18 @@ struct Scope {
 	PtrSet<Entity *> implicit;
 
 	Array<Scope *>   shared;
-	Array<AstNode *> delayed_file_decls;
 	Array<AstNode *> delayed_asserts;
+	Array<AstNode *> delayed_imports;
 	PtrSet<Scope *>  imported;
 	PtrSet<Scope *>  exported; // NOTE(bhall): Contains 'using import' too
 	bool             is_proc;
 	bool             is_global;
-	bool             is_file;
+	bool             is_package;
 	bool             is_init;
 	bool             is_struct;
 	bool             has_been_imported; // This is only applicable to file scopes
-	AstFile *        file;
+
+	AstPackage *     package;
 };
 
 
@@ -250,7 +253,7 @@ typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
 struct ImportGraphNode {
 	Scope *            scope;
 	String             path;
-	isize              file_id;
+	isize              package_id;
 	ImportGraphNodeSet pred;
 	ImportGraphNodeSet succ;
 	isize              index; // Index in array/queue
@@ -268,7 +271,7 @@ struct ForeignContext {
 typedef Array<Entity *> CheckerTypePath;
 
 struct CheckerContext {
-	Scope *    file_scope;
+	Scope *    package_scope;
 	Scope *    scope;
 	DeclInfo * decl;
 	u32        stmt_state_flags;
@@ -282,7 +285,6 @@ struct CheckerContext {
 	CheckerTypePath *type_path;
 	isize            type_level; // TODO(bill): Actually handle correctly
 
-	bool       collect_delayed_decls;
 	bool       allow_polymorphic_types;
 	bool       no_polymorphic_errors;
 	bool       in_polymorphic_specialization;
@@ -295,6 +297,7 @@ struct CheckerInfo {
 	Map<TypeAndValue>     types;           // Key: AstNode * | Expression -> Type (and value)
 	Map<ExprInfo>         untyped;         // Key: AstNode * | Expression -> ExprInfo
 	Map<AstFile *>        files;           // Key: String (full path)
+	Map<AstPackage *>     packages;        // Key: String (full path)
 	Map<Entity *>         foreigns;        // Key: String
 	Array<Entity *>       definitions;
 	Array<Entity *>       entities;
@@ -318,12 +321,12 @@ struct Checker {
 	CheckerInfo info;
 	gbMutex     mutex;
 
-	AstFile *                  curr_ast_file;
+	AstPackage *               curr_ast_package;
 	Scope *                    global_scope;
 	// NOTE(bill): Procedures to check
 	Array<ProcedureInfo>       procs;
-	Map<Scope *>               file_scopes; // Key: String (fullpath)
-	Array<ImportGraphNode *>   file_order;
+	Map<Scope *>               package_scopes; // Key: String (fullpath)
+	Array<ImportGraphNode *>   package_order;
 
 	gbAllocator                allocator;
 	gbArena                    arena;
@@ -334,9 +337,6 @@ struct Checker {
 
 	Array<Type *>              proc_stack;
 	bool                       done_preload;
-
-	PtrSet<AstFile *>          checked_files;
-
 };
 
 
@@ -382,7 +382,7 @@ void      add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, D
 void      add_type_info_type      (Checker *c, Type *t);
 
 void check_add_import_decl(Checker *c, AstNodeImportDecl *id);
-void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
+// void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
 void check_add_foreign_import_decl(Checker *c, AstNode *decl);
 
 

+ 19 - 1
src/common.cpp

@@ -748,6 +748,8 @@ enum ReadDirectoryError {
 	ReadDirectory_None,
 
 	ReadDirectory_InvalidPath,
+	ReadDirectory_NotExists,
+	ReadDirectory_Permission,
 	ReadDirectory_NotDir,
 	ReadDirectory_EOF,
 	ReadDirectory_Unknown,
@@ -760,6 +762,8 @@ enum ReadDirectoryError {
 ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
 	GB_ASSERT(fi != nullptr);
 
+	gbAllocator a = heap_allocator();
+
 	while (path.len > 0) {
 		Rune end = path[path.len-1];
 		if (end == '/') {
@@ -774,11 +778,25 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
 	if (path.len == 0) {
 		return ReadDirectory_InvalidPath;
 	}
+	{
+		char *c_str = alloc_cstring(a, path);
+		defer (gb_free(a, c_str));
+
+		gbFile f = {};
+		gbFileError file_err = gb_file_open(&f, c_str);
+		defer (gb_file_close(&f));
+
+		switch (file_err) {
+		case gbFileError_Invalid:    return ReadDirectory_InvalidPath;
+		case gbFileError_NotExists:  return ReadDirectory_NotExists;
+		// case gbFileError_Permission: return ReadDirectory_Permission;
+		}
+	}
+
 	if (!path_is_directory(path)) {
 		return ReadDirectory_NotDir;
 	}
 
-	gbAllocator a = heap_allocator();
 
 	char *new_path = gb_alloc_array(a, char, path.len+3);
 	defer (gb_free(a, new_path));

+ 16 - 0
src/entity.cpp

@@ -6,6 +6,7 @@ struct DeclInfo;
 
 #define ENTITY_KINDS \
 	ENTITY_KIND(Invalid) \
+	ENTITY_KIND(Package) \
 	ENTITY_KIND(Constant) \
 	ENTITY_KIND(Variable) \
 	ENTITY_KIND(TypeName) \
@@ -85,6 +86,12 @@ struct Entity {
 	String      deprecated_message;
 
 	union {
+		struct {
+			String fullpath;
+			String name;
+			Scope *scope;
+			// Array<Entity *> imports; // Entity_Package
+		} Package;
 		struct {
 			ExactValue value;
 		} Constant;
@@ -189,6 +196,15 @@ Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
 	return entity;
 }
 
+Entity *alloc_entity_package(Scope *scope, Type *type, String fullpath, String name) {
+	Token token = empty_token;
+	token.string = name;
+	Entity *entity = alloc_entity(Entity_Package, scope, token, type);
+	entity->Package.fullpath = fullpath;
+	entity->Package.name     = name;
+	return entity;
+}
+
 Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_immutable, EntityState state = EntityState_Unresolved) {
 	Entity *entity = alloc_entity(Entity_Variable, scope, token, type);
 	entity->Variable.is_immutable = is_immutable;

+ 17 - 12
src/main.cpp

@@ -12,9 +12,9 @@
 #include "checker.hpp"
 
 #include "parser.cpp"
-#if 0
 #include "docs.cpp"
 #include "checker.cpp"
+#if 0
 #include "ir.cpp"
 #include "ir_opt.cpp"
 #include "ir_print.cpp"
@@ -574,16 +574,22 @@ bool parse_build_flags(Array<String> args) {
 }
 
 void show_timings(Checker *c, Timings *t) {
-	Parser *p    = c->parser;
-	isize lines  = p->total_line_count;
-	isize tokens = p->total_token_count;
-	isize files  = p->files.count;
+	Parser *p      = c->parser;
+	isize lines    = p->total_line_count;
+	isize tokens   = p->total_token_count;
+	isize files    = 0;
+	isize packages = p->packages.count;
+	for_array(i, p->packages) {
+		files += p->packages[i]->files.entries.count;
+	}
+
 	{
 		timings_print_all(t);
 		gb_printf("\n");
-		gb_printf("Total Lines  - %td\n", lines);
-		gb_printf("Total Tokens - %td\n", tokens);
-		gb_printf("Total Files  - %td\n", files);
+		gb_printf("Total Lines    - %td\n", lines);
+		gb_printf("Total Tokens   - %td\n", tokens);
+		gb_printf("Total Files    - %td\n", files);
+		gb_printf("Total Packages - %td\n", packages);
 		gb_printf("\n");
 	}
 	{
@@ -774,9 +780,8 @@ int main(int arg_count, char **arg_ptr) {
 		print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
 		return 1;
 	}
-#if 0
+
 	init_universal_scope();
-#endif
 	// TODO(bill): prevent compiling without a linker
 
 	timings_start_section(&timings, str_lit("parse files"));
@@ -791,9 +796,8 @@ int main(int arg_count, char **arg_ptr) {
 		return 1;
 	}
 
-#if 0
 	if (build_context.generate_docs) {
-		generate_documentation(&parser);
+		// generate_documentation(&parser);
 		return 0;
 	}
 
@@ -807,6 +811,7 @@ int main(int arg_count, char **arg_ptr) {
 
 	check_parsed_files(&checker);
 
+#if 0
 	if (build_context.no_output_files) {
 		if (build_context.show_timings) {
 			show_timings(&checker, &timings);

+ 97 - 106
src/parser.cpp

@@ -61,7 +61,7 @@ Token ast_node_token(AstNode *node) {
 
 	case AstNode_ValueDecl:          return ast_node_token(node->ValueDecl.names[0]);
 	case AstNode_ImportDecl:         return node->ImportDecl.token;
-	case AstNode_ExportDecl:         return node->ExportDecl.token;
+	// case AstNode_ExportDecl:         return node->ExportDecl.token;
 	case AstNode_ForeignImportDecl:  return node->ForeignImportDecl.token;
 
 	case AstNode_ForeignBlockDecl:   return node->ForeignBlockDecl.token;
@@ -1002,15 +1002,15 @@ AstNode *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath,
 	return result;
 }
 
-AstNode *ast_export_decl(AstFile *f, Token token, Token relpath,
-                         CommentGroup docs, CommentGroup comment) {
-	AstNode *result = make_ast_node(f, AstNode_ExportDecl);
-	result->ExportDecl.token       = token;
-	result->ExportDecl.relpath     = relpath;
-	result->ExportDecl.docs        = docs;
-	result->ExportDecl.comment     = comment;
-	return result;
-}
+// AstNode *ast_export_decl(AstFile *f, Token token, Token relpath,
+//                          CommentGroup docs, CommentGroup comment) {
+// 	AstNode *result = make_ast_node(f, AstNode_ExportDecl);
+// 	result->ExportDecl.token       = token;
+// 	result->ExportDecl.relpath     = relpath;
+// 	result->ExportDecl.docs        = docs;
+// 	result->ExportDecl.comment     = comment;
+// 	return result;
+// }
 
 AstNode *ast_foreign_import_decl(AstFile *f, Token token, Token filepath, Token library_name,
                                  CommentGroup docs, CommentGroup comment) {
@@ -1309,7 +1309,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
 		return s->ProcLit.body != nullptr;
 
 	case AstNode_ImportDecl:
-	case AstNode_ExportDecl:
+	// case AstNode_ExportDecl:
 	case AstNode_ForeignImportDecl:
 		return true;
 
@@ -3477,21 +3477,21 @@ AstNode *parse_import_decl(AstFile *f, ImportDeclKind kind) {
 	return s;
 }
 
-AstNode *parse_export_decl(AstFile *f) {
-	CommentGroup docs = f->lead_comment;
-	Token token = expect_token(f, Token_export);
-	Token file_path = expect_token_after(f, Token_String, "export");
-	AstNode *s = nullptr;
-	if (f->curr_proc != nullptr) {
-		syntax_error(token, "You cannot use 'export' within a procedure. This must be done at the file scope");
-		s = ast_bad_decl(f, token, file_path);
-	} else {
-		s = ast_export_decl(f, token, file_path, docs, f->line_comment);
-		array_add(&f->imports_and_exports, s);
-	}
-	expect_semicolon(f, s);
-	return s;
-}
+// AstNode *parse_export_decl(AstFile *f) {
+// 	CommentGroup docs = f->lead_comment;
+// 	Token token = expect_token(f, Token_export);
+// 	Token file_path = expect_token_after(f, Token_String, "export");
+// 	AstNode *s = nullptr;
+// 	if (f->curr_proc != nullptr) {
+// 		syntax_error(token, "You cannot use 'export' within a procedure. This must be done at the file scope");
+// 		s = ast_bad_decl(f, token, file_path);
+// 	} else {
+// 		s = ast_export_decl(f, token, file_path, docs, f->line_comment);
+// 		array_add(&f->imports_and_exports, s);
+// 	}
+// 	expect_semicolon(f, s);
+// 	return s;
+// }
 
 AstNode *parse_foreign_decl(AstFile *f) {
 	CommentGroup docs = f->lead_comment;
@@ -3584,8 +3584,8 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_import:
 		return parse_import_decl(f, ImportDecl_Standard);
 
-	case Token_export:
-		return parse_export_decl(f);
+	// case Token_export:
+	// 	return parse_export_decl(f);
 
 
 	case Token_if:     return parse_if_stmt(f);
@@ -3632,13 +3632,13 @@ AstNode *parse_stmt(AstFile *f) {
 					import_decl->ImportDecl.using_in_list = list;
 				}
 				return import_decl;
-			} else if (f->curr_token.kind == Token_export) {
+			} /* else if (f->curr_token.kind == Token_export) {
 				AstNode *export_decl = parse_export_decl(f);
 				if (export_decl->kind == AstNode_ExportDecl) {
 					export_decl->ExportDecl.using_in_list = list;
 				}
 				return export_decl;
-			}
+			} */
 
 			AstNode *expr = parse_expr(f, true);
 			expect_semicolon(f, expr);
@@ -3883,9 +3883,9 @@ void destroy_ast_file(AstFile *f) {
 
 bool init_parser(Parser *p) {
 	GB_ASSERT(p != nullptr);
-	map_init(&p->packages, heap_allocator());
+	map_init(&p->imported_files, heap_allocator());
+	array_init(&p->packages, heap_allocator());
 	array_init(&p->imports, heap_allocator());
-	array_init(&p->files, heap_allocator());
 	gb_mutex_init(&p->file_add_mutex);
 	gb_mutex_init(&p->file_decl_mutex);
 	return true;
@@ -3894,22 +3894,27 @@ bool init_parser(Parser *p) {
 void destroy_parser(Parser *p) {
 	GB_ASSERT(p != nullptr);
 	// TODO(bill): Fix memory leak
-	for_array(i, p->files) {
-		destroy_ast_file(p->files[i]);
+	for_array(i, p->packages) {
+		AstPackage *package = p->packages[i];
+		for_array(j, package->files.entries) {
+			destroy_ast_file(package->files.entries[j].value);
+		}
+		map_destroy(&package->files);
 	}
 #if 0
 	for_array(i, p->imports) {
 		// gb_free(heap_allocator(), p->imports[i].text);
 	}
 #endif
-	array_free(&p->files);
+	array_free(&p->packages);
 	array_free(&p->imports);
+	map_destroy(&p->imported_files);
 	gb_mutex_destroy(&p->file_add_mutex);
 	gb_mutex_destroy(&p->file_decl_mutex);
 }
 
 // NOTE(bill): Returns true if it's added
-bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
+bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos, ImportedPackageKind kind = ImportedPackage_Normal) {
 	if (build_context.generate_docs) {
 		return false;
 	}
@@ -3917,22 +3922,20 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos)
 	path = string_trim_whitespace(path);
 	rel_path = string_trim_whitespace(rel_path);
 
-	for_array(i, p->imports) {
-		String import = p->imports[i].path;
-		if (import == path) {
-			return false;
-		}
+	HashKey key = hash_string(path);
+	if (map_get(&p->imported_files, key) != nullptr) {
+		return false;
 	}
+	map_set(&p->imported_files, key, true);
 
 	ImportedPackage item = {};
-	item.kind     = ImportedPackage_Normal;
+	item.kind     = kind;
 	item.path     = path;
 	item.rel_path = rel_path;
 	item.pos      = pos;
 	item.index    = p->imports.count;
 	array_add(&p->imports, item);
 
-
 	return true;
 }
 
@@ -4054,34 +4057,12 @@ bool determine_path_from_string(Parser *p, AstNode *node, String base_dir, Strin
 }
 
 
-void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNode *> decls);
-
-void parse_setup_file_when_stmt(Parser *p, AstFile *f, String base_dir, AstNodeWhenStmt *ws) {
-	if (ws->body != nullptr) {
-		auto stmts = ws->body->BlockStmt.stmts;
-		parse_setup_file_decls(p, f, base_dir, stmts);
-	}
-
-	if (ws->else_stmt != nullptr) {
-		switch (ws->else_stmt->kind) {
-		case AstNode_BlockStmt: {
-			auto stmts = ws->else_stmt->BlockStmt.stmts;
-			parse_setup_file_decls(p, f, base_dir, stmts);
-		} break;
-		case AstNode_WhenStmt:
-			parse_setup_file_when_stmt(p, f, base_dir, &ws->else_stmt->WhenStmt);
-			break;
-		}
-	}
-}
-
 void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNode *> decls) {
 	for_array(i, decls) {
 		AstNode *node = decls[i];
 		if (!is_ast_node_decl(node) &&
 		    node->kind != AstNode_BadStmt &&
-		    node->kind != AstNode_EmptyStmt &&
-		    node->kind != AstNode_WhenStmt) {
+		    node->kind != AstNode_EmptyStmt) {
 			// NOTE(bill): Sanity check
 
 			if (node->kind == AstNode_ExprStmt) {
@@ -4108,7 +4089,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNod
 
 			id->fullpath = import_path;
 			try_add_import_path(p, import_path, original_string, ast_node_token(node).pos);
-		} else if (node->kind == AstNode_ExportDecl) {
+		} /* else if (node->kind == AstNode_ExportDecl) {
 			ast_node(ed, ExportDecl, node);
 
 			String original_string = ed->relpath.string;
@@ -4123,7 +4104,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNod
 
 			ed->fullpath = export_path;
 			try_add_import_path(p, export_path, original_string, ast_node_token(node).pos);
-		} else if (node->kind == AstNode_ForeignImportDecl) {
+		}  */else if (node->kind == AstNode_ForeignImportDecl) {
 			ast_node(fl, ForeignImportDecl, node);
 
 			String file_str = fl->filepath.string;
@@ -4140,9 +4121,6 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<AstNod
 				fl->fullpath = foreign_path;
 			}
 
-		} else if (node->kind == AstNode_WhenStmt) {
-			ast_node(ws, WhenStmt, node);
-			parse_setup_file_when_stmt(p, f, base_dir, ws);
 		}
 	}
 }
@@ -4241,7 +4219,6 @@ skip:
 	// file->id = imported_package.index;
 	HashKey key = hash_string(fi->fullpath);
 	map_set(&package->files, key, file);
-	array_add(&p->files, file);
 
 	if (package->name.len == 0) {
 		package->name = file->package_name;
@@ -4262,41 +4239,47 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) {
 	String import_rel_path = imported_package.rel_path;
 	TokenPos pos = imported_package.pos;
 
-	HashKey path_key = hash_string(import_path);
-	if (map_get(&p->packages, path_key) != nullptr) {
-		return ParseFile_None;
-	}
-
-
 	Array<FileInfo> list = {};
 	ReadDirectoryError rd_err = read_directory(import_path, &list);
 	defer (array_free(&list));
 
-	if (rd_err != ReadDirectory_EOF && rd_err != ReadDirectory_None && pos.line != 0) {
-		gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
+	if (list.count == 1) {
+		GB_ASSERT(import_path != list[0].fullpath);
 	}
 
-	switch (rd_err) {
-	case ReadDirectory_InvalidPath:
-		gb_printf_err("Invalid path: %.*s\n", LIT(import_rel_path));
-		gb_mutex_lock(&global_error_collector.mutex);
-		global_error_collector.count++;
-		gb_mutex_unlock(&global_error_collector.mutex);
-		return ParseFile_InvalidFile;
-	case ReadDirectory_NotDir:
-		gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(import_rel_path));
-		gb_mutex_lock(&global_error_collector.mutex);
-		global_error_collector.count++;
-		gb_mutex_unlock(&global_error_collector.mutex);
-		return ParseFile_InvalidFile;
-	case ReadDirectory_Unknown:
-		gb_printf_err("Unknown error whilst reading directory");
+	if (rd_err != ReadDirectory_EOF && rd_err != ReadDirectory_None) {
+		if (pos.line != 0) {
+			gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);
+		}
 		gb_mutex_lock(&global_error_collector.mutex);
+		defer (gb_mutex_unlock(&global_error_collector.mutex));
 		global_error_collector.count++;
-		gb_mutex_unlock(&global_error_collector.mutex);
-		return ParseFile_InvalidFile;
-	case ReadDirectory_EOF:
-		break;
+
+
+		switch (rd_err) {
+		case ReadDirectory_InvalidPath:
+			gb_printf_err("Invalid path: %.*s\n", LIT(import_rel_path));
+			return ParseFile_InvalidFile;
+
+		case ReadDirectory_NotExists:
+			gb_printf_err("Path does not exist: %.*s\n", LIT(import_rel_path));
+			return ParseFile_NotFound;
+
+		case ReadDirectory_NotDir:
+			gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(import_rel_path));
+			return ParseFile_InvalidFile;
+
+		case ReadDirectory_Unknown:
+			gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(import_rel_path));
+			return ParseFile_InvalidFile;
+		case ReadDirectory_Permission:
+			gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(import_rel_path));
+			return ParseFile_InvalidFile;
+
+		case ReadDirectory_EOF:
+			gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(import_rel_path));
+			return ParseFile_InvalidFile;
+		}
 	}
 
 	AstPackage *package = gb_alloc_item(heap_allocator(), AstPackage);
@@ -4307,7 +4290,12 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) {
 	// TODO(bill): Fix concurrency
 	for_array(i, list) {
 		FileInfo *fi = &list[i];
-		if (string_ends_with(fi->name, str_lit(".odin"))) {
+		String name = fi->name;
+		String const ext = str_lit(".odin");
+		if (string_ends_with(name, ext)) {
+			if (is_excluded_target_filename(name)) {
+				continue;
+			}
 			ParseFileError err = parse_imported_file(p, package, fi, pos);
 			if (err != ParseFile_None) {
 				return err;
@@ -4315,6 +4303,10 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) {
 		}
 	}
 
+	package->id = p->packages.count+1;
+	array_add(&p->packages, package);
+
+
 	return ParseFile_None;
 }
 
@@ -4342,25 +4334,24 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
 	TokenPos init_pos = {};
 	ImportedPackage init_imported_package = {ImportedPackage_Init, init_fullpath, init_fullpath, init_pos};
 
-	isize shared_file_count = 0;
+	isize shared_package_count = 0;
 	if (!build_context.generate_docs) {
 		String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
-		ImportedPackage runtime_package = {ImportedPackage_Runtime, s, s, init_pos};
-		array_add(&p->imports, runtime_package);
-		shared_file_count++;
+		try_add_import_path(p, s, s, init_pos, ImportedPackage_Runtime);
+		shared_package_count++;
 	}
 
 	array_add(&p->imports, init_imported_package);
 	p->init_fullpath = init_fullpath;
 
 	// IMPORTANT TODO(bill): Figure out why this doesn't work on *nix sometimes
-#if defined(GB_SYSTEM_WINDOWS)
+#if 0 && defined(GB_SYSTEM_WINDOWS)
 	isize thread_count = gb_max(build_context.thread_count, 1);
 	if (thread_count > 1) {
 		isize volatile curr_import_index = 0;
 
 		// NOTE(bill): Make sure that these are in parsed in this order
-		for (isize i = 0; i < shared_file_count; i++) {
+		for (isize i = 0; i < shared_package_count; i++) {
 			ParseFileError err = parse_import(p, p->imports[i]);
 			if (err != ParseFile_None) {
 				return err;

+ 11 - 7
src/parser.hpp

@@ -67,8 +67,8 @@ struct AstFile {
 
 	AstNode *           curr_proc;
 	isize               scope_level;
-	Scope *             scope;       // NOTE(bill): Created in checker
-	DeclInfo *          decl_info;   // NOTE(bill): Created in checker
+	// Scope *             scope;       // NOTE(bill): Created in checker
+	// DeclInfo *          decl_info;   // NOTE(bill): Created in checker
 
 
 	CommentGroup        lead_comment; // Comment (block) before the decl
@@ -84,17 +84,21 @@ struct AstFile {
 
 
 struct AstPackage {
+	isize               id;
 	ImportedPackageKind kind;
 	String              name;
 	String              fullpath;
 	Map<AstFile *>      files; // Key: String (names)
+
+	Scope *   scope;       // NOTE(bill): Created in checker
+	DeclInfo *decl_info;   // NOTE(bill): Created in checker
 };
 
 
 struct Parser {
 	String                 init_fullpath;
-	Map<AstPackage *>      packages; // Key: String (fullpath)
-	Array<AstFile *>       files;
+	Map<bool>              imported_files; // Key: String (fullpath)
+	Array<AstPackage *>    packages;
 	Array<ImportedPackage> imports;
 	isize                  total_token_count;
 	isize                  total_line_count;
@@ -351,7 +355,7 @@ AST_NODE_KIND(_DeclBegin,      "", struct {}) \
 		bool             been_handled; \
 	}) \
 	AST_NODE_KIND(ImportDecl, "import declaration", struct { \
-		AstFile *file;          \
+		AstPackage *package;    \
 		Token    token;         \
 		Token    relpath;       \
 		String   fullpath;      \
@@ -362,7 +366,7 @@ AST_NODE_KIND(_DeclBegin,      "", struct {}) \
 		bool     is_using;      \
 		bool     been_handled;  \
 	}) \
-	AST_NODE_KIND(ExportDecl, "export declaration", struct { \
+	/* AST_NODE_KIND(ExportDecl, "export declaration", struct { \
 		AstFile *file;          \
 		Token    token;         \
 		Token    relpath;       \
@@ -371,7 +375,7 @@ AST_NODE_KIND(_DeclBegin,      "", struct {}) \
 		CommentGroup docs;      \
 		CommentGroup comment;   \
 		bool     been_handled;  \
-	}) \
+	}) */ \
 	AST_NODE_KIND(ForeignImportDecl, "foreign import declaration", struct { \
 		Token    token;           \
 		Token    filepath;        \

+ 7 - 0
src/string.cpp

@@ -94,6 +94,13 @@ String substring(String const &s, isize lo, isize hi) {
 }
 
 
+char *alloc_cstring(gbAllocator a, String s) {
+	char *c_str = gb_alloc_array(a, char, s.len+1);
+	gb_memcopy(c_str, s.text, s.len);
+	c_str[s.len] = '\0';
+	return c_str;
+}
+
 
 
 gb_inline bool str_eq_ignore_case(String const &a, String const &b) {

+ 1 - 4
src/tokenizer.cpp

@@ -448,12 +448,9 @@ void advance_to_next_rune(Tokenizer *t) {
 TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) {
 	TokenizerInitError err = TokenizerInit_None;
 
-	char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
+	char *c_str = alloc_cstring(heap_allocator(), fullpath);
 	defer (gb_free(heap_allocator(), c_str));
 
-	gb_memcopy(c_str, fullpath.text, fullpath.len);
-	c_str[fullpath.len] = '\0';
-
 	// TODO(bill): Memory map rather than copy contents
 	gbFileContents fc = gb_file_read_contents(heap_allocator(), true, c_str);
 	gb_zero_item(t);

Some files were not shown because too many files changed in this diff