Browse Source

Unicode file loading; push_allocator & push_context

Ginger Bill 9 years ago
parent
commit
a31bab5aae

+ 1 - 1
build.bat

@@ -24,7 +24,7 @@ set compiler_warnings= ^
 	-wd4505 -wd4512 -wd4550
 
 set compiler_includes=
-set libs= kernel32.lib user32.lib gdi32.lib opengl32.lib
+set libs= kernel32.lib
 
 set linker_flags= -incremental:no -opt:ref -subsystem:console
 

+ 14 - 2
code/demo.odin

@@ -1,19 +1,31 @@
 #import "fmt.odin"
 #import "os.odin"
+#import "mem.odin"
 // #import "http_test.odin" as ht
 // #import "game.odin" as game
 // #import "punity.odin" as pn
 
 
 main :: proc() {
+
+	arena: mem.Arena
+	mem.init_arena_from_context(^arena, 1000)
+	defer mem.free_arena(^arena)
+
+	push_allocator mem.arena_allocator(^arena) {
+		x := new(int)
+		x^ = 1337
+		fmt.println(x^)
+	}
+
+
 	// struct_padding()
 	// bounds_checking()
 	// type_introspection()
 	// any_type()
 	// crazy_introspection()
-	namespaces_and_files()
+	// namespaces_and_files()
 	// miscellany()
-
 	// ht.run()
 	// game.run()
 	// {

+ 0 - 1
code/test.odin

@@ -33,4 +33,3 @@ thing :: proc() {
 thing :: proc() {
 	println("Hello5!")
 }*/
-

+ 5 - 4
core/runtime.odin

@@ -130,6 +130,7 @@ memory_compare :: proc(dst, src: rawptr, len: int) -> int {
 }
 
 memory_copy :: proc(dst, src: rawptr, len: int) #inline {
+	// NOTE(bill): This _must_ implemented like C's memmove
 	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
 	llvm_memmove_64bit(dst, src, len, 1, false)
 }
@@ -142,7 +143,7 @@ memory_copy :: proc(dst, src: rawptr, len: int) #inline {
 
 
 
-Allocator :: struct {
+Allocator :: struct #ordered {
 	Mode :: enum {
 		ALLOC,
 		FREE,
@@ -159,7 +160,7 @@ Allocator :: struct {
 }
 
 
-Context :: struct {
+Context :: struct #ordered {
 	thread_id: int
 
 	allocator: Allocator
@@ -279,8 +280,6 @@ __default_allocator :: proc() -> Allocator {
 
 
 
-
-
 __string_eq :: proc(a, b: string) -> bool {
 	if a.count != b.count {
 		return false
@@ -382,3 +381,5 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
 	return ""
 }
 
+
+

+ 1 - 0
misc/shell.bat

@@ -1,6 +1,7 @@
 @echo off
 
 call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
+rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
 set _NO_DEBUG_HEAP=1
 

+ 22 - 4
src/checker/checker.cpp

@@ -839,10 +839,9 @@ void check_type_name_cycles(Checker *c, CycleCheck *cc, Entity *e) {
 	// }
 }
 
-void init_type_info_types(Checker *c) {
+void init_runtime_types(Checker *c) {
 	if (t_type_info == NULL) {
-		String type_info_str = make_string("Type_Info");
-		Entity *e = current_scope_lookup_entity(c->global_scope, type_info_str);
+		Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Type_Info"));
 		if (e == NULL) {
 			compiler_error("Could not find type declaration for `Type_Info`\n"
 			               "Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
@@ -875,6 +874,25 @@ void init_type_info_types(Checker *c) {
 		t_type_info_enum      = record->fields[15]->type;
 	}
 
+	if (t_allocator == NULL) {
+		Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Allocator"));
+		if (e == NULL) {
+			compiler_error("Could not find type declaration for `Allocator`\n"
+			               "Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
+		}
+		t_allocator = e->type;
+		t_allocator_ptr = make_type_pointer(c->allocator, t_allocator);
+	}
+
+	if (t_context == NULL) {
+		Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Context"));
+		if (e == NULL) {
+			compiler_error("Could not find type declaration for `Context`\n"
+			               "Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
+		}
+		t_context = e->type;
+		t_context_ptr = make_type_pointer(c->allocator, t_context);
+	}
 }
 
 
@@ -1131,7 +1149,7 @@ void check_parsed_files(Checker *c) {
 
 	check_global_entity(c, Entity_TypeName);
 
-	init_type_info_types(c);
+	init_runtime_types(c);
 #if 1
 	check_global_entity(c, Entity_Constant);
 	check_global_entity(c, Entity_Procedure);

+ 39 - 23
src/checker/expr.cpp

@@ -266,15 +266,19 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 				AstNode *name = cd->names[i];
 				Entity *e = entities[i];
 				Token name_token = name->Ident;
-				HashKey key = hash_string(name_token.string);
-				if (map_get(&entity_map, key) != NULL) {
-					// TODO(bill): Scope checking already checks the declaration
-					error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
-				} else {
-					map_set(&entity_map, key, e);
+				if (name_token.string == make_string("_")) {
 					other_fields[other_field_index++] = e;
+				} else {
+					HashKey key = hash_string(name_token.string);
+					if (map_get(&entity_map, key) != NULL) {
+						// TODO(bill): Scope checking already checks the declaration
+						error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
+					} else {
+						map_set(&entity_map, key, e);
+						other_fields[other_field_index++] = e;
+					}
+					add_entity(c, c->context.scope, name, e);
 				}
-				add_entity(c, c->context.scope, name, e);
 			}
 		} else if (decl->kind == AstNode_TypeDecl) {
 			ast_node(td, TypeDecl, decl);
@@ -284,15 +288,19 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 			add_entity(c, c->context.scope, td->name, e);
 			check_type_decl(c, e, td->type, NULL, NULL);
 
-			HashKey key = hash_string(name_token.string);
-			if (map_get(&entity_map, key) != NULL) {
-				// TODO(bill): Scope checking already checks the declaration
-				error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
-			} else {
-				map_set(&entity_map, key, e);
+			if (name_token.string == make_string("_")) {
 				other_fields[other_field_index++] = e;
+			} else {
+				HashKey key = hash_string(name_token.string);
+				if (map_get(&entity_map, key) != NULL) {
+					// TODO(bill): Scope checking already checks the declaration
+					error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
+				} else {
+					map_set(&entity_map, key, e);
+					other_fields[other_field_index++] = e;
+				}
+				add_entity_use(&c->info, td->name, e);
 			}
-			add_entity_use(&c->info, td->name, e);
 		}
 
 	}
@@ -318,6 +326,11 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 				type->Named.type_name = e;
 				add_entity(c, c->context.scope, name, e);
 
+				if (name_token.string == make_string("_")) {
+					error(name_token, "`_` cannot be used a union subtype");
+					continue;
+				}
+
 				HashKey key = hash_string(name_token.string);
 				if (map_get(&entity_map, key) != NULL) {
 					// TODO(bill): Scope checking already checks the declaration
@@ -352,17 +365,20 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
 				Token name_token = name->Ident;
 
 				Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, vd->is_using, cast(i32)field_index);
-				HashKey key = hash_string(name_token.string);
-				if (map_get(&entity_map, key) != NULL) {
-					// TODO(bill): Scope checking already checks the declaration
-					error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string));
+				if (name_token.string == make_string("_")) {
+					fields[field_index++] = e;
 				} else {
-					map_set(&entity_map, key, e);
-					fields[field_index] = e;
-					field_index++;
-					add_entity(c, c->context.scope, name, e);
+					HashKey key = hash_string(name_token.string);
+					if (map_get(&entity_map, key) != NULL) {
+						// TODO(bill): Scope checking already checks the declaration
+						error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string));
+					} else {
+						map_set(&entity_map, key, e);
+						fields[field_index++] = e;
+						add_entity(c, c->context.scope, name, e);
+					}
+					add_entity_use(&c->info, name, e);
 				}
-				add_entity_use(&c->info, name, e);
 			}
 
 

+ 17 - 0
src/checker/stmt.cpp

@@ -1483,6 +1483,23 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 
 
 
+	case_ast_node(pa, PushAllocator, node);
+		Operand op = {};
+		check_expr(c, &op, pa->expr);
+		check_assignment(c, &op, t_allocator, make_string("argument to push_allocator"));
+		check_stmt(c, pa->body, mod_flags);
+	case_end;
+
+
+	case_ast_node(pa, PushContext, node);
+		Operand op = {};
+		check_expr(c, &op, pa->expr);
+		check_assignment(c, &op, t_context, make_string("argument to push_context"));
+		check_stmt(c, pa->body, mod_flags);
+	case_end;
+
+
+
 
 
 

+ 17 - 13
src/checker/type.cpp

@@ -4,21 +4,20 @@ enum BasicKind {
 	Basic_Invalid,
 	Basic_bool,
 	Basic_i8,
-	Basic_i16,
-	Basic_i32,
-	Basic_i64,
 	Basic_u8,
+	Basic_i16,
 	Basic_u16,
+	Basic_i32,
 	Basic_u32,
+	Basic_i64,
 	Basic_u64,
 	Basic_f32,
 	Basic_f64,
 	Basic_int,
 	Basic_uint,
 	Basic_rawptr,
-	Basic_string,
-
-	Basic_any,
+	Basic_string, // ^u8 + int
+	Basic_any,    // ^Type_Info + rawptr
 
 	Basic_UntypedBool,
 	Basic_UntypedInteger,
@@ -27,7 +26,6 @@ enum BasicKind {
 	Basic_UntypedString,
 	Basic_UntypedRune,
 
-
 	Basic_Count,
 
 	Basic_byte = Basic_u8,
@@ -294,12 +292,12 @@ gb_global Type basic_types[] = {
 	{0, Type_Basic, {Basic_Invalid,        0,                                      STR_LIT("invalid type")}},
 	{0, Type_Basic, {Basic_bool,           BasicFlag_Boolean,                      STR_LIT("bool")}},
 	{0, Type_Basic, {Basic_i8,             BasicFlag_Integer,                      STR_LIT("i8")}},
-	{0, Type_Basic, {Basic_i16,            BasicFlag_Integer,                      STR_LIT("i16")}},
-	{0, Type_Basic, {Basic_i32,            BasicFlag_Integer,                      STR_LIT("i32")}},
-	{0, Type_Basic, {Basic_i64,            BasicFlag_Integer,                      STR_LIT("i64")}},
 	{0, Type_Basic, {Basic_u8,             BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}},
+	{0, Type_Basic, {Basic_i16,            BasicFlag_Integer,                      STR_LIT("i16")}},
 	{0, Type_Basic, {Basic_u16,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}},
+	{0, Type_Basic, {Basic_i32,            BasicFlag_Integer,                      STR_LIT("i32")}},
 	{0, Type_Basic, {Basic_u32,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}},
+	{0, Type_Basic, {Basic_i64,            BasicFlag_Integer,                      STR_LIT("i64")}},
 	{0, Type_Basic, {Basic_u64,            BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}},
 	{0, Type_Basic, {Basic_f32,            BasicFlag_Float,                        STR_LIT("f32")}},
 	{0, Type_Basic, {Basic_f64,            BasicFlag_Float,                        STR_LIT("f64")}},
@@ -370,6 +368,12 @@ gb_global Type *t_type_info_raw_union  = NULL;
 gb_global Type *t_type_info_enum       = NULL;
 gb_global Type *t_type_info_any        = NULL;
 
+gb_global Type *t_allocator            = NULL;
+gb_global Type *t_allocator_ptr        = NULL;
+gb_global Type *t_context              = NULL;
+gb_global Type *t_context_ptr          = NULL;
+
+
 
 
 b32 is_type_named(Type *t) {
@@ -674,12 +678,12 @@ gb_global i64 basic_type_sizes[] = {
 	0,  // Basic_Invalid
 	1,  // Basic_bool
 	1,  // Basic_i8
-	2,  // Basic_i16
-	4,  // Basic_i32
-	8,  // Basic_i64
 	1,  // Basic_u8
+	2,  // Basic_i16
 	2,  // Basic_u16
+	4,  // Basic_i32
 	4,  // Basic_u32
+	8,  // Basic_i64
 	8,  // Basic_u64
 	4,  // Basic_f32
 	8,  // Basic_f64

+ 0 - 1
src/codegen/codegen.cpp

@@ -48,7 +48,6 @@ String ssa_mangle_name(ssaGen *s, String path, String name) {
 		if (str[i] == '\\') {
 			str[i] = '/';
 		}
-
 	}
 
 	char const *base = gb_path_base_name(str);

+ 10 - 5
src/codegen/print_llvm.cpp

@@ -84,8 +84,11 @@ void ssa_print_escape_string(ssaFileBuffer *f, String name, b32 print_quotes) {
 
 	char hex_table[] = "0123456789ABCDEF";
 	isize buf_len = name.len + extra + 2;
-	u8 *buf = gb_alloc_array(gb_heap_allocator(), u8, buf_len);
-	defer (gb_free(gb_heap_allocator(), buf));
+
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	defer (gb_temp_arena_memory_end(tmp));
+
+	u8 *buf = gb_alloc_array(string_buffer_allocator, u8, buf_len);
 
 	isize j = 0;
 
@@ -809,9 +812,11 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 
 
 	if (proc->module->generate_debug_info && proc->entity != NULL) {
-		ssaDebugInfo *di = *map_get(&proc->module->debug_info, hash_pointer(proc->entity));
-		GB_ASSERT(di->kind == ssaDebugInfo_Proc);
-		ssa_fprintf(f, "!dbg !%d ", di->id);
+		if (proc->body != NULL) {
+			ssaDebugInfo *di = *map_get(&proc->module->debug_info, hash_pointer(proc->entity));
+			GB_ASSERT(di->kind == ssaDebugInfo_Proc);
+			ssa_fprintf(f, "!dbg !%d ", di->id);
+		}
 	}
 
 

+ 45 - 5
src/codegen/ssa.cpp

@@ -2200,10 +2200,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					ssaValue *elem_size  = ssa_make_const_int(allocator, s);
 					ssaValue *elem_align = ssa_make_const_int(allocator, a);
 
-					ssaValue *len = ssa_build_expr(proc, ce->args[1]);
+					ssaValue *len =ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[1]), t_int);
 					ssaValue *cap = len;
 					if (gb_array_count(ce->args) == 3) {
-						cap = ssa_build_expr(proc, ce->args[2]);
+						cap = ssa_emit_conv(proc, ssa_build_expr(proc, ce->args[2]), t_int);
 					}
 
 					ssa_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false);
@@ -2218,9 +2218,13 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 
 					ssaValue *ptr = ssa_emit_conv(proc, call, ptr_type, true);
 					ssaValue *slice = ssa_add_local_generated(proc, slice_type);
-					ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_zero32, ptr_type), ptr);
-					ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_one32,  t_int),    len);
-					ssa_emit_store(proc, ssa_emit_struct_gep(proc, slice, v_two32,  t_int),    cap);
+
+					ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ptr_type);
+					ssaValue *gep1 = ssa_emit_struct_gep(proc, slice, v_one32, t_int);
+					ssaValue *gep2 = ssa_emit_struct_gep(proc, slice, v_two32, t_int);
+					ssa_emit_store(proc, gep0, ptr);
+					ssa_emit_store(proc, gep1, len);
+					ssa_emit_store(proc, gep2, cap);
 					return ssa_emit_load(proc, slice);
 				} break;
 
@@ -3678,6 +3682,42 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		ssa_emit_unreachable(proc);
 	case_end;
 
+
+
+	case_ast_node(pa, PushAllocator, node);
+		ssa_emit_comment(proc, make_string("PushAllocator"));
+
+		ssaValue *context_ptr = *map_get(&proc->module->members, hash_string(make_string("__context")));
+		ssaValue *prev_context = ssa_add_local_generated(proc, t_context);
+		ssa_emit_store(proc, prev_context, ssa_emit_load(proc, context_ptr));
+		defer (ssa_emit_store(proc, context_ptr, ssa_emit_load(proc, prev_context)));
+
+		ssaValue *gep = ssa_emit_struct_gep(proc, context_ptr, 1, t_allocator_ptr);
+		ssa_emit_store(proc, gep, ssa_build_expr(proc, pa->expr));
+
+		proc->scope_index++;
+		ssa_build_stmt(proc, pa->body);
+		proc->scope_index--;
+
+	case_end;
+
+
+	case_ast_node(pa, PushContext, node);
+		ssa_emit_comment(proc, make_string("PushContext"));
+
+		ssaValue *context_ptr = *map_get(&proc->module->members, hash_string(make_string("__context")));
+		ssaValue *prev_context = ssa_add_local_generated(proc, t_context);
+		ssa_emit_store(proc, prev_context, ssa_emit_load(proc, context_ptr));
+		defer (ssa_emit_store(proc, context_ptr, ssa_emit_load(proc, prev_context)));
+
+		ssa_emit_store(proc, context_ptr, ssa_build_expr(proc, pa->expr));
+
+		proc->scope_index++;
+		ssa_build_stmt(proc, pa->body);
+		proc->scope_index--;
+	case_end;
+
+
 	}
 }
 

+ 41 - 0
src/common.cpp

@@ -4,6 +4,47 @@
 
 #include "string.cpp"
 
+String get_module_dir(gbAllocator a) {
+	isize len = GetModuleFileNameW(NULL, NULL, 0);
+	if (len == 0) {
+		return make_string(NULL, 0);
+	}
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	defer (gb_temp_arena_memory_end(tmp));
+
+	
+	wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
+
+	String16 str = {text, len};
+	GetModuleFileNameW(NULL, text, len);
+	String path = string16_to_string(a, str);
+	for (isize i = path.len-1; i >= 0; i--) {
+		u8 c = path.text[i];
+		if (c == '/' || c == '\\') {
+			break;
+		}
+		path.len--;
+	}
+	
+	return path;
+}
+
+String path_to_fullpath(gbAllocator a, String s) {
+	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	defer (gb_temp_arena_memory_end(tmp));
+
+	String16 string16 = string_to_string16(string_buffer_allocator, s);
+
+	DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL);
+	if (len == 0) {
+		return make_string(NULL, 0);
+	}
+	wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1);
+	GetFullPathNameW(string16.text, len, text, NULL);
+	text[len] = 0;
+
+	return string16_to_string(a, make_string16(text, len));
+}
 
 struct BlockTimer {
 	u64 start;

+ 2 - 2
src/exact_value.cpp

@@ -190,7 +190,7 @@ ExactValue exact_unary_operator_value(Token op, ExactValue v, i32 precision) {
 	}
 
 failure:
-	compiler_error("Invalid unary operation, %.*s", LIT(token_strings[op.kind]));
+	GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op.kind]));
 
 	ExactValue error_value = {};
 	return error_value;
@@ -212,7 +212,7 @@ i32 exact_value_order(ExactValue v) {
 		return 4;
 
 	default:
-		compiler_error("How'd you get here? Invalid Value.kind");
+		GB_PANIC("How'd you get here? Invalid Value.kind");
 		return -1;
 	}
 }

+ 2 - 2
src/gb/gb.h

@@ -3948,7 +3948,7 @@ void const *gb_memrchr(void const *data, u8 c, isize n) {
 
 gb_inline void *gb_alloc_align (gbAllocator a, isize size, isize alignment)                                { return a.proc(a.data, gbAllocation_Alloc, size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); }
 gb_inline void *gb_alloc       (gbAllocator a, isize size)                                                 { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); }
-gb_inline void  gb_free        (gbAllocator a, void *ptr)                                                  { a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); }
+gb_inline void  gb_free        (gbAllocator a, void *ptr)                                                  { if (ptr != NULL) a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); }
 gb_inline void  gb_free_all    (gbAllocator a)                                                             { a.proc(a.data, gbAllocation_FreeAll, 0, 0, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); }
 gb_inline void *gb_resize      (gbAllocator a, void *ptr, isize old_size, isize new_size)                  { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); }
 gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { return a.proc(a.data, gbAllocation_Resize, new_size, alignment, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); }
@@ -4698,7 +4698,7 @@ void gb_thread_set_name(gbThread *t, char const *name) {
 		tn.flags = 0;
 
 		__try {
-			RaiseException(0x406d1388, 0, gb_size_of(tn)/4, cast(usize *)&tn);
+			RaiseException(0x406d1388, 0, gb_size_of(tn)/4, cast(ULONG_PTR *)&tn);
 		} __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) {
 		}
 

+ 69 - 36
src/main.cpp

@@ -7,26 +7,35 @@
 #include "codegen/codegen.cpp"
 
 i32 win32_exec_command_line_app(char *fmt, ...) {
-	STARTUPINFOA start_info = {gb_size_of(STARTUPINFOA)};
+	STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
 	PROCESS_INFORMATION pi = {};
+	char cmd_line[2048] = {};
+	isize cmd_len;
+	va_list va;
+	gbTempArenaMemory tmp;
+	String16 cmd;
+
 	start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 	start_info.wShowWindow = SW_SHOW;
 	start_info.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);
 	start_info.hStdOutput  = GetStdHandle(STD_OUTPUT_HANDLE);
 	start_info.hStdError   = GetStdHandle(STD_ERROR_HANDLE);
 
-	char cmd_line[2048] = {};
-	va_list va;
 	va_start(va, fmt);
-	gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
+	cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
 	va_end(va);
 
-	if (CreateProcessA(NULL, cmd_line,
-                   NULL, NULL, true, 0, NULL, NULL,
-	                   &start_info, &pi)) {
-		WaitForSingleObject(pi.hProcess, INFINITE);
+	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	defer (gb_temp_arena_memory_end(tmp));
+
+	cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
 
+	if (CreateProcessW(NULL, cmd.text,
+	                   NULL, NULL, true, 0, NULL, NULL,
+	                   &start_info, &pi)) {
 		DWORD exit_code = 0;
+
+		WaitForSingleObject(pi.hProcess, INFINITE);
 		GetExitCodeProcess(pi.hProcess, &exit_code);
 
 		CloseHandle(pi.hProcess);
@@ -40,7 +49,7 @@ i32 win32_exec_command_line_app(char *fmt, ...) {
 	}
 }
 
-// #define DISPLAY_TIMING
+#define DISPLAY_TIMING
 #if defined(DISPLAY_TIMING)
 #define INIT_TIMER() f64 start_time = gb_time_now(), end_time = 0, total_time = 0
 #define PRINT_TIMER(section) do { \
@@ -62,23 +71,50 @@ i32 win32_exec_command_line_app(char *fmt, ...) {
 #endif
 
 
+enum ArchKind {
+	ArchKind_x64,
+	ArchKind_x86,
+};
+
+struct ArchData {
+	BaseTypeSizes sizes;
+	String llc_flags;
+	String link_flags;
+};
+
+ArchData make_arch_data(ArchKind kind) {
+	ArchData data = {};
+
+	switch (kind) {
+	case ArchKind_x64:
+	default:
+		data.sizes.word_size = 8;
+		data.sizes.max_align = 16;
+		data.llc_flags = make_string("-march=x86-64 ");
+		data.link_flags = make_string("/machine:x64 /defaultlib:libcmt ");
+		break;
+
+	case ArchKind_x86:
+		data.sizes.word_size = 4;
+		data.sizes.max_align = 8;
+		data.llc_flags = make_string("-march=x86 ");
+		data.link_flags = make_string("/machine:x86 /defaultlib:libcmt ");
+		break;
+	}
+
+	return data;
+}
+
+
 int main(int argc, char **argv) {
 	if (argc < 2) {
-		gb_printf_err("Please specify a .odin file\n");
+		gb_printf_err("using: %s [run] <filename> \n", argv[0]);
 		return 1;
 	}
-	char module_path_buf[300] = {};
-	String module_path = {};
-	module_path.text = cast(u8 *)module_path_buf;
-	module_path.len = GetModuleFileNameA(NULL, module_path_buf, gb_size_of(module_path_buf));
-	for (isize i = module_path.len-1; i >= 0; i--) {
-		u8 c = module_path.text[i];
-		if (c == '/' || c == '\\') {
-			break;
-		}
-		module_path.len--;
-	}
+	init_string_buffer_memory();
 
+	String module_dir = get_module_dir(gb_heap_allocator());
+	// defer (gb_free(gb_heap_allocator(), module_dir.text));
 
 	INIT_TIMER();
 
@@ -104,16 +140,11 @@ int main(int argc, char **argv) {
 
 	PRINT_TIMER("Syntax Parser");
 
-	// print_ast(parser.files[0].decls, 0);
-
 #if 1
 	Checker checker = {};
-	BaseTypeSizes sizes = {};
-	// NOTE(bill): x64
-	sizes.word_size = 8;
-	sizes.max_align = 16;
+	ArchData arch_data = make_arch_data(ArchKind_x64);
 
-	init_checker(&checker, &parser, sizes);
+	init_checker(&checker, &parser, arch_data.sizes);
 	// defer (destroy_checker(&checker));
 
 	check_parsed_files(&checker);
@@ -146,14 +177,14 @@ int main(int argc, char **argv) {
 	// For more passes arguments: http://llvm.org/docs/Passes.html
 	exit_code = win32_exec_command_line_app(
 		"%.*sbin/opt %s -o %.*s.bc "
-		"-memcpyopt "
 		"-mem2reg "
+		"-memcpyopt "
 		"-die -dse "
 		"-dce "
 		// "-S "
 		// "-debug-pass=Arguments "
 		"",
-		LIT(module_path),
+		LIT(module_dir),
 		output_name, LIT(output));
 	if (exit_code != 0) {
 		return exit_code;
@@ -164,10 +195,11 @@ int main(int argc, char **argv) {
 	// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
 	exit_code = win32_exec_command_line_app(
 		"%.*sbin/llc %.*s.bc -filetype=obj -O0 "
-		"-march=x86-64 "
+		"%.*s "
 		"",
-		LIT(module_path),
-		LIT(output));
+		LIT(module_dir),
+		LIT(output),
+		LIT(arch_data.llc_flags));
 	if (exit_code != 0) {
 		return exit_code;
 	}
@@ -183,13 +215,14 @@ int main(int argc, char **argv) {
 		                        " %.*s.lib", LIT(lib));
 		lib_str = gb_string_appendc(lib_str, lib_str_buf);
 	}
-	char *linker_flags = "-nologo -DEFAULTLIB:libcmt -machine:x64 -incremental:no -opt:ref -subsystem:console";
+	char *linker_flags =
+	"/nologo /incremental:no /opt:ref /subsystem:console";
 
 	exit_code = win32_exec_command_line_app(
-		"link %.*s.obj -OUT:%.*s.exe %s %s "
+		"link %.*s.obj -OUT:%.*s.exe %s %.*s %s"
 		"",
 		LIT(output), LIT(output),
-		lib_str, linker_flags);
+		lib_str, LIT(arch_data.link_flags), linker_flags);
 	if (exit_code != 0) {
 		return exit_code;
 	}

+ 79 - 45
src/parser.cpp

@@ -214,6 +214,16 @@ AST_NODE_KIND(_ComplexStmtBegin, "", struct{}) \
 		AstNode *clobber_list; \
 		isize output_count, input_count, clobber_count; \
 	}) \
+	AST_NODE_KIND(PushAllocator, "push_allocator statement", struct { \
+		Token token; \
+		AstNode *expr; \
+		AstNode *body; \
+	}) \
+	AST_NODE_KIND(PushContext, "push_context statement", struct { \
+		Token token; \
+		AstNode *expr; \
+		AstNode *body; \
+	}) \
 \
 AST_NODE_KIND(_ComplexStmtEnd, "", struct{}) \
 AST_NODE_KIND(_StmtEnd,        "", struct{}) \
@@ -414,6 +424,10 @@ Token ast_node_token(AstNode *node) {
 		return node->UsingStmt.token;
 	case AstNode_AsmStmt:
 		return node->AsmStmt.token;
+	case AstNode_PushAllocator:
+		return node->PushAllocator.token;
+	case AstNode_PushContext:
+		return node->PushContext.token;
 	case AstNode_BadDecl:
 		return node->BadDecl.begin;
 	case AstNode_VarDecl:
@@ -765,6 +779,21 @@ gb_inline AstNode *make_asm_stmt(AstFile *f, Token token, b32 is_volatile, Token
 	return result;
 }
 
+gb_inline AstNode *make_push_allocator(AstFile *f, Token token, AstNode *expr, AstNode *body) {
+	AstNode *result = make_node(f, AstNode_PushAllocator);
+	result->PushAllocator.token = token;
+	result->PushAllocator.expr = expr;
+	result->PushAllocator.body = body;
+	return result;
+}
+
+gb_inline AstNode *make_push_context(AstFile *f, Token token, AstNode *expr, AstNode *body) {
+	AstNode *result = make_node(f, AstNode_PushContext);
+	result->PushContext.token = token;
+	result->PushContext.expr = expr;
+	result->PushContext.body = body;
+	return result;
+}
 
 
 
@@ -996,34 +1025,24 @@ void fix_advance_to_next_stmt(AstFile *f) {
 }
 
 b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) {
-	// if (s != NULL) {
-	// 	switch (s->kind) {
-	// 	case AstNode_ProcDecl:
-	// 		return true;
-	// 	case AstNode_TypeDecl: {
-	// 		switch (s->TypeDecl.type->kind) {
-	// 		case AstNode_StructType:
-	// 		case AstNode_UnionType:
-	// 		case AstNode_EnumType:
-	// 		case AstNode_ProcType:
-	// 			return true;
-	// 		}
-	// 	} break;
-	// 	}
-	// }
+	if (allow_token(f, Token_Semicolon)) {
+		return true;
+	}
 
-	if (!allow_token(f, Token_Semicolon)) {
-		if (f->cursor[0].pos.line == f->cursor[-1].pos.line) {
-			if (f->cursor[0].kind != Token_CloseBrace) {
-				// CLEANUP(bill): Semicolon handling in parser
-				syntax_error(f->cursor[0],
-				             "Expected `;` after %.*s, got `%.*s`",
-				             LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
-				return false;
-			}
-		}
+	if (f->cursor[0].pos.line != f->cursor[-1].pos.line) {
+		return true;
 	}
-	return true;
+
+	switch (f->cursor[0].kind) {
+	case Token_EOF:
+	case Token_CloseBrace:
+		return true;
+	}
+
+	syntax_error(f->cursor[0],
+	             "Expected `;` after %.*s, got `%.*s`",
+	             LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
+	return false;
 }
 
 
@@ -2593,6 +2612,28 @@ AstNode *parse_stmt(AstFile *f) {
 		return make_using_stmt(f, token, node);
 	} break;
 
+	case Token_push_allocator: {
+		next_token(f);
+		isize prev_level = f->expr_level;
+		f->expr_level = -1;
+		AstNode *expr = parse_expr(f, false);
+		f->expr_level = prev_level;
+
+		AstNode *body = parse_block_stmt(f);
+		return make_push_allocator(f, token, expr, body);
+	} break;
+
+	case Token_push_context: {
+		next_token(f);
+		isize prev_level = f->expr_level;
+		f->expr_level = -1;
+		AstNode *expr = parse_expr(f, false);
+		f->expr_level = prev_level;
+
+		AstNode *body = parse_block_stmt(f);
+		return make_push_context(f, token, expr, body);
+	} break;
+
 	case Token_Hash: {
 		s = parse_tag_stmt(f, NULL);
 		String tag = s->TagStmt.name.string;
@@ -2706,10 +2747,8 @@ AstNodeArray parse_stmt_list(AstFile *f) {
 }
 
 
-
 ParseFileError init_ast_file(AstFile *f, String fullpath) {
 	if (!string_has_extension(fullpath, make_string("odin"))) {
-		// gb_printf_err("Only `.odin` files are allowed\n");
 		return ParseFile_WrongExtension;
 	}
 	TokenizerInitError err = init_tokenizer(&f->tokenizer, fullpath);
@@ -2809,34 +2848,29 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
 	gb_memcopy(str+i, base_dir.text, base_dir.len); i += base_dir.len;
 	gb_memcopy(str+i, path.text, path.len);
 	str[str_len] = '\0';
-	char *path_str = gb_path_get_full_name(a, cast(char *)str);
-	return make_string(path_str);
+	return path_to_fullpath(a, make_string(str, str_len));
 }
 
 String get_fullpath_core(gbAllocator a, String path) {
-	char buf[300] = {};
-	u32 buf_len = GetModuleFileNameA(GetModuleHandleA(NULL), buf, gb_size_of(buf));
-	for (isize i = buf_len-1; i >= 0; i--) {
-		if (buf[i] == '\\' ||
-		    buf[i] == '/') {
-			break;
-		}
-		buf_len--;
-	}
+	String module_dir = get_module_dir(gb_heap_allocator());
+	defer (if (module_dir.len > 0) {
+		gb_free(gb_heap_allocator(), module_dir.text);
+	});
 
 	char core[] = "core/";
 	isize core_len = gb_size_of(core)-1;
 
-	isize str_len = buf_len + core_len + path.len;
+	isize str_len = module_dir.len + core_len + path.len;
 	u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
 	defer (gb_free(gb_heap_allocator(), str));
 
-	gb_memcopy(str, buf, buf_len);
-	gb_memcopy(str+buf_len, core, core_len);
-	gb_memcopy(str+buf_len+core_len, path.text, path.len);
+	gb_memcopy(str, module_dir.text, module_dir.len);
+	gb_memcopy(str+module_dir.len, core, core_len);
+	gb_memcopy(str+module_dir.len+core_len, path.text, path.len);
 	str[str_len] = '\0';
-	char *path_str = gb_path_get_full_name(a, cast(char *)str);
-	return make_string(path_str);}
+
+	return path_to_fullpath(a, make_string(str, str_len));
+}
 
 // NOTE(bill): Returns true if it's added
 b32 try_add_foreign_system_library_path(Parser *p, String import_file) {

+ 91 - 1
src/string.cpp

@@ -1,13 +1,26 @@
+gb_global gbArena string_buffer_arena = {};
+gb_global gbAllocator string_buffer_allocator = {};
+
+void init_string_buffer_memory() {
+	// NOTE(bill): This should be enough memory for file systems
+	gb_arena_init_from_allocator(&string_buffer_arena, gb_heap_allocator(), gb_megabytes(1));
+	string_buffer_allocator = gb_arena_allocator(&string_buffer_arena);
+}
+
 
 // NOTE(bill): Used for UTF-8 strings
 typedef struct String {
-	u8 *text;
+	u8 *  text;
 	isize len;
 } String;
 // NOTE(bill): used for printf style arguments
 #define LIT(x) (x).len, (x).text
 
 
+typedef struct String16 {
+	wchar_t *text;
+	isize    len;
+} String16;
 
 
 gb_inline String make_string(u8 *text, isize len) {
@@ -20,6 +33,15 @@ gb_inline String make_string(u8 *text, isize len) {
 	return s;
 }
 
+
+gb_inline String16 make_string16(wchar_t *text, isize len) {
+	String16 s;
+	s.text = text;
+	s.len = len;
+	return s;
+}
+
+
 gb_inline String make_string(char *text) {
 	return make_string(cast(u8 *)cast(void *)text, gb_strlen(text));
 }
@@ -133,6 +155,74 @@ b32 string_contains_char(String s, u8 c) {
 	return false;
 }
 
+// TODO(bill): Make this non-windows specific
+String16 string_to_string16(gbAllocator a, String s) {
+	if (s.len < 1) {
+		return make_string16(NULL, 0);
+	}
+
+	int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+	                              cast(char *)s.text, s.len, NULL, 0);
+	if (len == 0) {
+		return make_string16(NULL, 0);
+	}
+
+	wchar_t *text = gb_alloc_array(a, wchar_t, len+1);
+
+	int len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+	                               cast(char *)s.text, s.len, text, len);
+	if (len1 == 0) {
+		gb_free(a, text);
+		return make_string16(NULL, 0);
+	}
+	text[len] = 0;
+
+	return make_string16(text, len-1);
+}
+
+String string16_to_string(gbAllocator a, String16 s) {
+	if (s.len < 1) {
+		return make_string(NULL, 0);
+	}
+
+	int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
+	                              s.text, s.len, NULL, 0,
+	                              NULL, NULL);
+	if (len == 0) {
+		return make_string(NULL, 0);
+	}
+
+	u8 *text = gb_alloc_array(a, u8, len+1);
+
+	int len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
+	                               s.text, s.len, cast(char *)text, len,
+	                               NULL, NULL);
+	if (len1 == 0) {
+		gb_free(a, text);
+		return make_string(NULL, 0);
+	}
+	text[len] = 0;
+
+	return make_string(text, len-1);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 b32 unquote_char(String s, u8 quote, Rune *rune, b32 *multiple_bytes, String *tail_string) {
 	if (s.text[0] == quote &&
 	    (quote == '$' || quote == '"')) {

+ 25 - 23
src/tokenizer.cpp

@@ -82,29 +82,31 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
 TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
-	TOKEN_KIND(Token_type,        "type"), \
-	TOKEN_KIND(Token_proc,        "proc"), \
-	TOKEN_KIND(Token_match,       "match"), \
-	TOKEN_KIND(Token_break,       "break"), \
-	TOKEN_KIND(Token_continue,    "continue"), \
-	TOKEN_KIND(Token_fallthrough, "fallthrough"), \
-	TOKEN_KIND(Token_case,        "case"), \
-	TOKEN_KIND(Token_default,     "default"), \
-	TOKEN_KIND(Token_then,        "then"), \
-	TOKEN_KIND(Token_if,          "if"), \
-	TOKEN_KIND(Token_else,        "else"), \
-	TOKEN_KIND(Token_for,         "for"), \
-	TOKEN_KIND(Token_range,       "range"), \
-	TOKEN_KIND(Token_defer,       "defer"), \
-	TOKEN_KIND(Token_return,      "return"), \
-	TOKEN_KIND(Token_struct,      "struct"), \
-	TOKEN_KIND(Token_union,       "union"), \
-	TOKEN_KIND(Token_raw_union,   "raw_union"), \
-	TOKEN_KIND(Token_enum,        "enum"), \
-	TOKEN_KIND(Token_using,       "using"), \
-	TOKEN_KIND(Token_asm,         "asm"), \
-	TOKEN_KIND(Token_volatile,    "volatile"), \
-	TOKEN_KIND(Token_atomic,      "atomic"), \
+	TOKEN_KIND(Token_type,           "type"), \
+	TOKEN_KIND(Token_proc,           "proc"), \
+	TOKEN_KIND(Token_match,          "match"), \
+	TOKEN_KIND(Token_break,          "break"), \
+	TOKEN_KIND(Token_continue,       "continue"), \
+	TOKEN_KIND(Token_fallthrough,    "fallthrough"), \
+	TOKEN_KIND(Token_case,           "case"), \
+	TOKEN_KIND(Token_default,        "default"), \
+	TOKEN_KIND(Token_then,           "then"), \
+	TOKEN_KIND(Token_if,             "if"), \
+	TOKEN_KIND(Token_else,           "else"), \
+	TOKEN_KIND(Token_for,            "for"), \
+	TOKEN_KIND(Token_range,          "range"), \
+	TOKEN_KIND(Token_defer,          "defer"), \
+	TOKEN_KIND(Token_return,         "return"), \
+	TOKEN_KIND(Token_struct,         "struct"), \
+	TOKEN_KIND(Token_union,          "union"), \
+	TOKEN_KIND(Token_raw_union,      "raw_union"), \
+	TOKEN_KIND(Token_enum,           "enum"), \
+	TOKEN_KIND(Token_using,          "using"), \
+	TOKEN_KIND(Token_asm,            "asm"), \
+	TOKEN_KIND(Token_volatile,       "volatile"), \
+	TOKEN_KIND(Token_atomic,         "atomic"), \
+	TOKEN_KIND(Token_push_allocator, "push_allocator"), \
+	TOKEN_KIND(Token_push_context,   "push_context"), \
 TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
 	TOKEN_KIND(Token_Count, "")