Browse Source

Merge pull request #16 from zhiayang/master

Basic, but sketchy, but somewhat usable, non-windows support
gingerBill 8 years ago
parent
commit
c6133587d1
17 changed files with 577 additions and 90 deletions
  1. 18 15
      code/old_demos/demo001.odin
  2. 3 3
      code/test.odin
  3. 1 0
      core/os.odin
  4. 230 0
      core/os_x.odin
  5. 92 0
      src/build.c
  6. 1 1
      src/check_decl.c
  7. 5 1
      src/check_expr.c
  8. 1 0
      src/check_stmt.c
  9. 0 48
      src/checker.c
  10. 59 2
      src/entity.c
  11. 1 0
      src/exact_value.c
  12. 20 3
      src/gb/gb.h
  13. 56 7
      src/main.c
  14. 1 0
      src/parser.c
  15. 52 9
      src/string.c
  16. 36 0
      src/timings.c
  17. 1 1
      src/types.c

+ 18 - 15
code/old_demos/demo001.odin

@@ -6,21 +6,24 @@
 // #import "punity.odin" as pn;
 
 main :: proc() {
-	// struct_padding()
-	// bounds_checking()
-	// type_introspection()
-	// any_type()
-	// crazy_introspection()
-	// namespaces_and_files()
-	// miscellany()
-	// ht.run()
-	// game.run()
-	// {
-	// 	init :: proc(c: ^pn.Core) {}
-	// 	step :: proc(c: ^pn.Core) {}
-
-	// 	pn.run(init, step)
-	// }
+	struct_padding();
+	bounds_checking();
+	type_introspection();
+	any_type();
+	crazy_introspection();
+	namespaces_and_files();
+	miscellany();
+
+	/*
+	ht.run();
+	game.run();
+	{
+		init :: proc(c: ^pn.Core) {}
+		step :: proc(c: ^pn.Core) {}
+
+		pn.run(init, step);
+	}
+	*/
 }
 
 struct_padding :: proc() {

+ 3 - 3
code/test.odin

@@ -5,10 +5,10 @@ thing :: proc() {
 }*/
 
 
-#import "fmt.odin" as format
+#import "fmt.odin";
 
-thing :: proc() {
-	format.println("Hello2!")
+main :: proc() {
+	fmt.println("hello, world!");
 }
 
 

+ 1 - 0
core/os.odin

@@ -1,2 +1,3 @@
 #include "os_windows.odin" when ODIN_OS == "windows";
+#include "os_x.odin" when ODIN_OS == "osx";
 

+ 230 - 0
core/os_x.odin

@@ -0,0 +1,230 @@
+#import "fmt.odin";
+
+Handle    :: i32;
+File_Time :: u64;
+Errno     :: int;
+
+// INVALID_HANDLE: Handle : -1;
+
+
+O_RDONLY   :: 0x00000;
+O_WRONLY   :: 0x00001;
+O_RDWR     :: 0x00002;
+O_CREAT    :: 0x00040;
+O_EXCL     :: 0x00080;
+O_NOCTTY   :: 0x00100;
+O_TRUNC    :: 0x00200;
+O_NONBLOCK :: 0x00800;
+O_APPEND   :: 0x00400;
+O_SYNC     :: 0x01000;
+O_ASYNC    :: 0x02000;
+O_CLOEXEC  :: 0x80000;
+
+// ERROR_NONE:                Errno : 0;
+// ERROR_FILE_NOT_FOUND:      Errno : 2;
+// ERROR_PATH_NOT_FOUND:      Errno : 3;
+// ERROR_ACCESS_DENIED:       Errno : 5;
+// ERROR_NO_MORE_FILES:       Errno : 18;
+// ERROR_HANDLE_EOF:          Errno : 38;
+// ERROR_NETNAME_DELETED:     Errno : 64;
+// ERROR_FILE_EXISTS:         Errno : 80;
+// ERROR_BROKEN_PIPE:         Errno : 109;
+// ERROR_BUFFER_OVERFLOW:     Errno : 111;
+// ERROR_INSUFFICIENT_BUFFER: Errno : 122;
+// ERROR_MOD_NOT_FOUND:       Errno : 126;
+// ERROR_PROC_NOT_FOUND:      Errno : 127;
+// ERROR_DIR_NOT_EMPTY:       Errno : 145;
+// ERROR_ALREADY_EXISTS:      Errno : 183;
+// ERROR_ENVVAR_NOT_FOUND:    Errno : 203;
+// ERROR_MORE_DATA:           Errno : 234;
+// ERROR_OPERATION_ABORTED:   Errno : 995;
+// ERROR_IO_PENDING:          Errno : 997;
+// ERROR_NOT_FOUND:           Errno : 1168;
+// ERROR_PRIVILEGE_NOT_HELD:  Errno : 1314;
+// WSAEACCES:                 Errno : 10013;
+// WSAECONNRESET:             Errno : 10054;
+
+// Windows reserves errors >= 1<<29 for application use
+// ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
+
+#foreign_system_library libc "c";
+
+unix_open :: proc(path: ^u8, mode: int, perm: u32) -> Handle          #foreign libc "open";
+unix_close :: proc(handle: Handle)                                    #foreign libc "close";
+unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int  #foreign libc "read";
+unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #foreign libc "write";
+unix_gettid :: proc() -> u64                                          #foreign libc "gettid";
+
+unix_malloc :: proc(size: int) -> rawptr                              #foreign libc "malloc";
+unix_free :: proc(ptr: rawptr)                                        #foreign libc "free";
+unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr                #foreign libc "realloc";
+
+unix_exit :: proc(status: int)                                        #foreign libc "exit";
+
+
+
+
+open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
+	return unix_open(path.data, mode, perm), 0;
+}
+
+close :: proc(fd: Handle) {
+	unix_close(fd);
+}
+
+write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+	return unix_write(fd, data.data, data.count), 0;
+}
+
+read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+	return unix_read(fd, data.data, data.count), 0;
+}
+
+seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
+	/*
+	using win32;
+	w: u32;
+	match whence {
+	case 0: w = FILE_BEGIN;
+	case 1: w = FILE_CURRENT;
+	case 2: w = FILE_END;
+	}
+	hi := cast(i32)(offset>>32);
+	lo := cast(i32)(offset);
+	ft := GetFileType(cast(HANDLE)fd);
+	if ft == FILE_TYPE_PIPE {
+		return 0, ERROR_FILE_IS_PIPE;
+	}
+	dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
+	if dw_ptr == INVALID_SET_FILE_POINTER {
+		err := GetLastError();
+		return 0, cast(Errno)err;
+	}
+	return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
+
+	*/
+	return 0, 0;
+}
+
+
+// NOTE(bill): Uses startup to initialize it
+stdin: Handle  = 0; // get_std_handle(win32.STD_INPUT_HANDLE);
+stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE);
+stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE);
+
+
+/*
+get_std_handle :: proc(h: int) -> Handle {
+	fd := win32.GetStdHandle(cast(i32)h);
+	win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
+	return cast(Handle)fd;
+}
+
+
+
+
+
+
+last_write_time :: proc(fd: Handle) -> File_Time {
+	file_info: win32.BY_HANDLE_FILE_INFORMATION;
+	win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
+	lo := cast(File_Time)file_info.last_write_time.lo;
+	hi := cast(File_Time)file_info.last_write_time.hi;
+	return lo | hi << 32;
+}
+
+last_write_time_by_name :: proc(name: string) -> File_Time {
+	last_write_time: win32.FILETIME;
+	data: win32.FILE_ATTRIBUTE_DATA;
+	buf: [1024]byte;
+
+	assert(buf.count > name.count);
+
+	copy(buf[:], cast([]byte)name);
+
+	if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
+		last_write_time = data.last_write_time;
+	}
+
+	l := cast(File_Time)last_write_time.lo;
+	h := cast(File_Time)last_write_time.hi;
+	return l | h << 32;
+}
+
+
+
+
+
+read_entire_file :: proc(name: string) -> ([]byte, bool) {
+	buf: [300]byte;
+	copy(buf[:], cast([]byte)name);
+
+	fd, err := open(name, O_RDONLY, 0);
+	if err != ERROR_NONE {
+		return nil, false;
+	}
+	defer close(fd);
+
+	length: i64;
+	file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
+	if !file_size_ok {
+		return nil, false;
+	}
+
+	data := new_slice(u8, length);
+	if data.data == nil {
+		return nil, false;
+	}
+
+	single_read_length: i32;
+	total_read: i64;
+
+	for total_read < length {
+		remaining := length - total_read;
+		to_read: u32;
+		MAX :: 1<<32-1;
+		if remaining <= MAX {
+			to_read = cast(u32)remaining;
+		} else {
+			to_read = MAX;
+		}
+
+		win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
+		if single_read_length <= 0 {
+			free(data);
+			return nil, false;
+		}
+
+		total_read += cast(i64)single_read_length;
+	}
+
+	return data, true;
+}
+
+
+*/
+
+heap_alloc :: proc(size: int) -> rawptr {
+	assert(size > 0);
+	return unix_malloc(size);
+}
+heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
+	return unix_realloc(ptr, new_size);
+}
+heap_free :: proc(ptr: rawptr) {
+	unix_free(ptr);
+}
+
+
+exit :: proc(code: int) {
+	unix_exit(code);
+}
+
+
+current_thread_id :: proc() -> int {
+	// return cast(int) unix_gettid();
+	return 0;
+}
+
+
+

+ 92 - 0
src/build.c

@@ -22,6 +22,7 @@ typedef struct BuildContext {
 String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
 String const NIX_SEPARATOR_STRING   = {cast(u8 *)"/",  1};
 
+#if defined(WINDOWS)
 String odin_root_dir(void) {
 	String path = global_module_path;
 	Array(wchar_t) path_buf;
@@ -71,6 +72,83 @@ String odin_root_dir(void) {
 	return path;
 }
 
+#elif defined(GB_SYSTEM_OSX)
+
+#include <mach-o/dyld.h>
+
+String odin_root_dir(void) {
+	String path = global_module_path;
+	Array(char) path_buf;
+	isize len, i;
+	gbTempArenaMemory tmp;
+	wchar_t *text;
+
+	if (global_module_path_set) {
+		return global_module_path;
+	}
+
+	array_init_count(&path_buf, heap_allocator(), 300);
+
+	len = 0;
+	for (;;) {
+		int sz = path_buf.count;
+		int res = _NSGetExecutablePath(&path_buf.e[0], &sz);
+		if(res == 0) {
+			len = sz;
+			break;
+		} else {
+			array_resize(&path_buf, sz + 1);
+		}
+	}
+
+
+	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
+	gb_memmove(text, &path_buf.e[0], len);
+
+	path = make_string(text, len);
+	for (i = path.len-1; i >= 0; i--) {
+		u8 c = path.text[i];
+		if (c == '/' || c == '\\') {
+			break;
+		}
+		path.len--;
+	}
+
+	global_module_path = path;
+	global_module_path_set = true;
+
+	gb_temp_arena_memory_end(tmp);
+
+	// array_free(&path_buf);
+
+	return path;
+}
+#else
+#error Implement system
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if defined(GB_SYSTEM_WINDOWS)
 String path_to_fullpath(gbAllocator a, String s) {
 	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
 	String16 string16 = string_to_string16(string_buffer_allocator, s);
@@ -86,6 +164,17 @@ String path_to_fullpath(gbAllocator a, String s) {
 	gb_temp_arena_memory_end(tmp);
 	return result;
 }
+#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
+String path_to_fullpath(gbAllocator a, String s) {
+	char* p = realpath(s.text, 0);
+	// GB_ASSERT(p && "file does not exist");
+	if(!p) return make_string_c("");
+
+	return make_string(p, strlen(p));
+}
+#else
+#error Implement system
+#endif
 
 
 String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
@@ -154,6 +243,9 @@ void init_build_context(BuildContext *bc) {
 #if defined(GB_SYSTEM_WINDOWS)
 	bc->ODIN_OS      = str_lit("windows");
 	bc->ODIN_ARCH    = str_lit("amd64");
+#elif defined(GB_SYSTEM_OSX)
+	bc->ODIN_OS      = str_lit("osx");
+	bc->ODIN_ARCH    = str_lit("amd64");
 #else
 #error Implement system
 #endif

+ 1 - 1
src/check_decl.c

@@ -69,7 +69,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
 		AstNode *rhs = inits.e[i];
 		Operand o = {0};
 		check_multi_expr(c, &o, rhs);
-		if (o.type->kind != Type_Tuple) {
+		if (o.type == NULL || o.type->kind != Type_Tuple) {
 			array_add(&operands, o);
 		} else {
 			TypeTuple *tuple = &o.type->Tuple;

+ 5 - 1
src/check_expr.c

@@ -225,6 +225,9 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
 	return -1;
 }
 
+#ifndef _MAX
+#define _MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
 
 bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score_) {
 	i64 score = 0;
@@ -232,7 +235,8 @@ bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type,
 	bool ok = distance >= 0;
 	if (ok) {
 		// TODO(bill): A decent score function
-		score = max(1000000 - distance*distance, 0);
+		// score = max(1000000 - distance*distance, 0);
+		score = _MAX(1000000 - distance*distance, 0);
 	}
 	if (score_) *score_ = score;
 	return ok;

+ 1 - 0
src/check_stmt.c

@@ -724,6 +724,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		}
 
 	skip_expr:
+		;		// again, declaring a variable immediately after a label... weird.
 		AstNode *lhs[2] = {rs->value, rs->index};
 		Type *   rhs[2] = {val, idx};
 

+ 0 - 48
src/checker.c

@@ -118,47 +118,6 @@ typedef enum StmtFlag {
 	Stmt_GiveAllowed        = 1<<3,
 } StmtFlag;
 
-typedef enum BuiltinProcId {
-	BuiltinProc_Invalid,
-
-	BuiltinProc_new,
-	BuiltinProc_new_slice,
-	BuiltinProc_free,
-
-	BuiltinProc_reserve,
-	BuiltinProc_append,
-
-	BuiltinProc_size_of,
-	BuiltinProc_size_of_val,
-	BuiltinProc_align_of,
-	BuiltinProc_align_of_val,
-	BuiltinProc_offset_of,
-	BuiltinProc_offset_of_val,
-	BuiltinProc_type_of_val,
-
-	BuiltinProc_type_info,
-	BuiltinProc_type_info_of_val,
-
-	BuiltinProc_compile_assert,
-	BuiltinProc_assert,
-	BuiltinProc_panic,
-
-	BuiltinProc_copy,
-	// BuiltinProc_append,
-
-	BuiltinProc_swizzle,
-
-	// BuiltinProc_ptr_offset,
-	// BuiltinProc_ptr_sub,
-	BuiltinProc_slice_ptr,
-
-	BuiltinProc_min,
-	BuiltinProc_max,
-	BuiltinProc_abs,
-	BuiltinProc_clamp,
-
-	BuiltinProc_Count,
-} BuiltinProcId;
 typedef struct BuiltinProc {
 	String   name;
 	isize    arg_count;
@@ -205,13 +164,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
 	{STR_LIT("clamp"),            3, false, Expr_Expr},
 };
 
-typedef enum ImplicitValueId {
-	ImplicitValue_Invalid,
-
-	ImplicitValue_context,
-
-	ImplicitValue_Count,
-} ImplicitValueId;
 typedef struct ImplicitValueInfo {
 	String  name;
 	String  backing_name;

+ 59 - 2
src/entity.c

@@ -1,8 +1,65 @@
 typedef struct Scope Scope;
 typedef struct Checker Checker;
 typedef struct Type Type;
-typedef enum BuiltinProcId BuiltinProcId;
-typedef enum ImplicitValueId ImplicitValueId;
+// typedef enum BuiltinProcId BuiltinProcId;
+// typedef enum ImplicitValueId ImplicitValueId;
+
+
+
+typedef enum BuiltinProcId {
+	BuiltinProc_Invalid,
+
+	BuiltinProc_new,
+	BuiltinProc_new_slice,
+	BuiltinProc_free,
+
+	BuiltinProc_reserve,
+	BuiltinProc_append,
+
+	BuiltinProc_size_of,
+	BuiltinProc_size_of_val,
+	BuiltinProc_align_of,
+	BuiltinProc_align_of_val,
+	BuiltinProc_offset_of,
+	BuiltinProc_offset_of_val,
+	BuiltinProc_type_of_val,
+
+	BuiltinProc_type_info,
+	BuiltinProc_type_info_of_val,
+
+	BuiltinProc_compile_assert,
+	BuiltinProc_assert,
+	BuiltinProc_panic,
+
+	BuiltinProc_copy,
+	// BuiltinProc_append,
+
+	BuiltinProc_swizzle,
+
+	// BuiltinProc_ptr_offset,
+	// BuiltinProc_ptr_sub,
+	BuiltinProc_slice_ptr,
+
+	BuiltinProc_min,
+	BuiltinProc_max,
+	BuiltinProc_abs,
+	BuiltinProc_clamp,
+
+	BuiltinProc_Count,
+} BuiltinProcId;
+
+
+typedef enum ImplicitValueId {
+	ImplicitValue_Invalid,
+
+	ImplicitValue_context,
+
+	ImplicitValue_Count,
+} ImplicitValueId;
+
+
+
+
 
 #define ENTITY_KINDS \
 	ENTITY_KIND(Invalid) \

+ 1 - 0
src/exact_value.c

@@ -416,6 +416,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
 	}
 
 error:
+	;		// MSVC accepts this??? apparently you cannot declare variables immediately after labels...
 	ExactValue error_value = {0};
 	// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op));
 	return error_value;

+ 20 - 3
src/gb/gb.h

@@ -276,6 +276,8 @@ extern "C" {
 #include <stdarg.h>
 #include <stddef.h>
 
+
+
 #if defined(GB_SYSTEM_WINDOWS)
 	#if !defined(GB_NO_WINDOWS_H)
 		#define NOMINMAX            1
@@ -296,6 +298,7 @@ extern "C" {
 	#include <errno.h>
 	#include <fcntl.h>
 	#include <pthread.h>
+	#define _IOSC11_SOURCE
 	#include <stdlib.h> // NOTE(bill): malloc on linux
 	#include <sys/mman.h>
 	#if !defined(GB_SYSTEM_OSX)
@@ -4819,14 +4822,17 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
 #else
 	// TODO(bill): *nix version that's decent
 	case gbAllocation_Alloc: {
-		ptr = aligned_alloc(alignment, size);
+		// ptr = aligned_alloc(alignment, size);
+
+		posix_memalign(&ptr, alignment, size);
+
 		if (flags & gbAllocatorFlag_ClearToZero) {
 			gb_zero_size(ptr, size);
 		}
 	} break;
 
 	case gbAllocation_Free: {
-		free(gb_allocation_header(old_memory));
+		// free(old_memory);
 	} break;
 
 	case gbAllocation_Resize: {
@@ -7754,7 +7760,18 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
 	return gb_alloc_str_len(a, buf, len+1);
 #else
 // TODO(bill): Make work on *nix, etc.
-	return gb_alloc_str_len(a, path, gb_strlen(path));
+	char* p = realpath(path, 0);
+	GB_ASSERT(p && "file does not exist");
+
+	isize len = gb_strlen(p);
+
+	// bill... gb_alloc_str_len refused to work for this...
+	char* ret = gb_alloc(a, sizeof(char) * len + 1);
+	gb_memmove(ret, p, len);
+	ret[len] = 0;
+	free(p);
+
+	return ret;
 #endif
 }
 

+ 56 - 7
src/main.c

@@ -16,8 +16,10 @@ extern "C" {
 #include "ir_print.c"
 // #include "vm.c"
 
+#if defined(GB_SYSTEM_WINDOWS)
+
 // NOTE(bill): `name` is used in debugging and profiling modes
-i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
+i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 	STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
 	PROCESS_INFORMATION pi = {0};
 	char cmd_line[4096] = {0};
@@ -59,6 +61,53 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 	gb_temp_arena_memory_end(tmp);
 	return exit_code;
 }
+#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
+i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
+
+	char cmd_line[4096] = {0};
+	isize cmd_len;
+	va_list va;
+	String cmd;
+	i32 exit_code = 0;
+
+	va_start(va, fmt);
+	cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
+	va_end(va);
+
+	exit_code = system(cmd.text);
+
+	// pid_t pid = fork();
+	// int status = 0;
+
+	// if(pid == 0) {
+	// 	// in child, pid == 0.
+	// 	int ret = execvp(cmd.text, (char* const*) cmd.text);
+
+	// 	if(ret == -1) {
+	// 		gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
+
+	// 		// we're in the child, so returning won't do us any good -- just quit.
+	// 		exit(-1);
+	// 	}
+
+	// 	// unreachable
+	// 	abort();
+	// } else {
+	// 	// wait for child to finish, then we can continue cleanup
+
+	// 	int s = 0;
+	// 	waitpid(pid, &s, 0);
+
+	// 	status = WEXITSTATUS(s);
+	// }
+
+	// exit_code = status;
+}
+#endif
+
+
+
+
 
 void print_usage_line(i32 indent, char *fmt, ...) {
 	while (indent --> 0) {
@@ -190,7 +239,7 @@ int main(int argc, char **argv) {
 
 	// prof_print_all();
 
-#if 1
+	#if 1
 	timings_start_section(&timings, str_lit("llvm-opt"));
 
 	char const *output_name = ir_gen.output_file.filename;
@@ -202,7 +251,7 @@ int main(int argc, char **argv) {
 
 	i32 exit_code = 0;
 	// For more passes arguments: http://llvm.org/docs/Passes.html
-	exit_code = win32_exec_command_line_app("llvm-opt", false,
+	exit_code = system_exec_command_line_app("llvm-opt", false,
 		"\"%.*sbin/opt\" \"%s\" -o \"%.*s\".bc "
 		"-mem2reg "
 		"-memcpyopt "
@@ -217,10 +266,10 @@ int main(int argc, char **argv) {
 		return exit_code;
 	}
 
-	#if 1
+	#if 0
 	timings_start_section(&timings, str_lit("llvm-llc"));
 	// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
-	exit_code = win32_exec_command_line_app("llvm-llc", false,
+	exit_code = system_exec_command_line_app("llvm-llc", false,
 		"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
 		"%.*s "
 		// "-debug-pass=Arguments "
@@ -255,7 +304,7 @@ int main(int argc, char **argv) {
 		link_settings = "/ENTRY:mainCRTStartup";
 	}
 
-	exit_code = win32_exec_command_line_app("msvc-link", true,
+	exit_code = system_exec_command_line_app("msvc-link", true,
 		"link \"%.*s\".obj -OUT:\"%.*s.%s\" %s "
 		"/defaultlib:libcmt "
 		"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
@@ -273,7 +322,7 @@ int main(int argc, char **argv) {
 	// timings_print_all(&timings);
 
 	if (run_output) {
-		win32_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
+		system_exec_command_line_app("odin run", false, "%.*s.exe", cast(int)base_name_len, output_name);
 	}
 	#endif
 #endif

+ 1 - 0
src/parser.c

@@ -3731,6 +3731,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
 		String import_rel_path = imported_file.rel_path;
 		TokenPos pos = imported_file.pos;
 		AstFile file = {0};
+
 		ParseFileError err = init_ast_file(&file, import_path);
 
 		if (err != ParseFile_None) {

+ 52 - 9
src/string.c

@@ -165,6 +165,54 @@ bool string_contains_char(String s, u8 c) {
 	return false;
 }
 
+
+
+
+
+
+
+
+
+#if defined(GB_SYSTEM_WINDOWS)
+
+	int convert_multibyte_to_widechar(char* multibyte_input, int input_length, wchar_t* output, int output_size)
+	{
+		return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, multibyte_input, input_length, output, output_size);
+	}
+
+	int convert_widechar_to_multibyte(wchar_t* widechar_input, int input_length, char* output, int output_size)
+	{
+		return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, NULL, NULL);
+	}
+}
+#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
+
+	#include <iconv.h>
+
+	int convert_multibyte_to_widechar(char* multibyte_input, int input_length, wchar_t* output, int output_size)
+	{
+		iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
+		size_t result = iconv(conv, (char**) &multibyte_input, &input_length, (char**) &output, &output_size);
+		iconv_close(conv);
+
+		return (int) result;
+	}
+
+	int convert_widechar_to_multibyte(wchar_t* widechar_input, int input_length, char* output, int output_size)
+	{
+		iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
+		size_t result = iconv(conv, (char**) &widechar_input, &input_length, (char**) &output, &output_size);
+		iconv_close(conv);
+
+		return (int) result;
+	}
+#else
+#error Implement system
+#endif
+
+
+
+
 // TODO(bill): Make this non-windows specific
 String16 string_to_string16(gbAllocator a, String s) {
 	int len, len1;
@@ -174,16 +222,14 @@ String16 string_to_string16(gbAllocator a, String s) {
 		return make_string16(NULL, 0);
 	}
 
-	len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
-	                          cast(char *)s.text, s.len, NULL, 0);
+	len = convert_multibyte_to_widechar(cast(char *)s.text, s.len, NULL, 0);
 	if (len == 0) {
 		return make_string16(NULL, 0);
 	}
 
 	text = gb_alloc_array(a, wchar_t, len+1);
 
-	len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
-	                           cast(char *)s.text, s.len, text, len);
+	len1 = convert_multibyte_to_widechar(cast(char *)s.text, s.len, text, len);
 	if (len1 == 0) {
 		gb_free(a, text);
 		return make_string16(NULL, 0);
@@ -201,16 +247,14 @@ String string16_to_string(gbAllocator a, String16 s) {
 		return make_string(NULL, 0);
 	}
 
-	len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
-	                          s.text, s.len, NULL, 0, NULL, NULL);
+	len = convert_widechar_to_multibyte(s.text, s.len, NULL, 0);
 	if (len == 0) {
 		return make_string(NULL, 0);
 	}
 
 	text = gb_alloc_array(a, u8, len+1);
 
-	len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
-	                           s.text, s.len, cast(char *)text, len, NULL, NULL);
+	len1 = convert_widechar_to_multibyte(s.text, s.len, cast(char *)text, len);
 	if (len1 == 0) {
 		gb_free(a, text);
 		return make_string(NULL, 0);
@@ -236,7 +280,6 @@ String string16_to_string(gbAllocator a, String16 s) {
 
 
 
-
 bool unquote_char(String s, u8 quote, Rune *rune, bool *multiple_bytes, String *tail_string) {
 	u8 c;
 

+ 36 - 0
src/timings.c

@@ -11,6 +11,7 @@ typedef struct Timings {
 } Timings;
 
 
+#if defined(GB_SYSTEM_WINDOWS)
 u64 win32_time_stamp_time_now(void) {
 	LARGE_INTEGER counter;
 	QueryPerformanceCounter(&counter);
@@ -26,10 +27,43 @@ u64 win32_time_stamp__freq(void) {
 
 	return win32_perf_count_freq.QuadPart;
 }
+#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
+#include <time.h>
+
+u64 unix_time_stamp_time_now(void) {
+	struct timespec ts;
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
+
+	return (ts.tv_sec * 1000000000) + ts.tv_nsec;
+}
+
+u64 unix_time_stamp__freq(void) {
+	gb_local_persist u64 freq = 0;
+
+	if (freq == 0) {
+		struct timespec ts;
+		clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
+
+		// that would be an absurd resolution (or lack thereof)
+		GB_ASSERT(ts.tv_sec == 0);
+
+		freq = cast(u64) ((1.0 / ts.tv_nsec) * 1000000000.0);
+
+		GB_ASSERT(freq != 0);
+	}
+
+	return freq;
+}
+
+#else
+#error Implement system
+#endif
 
 u64 time_stamp_time_now(void) {
 #if defined(GB_SYSTEM_WINDOWS)
 	return win32_time_stamp_time_now();
+#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
+	return unix_time_stamp_time_now();
 #else
 #error time_stamp_time_now
 #endif
@@ -38,6 +72,8 @@ u64 time_stamp_time_now(void) {
 u64 time_stamp__freq(void) {
 #if defined(GB_SYSTEM_WINDOWS)
 	return win32_time_stamp__freq();
+#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
+	return unix_time_stamp__freq();
 #else
 #error time_stamp__freq
 #endif

+ 1 - 1
src/types.c

@@ -1348,7 +1348,7 @@ void type_path_pop(TypePath *tp) {
 
 i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
 i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
-i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index);
+i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index);
 
 i64 type_size_of_internal (BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path);
 i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path);