diff --git a/build.bat b/build.bat index c68f2e40d..3c7f8992a 100644 --- a/build.bat +++ b/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 diff --git a/code/demo.odin b/code/demo.odin index 4df748394..482733dc7 100644 --- a/code/demo.odin +++ b/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() // { diff --git a/code/test.odin b/code/test.odin index 8748ab3b5..76dbf0468 100644 --- a/code/test.odin +++ b/code/test.odin @@ -33,4 +33,3 @@ thing :: proc() { thing :: proc() { println("Hello5!") }*/ - diff --git a/core/runtime.odin b/core/runtime.odin index a23464e18..03e7ab203 100644 --- a/core/runtime.odin +++ b/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 "" } + + diff --git a/misc/shell.bat b/misc/shell.bat index d23f1b9bf..7d8dee6d6 100644 --- a/misc/shell.bat +++ b/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 diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index ea246dba0..e94482c34 100644 --- a/src/checker/checker.cpp +++ b/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); diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index c7f424315..f6670eb4d 100644 --- a/src/checker/expr.cpp +++ b/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); } diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 2c7b36848..04df70ffb 100644 --- a/src/checker/stmt.cpp +++ b/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; + + + diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 085e7c61e..24bab46ad 100644 --- a/src/checker/type.cpp +++ b/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 diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 4a4a7da46..e66d4fd03 100644 --- a/src/codegen/codegen.cpp +++ b/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); diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 313299552..9b90106df 100644 --- a/src/codegen/print_llvm.cpp +++ b/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); + } } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 66d00ed0f..f64da951c 100644 --- a/src/codegen/ssa.cpp +++ b/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; + + } } diff --git a/src/common.cpp b/src/common.cpp index bbad5b845..fb4223d9d 100644 --- a/src/common.cpp +++ b/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; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 7e0292a09..e120bff7a 100644 --- a/src/exact_value.cpp +++ b/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; } } diff --git a/src/gb/gb.h b/src/gb/gb.h index fb2681b34..542677fce 100644 --- a/src/gb/gb.h +++ b/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*/) { } diff --git a/src/main.cpp b/src/main.cpp index 1e0528863..60833a746 100644 --- a/src/main.cpp +++ b/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 -int main(int argc, char **argv) { - if (argc < 2) { - gb_printf_err("Please specify a .odin file\n"); - 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--; +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("using: %s [run] \n", argv[0]); + return 1; + } + 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; } diff --git a/src/parser.cpp b/src/parser.cpp index 0fcb7110a..01e310aa4 100644 --- a/src/parser.cpp +++ b/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)) { - 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 (allow_token(f, Token_Semicolon)) { + return true; } - return true; + + if (f->cursor[0].pos.line != f->cursor[-1].pos.line) { + 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) { diff --git a/src/string.cpp b/src/string.cpp index 3843fa676..6a08c5aa4 100644 --- a/src/string.cpp +++ b/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 == '"')) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 88fec813f..487ab004c 100644 --- a/src/tokenizer.cpp +++ b/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, "")