From 968de5aae886e87f395533283c17d77f31eabd0d Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Fri, 16 Sep 2016 11:38:20 +0100 Subject: [PATCH] Call expression, either handle all or ignore all results. --- code/demo.odin | 24 ++++++++++++---- code/game.odin | 8 +++--- code/runtime.odin | 44 ++++++++++++++++------------- code/win32.odin | 20 +++++++------ src/checker/checker.cpp | 4 ++- src/checker/entity.cpp | 11 +++++++- src/checker/expr.cpp | 48 ++++++++++++++++++------------- src/checker/stmt.cpp | 62 +++++++++++++++++++++++++++++++++-------- src/codegen/ssa.cpp | 46 +++++++++++++++++++++++++----- src/main.cpp | 8 +++--- src/parser.cpp | 37 +++++++++++++++++++++--- 11 files changed, 226 insertions(+), 86 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 4fca39f63..4909a3e72 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,16 +1,28 @@ -#import "runtime.odin" as _ -#import "punity.odin" as punity +#import "punity.odin" as pn +#import "fmt.odin" as fmt +test :: proc() { + thing :: proc() { + thing :: proc() { + fmt.println("Hello1") + } + fmt.println("Hello") + } +} main :: proc() { - init :: proc() { + test() + + init :: proc(c: ^pn.Core) { } - step :: proc() { - + step :: proc(c: ^pn.Core) { + if pn.key_down(pn.Key.ESCAPE) { + c.running = false + } } - punity.run(init, step) + pn.run(init, step) } diff --git a/code/game.odin b/code/game.odin index 2b56cb64e..dfa05750b 100644 --- a/code/game.odin +++ b/code/game.odin @@ -10,7 +10,7 @@ time_now :: proc() -> f64 { assert(win32_perf_count_freq != 0) counter: i64 - _ = win32.QueryPerformanceCounter(^counter) + win32.QueryPerformanceCounter(^counter) result := counter as f64 / win32_perf_count_freq as f64 return result } @@ -24,7 +24,7 @@ win32_print_last_error :: proc() { // Yuk! to_c_string :: proc(s: string) -> []u8 { c_str := new_slice(u8, s.count+1) - _ = copy(c_str, s as []byte) + copy(c_str, s as []byte) c_str[s.count] = 0 return c_str } @@ -157,8 +157,8 @@ run :: proc() { if msg.message == WM_QUIT { running = false } - _ = TranslateMessage(^msg) - _ = DispatchMessageA(^msg) + TranslateMessage(^msg) + DispatchMessageA(^msg) } if is_key_down(Key_Code.ESCAPE) { diff --git a/code/runtime.odin b/code/runtime.odin index 1d293b5f7..b0320beec 100644 --- a/code/runtime.odin +++ b/code/runtime.odin @@ -1,10 +1,5 @@ #shared_global_scope -// TODO(bill): Create a standard library "location" so I don't have to manually import "runtime.odin" -#import "win32.odin" as win32 -#import "os.odin" as os -#import "fmt.odin" as fmt - // IMPORTANT NOTE(bill): Do not change the order of any of this data // The compiler relies upon this _exact_ order Type_Info :: union { @@ -80,20 +75,22 @@ byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16" byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32" byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" -fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" -fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" +fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" +fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" -heap_alloc :: proc(len: int) -> rawptr { - return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, len) +heap_alloc :: proc(len: int) -> rawptr { + c_malloc :: proc(len: int) -> rawptr #foreign "malloc" + return c_malloc(len) } heap_free :: proc(ptr: rawptr) { - _ = win32.HeapFree(win32.GetProcessHeap(), 0, ptr) + c_free :: proc(ptr: rawptr) #foreign "free" + c_free(ptr) } current_thread_id :: proc() -> int { - id := win32.GetCurrentThreadId() - return id as int + GetCurrentThreadId :: proc() -> u32 #foreign #dll_import + return GetCurrentThreadId() as int } memory_zero :: proc(data: rawptr, len: int) { @@ -168,10 +165,16 @@ __string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > __string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 } __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 } +__print_err_str :: proc(s: string) { +} +__print_err_int :: proc(i: int) { + +} __assert :: proc(msg: string) { - _ = os.write(os.get_standard_file(os.File_Standard.ERROR), msg as []byte) + // TODO(bill): Write message + __print_err_str(msg) __debug_trap() } @@ -180,9 +183,10 @@ __bounds_check_error :: proc(file: string, line, column: int, if 0 <= index && index < count { return } + // TODO(bill): Write message // TODO(bill): Probably reduce the need for `print` in the runtime if possible - fmt.println_err("%(%:%) Index % is out of bounds range [0, %)", - file, line, column, index, count) + // fmt.println_err("%(%:%) Index % is out of bounds range [0, %)", + // file, line, column, index, count) __debug_trap() } @@ -191,8 +195,9 @@ __slice_expr_error :: proc(file: string, line, column: int, if 0 <= low && low <= high && high <= max { return } - fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]", - file, line, column, low, high, max) + // TODO(bill): Write message + // fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]", + // file, line, column, low, high, max) __debug_trap() } __substring_expr_error :: proc(file: string, line, column: int, @@ -200,8 +205,9 @@ __substring_expr_error :: proc(file: string, line, column: int, if 0 <= low && low <= high { return } - fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]", - file, line, column, low, high) + // TODO(bill): Write message + // fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]", + // file, line, column, low, high) __debug_trap() } diff --git a/code/win32.odin b/code/win32.odin index de67784d3..0ccc934aa 100644 --- a/code/win32.odin +++ b/code/win32.odin @@ -83,14 +83,15 @@ RECT :: struct #ordered { } -GetLastError :: proc() -> i32 #foreign #dll_import -ExitProcess :: proc(exit_code: u32) #foreign #dll_import -GetDesktopWindow :: proc() -> HWND #foreign #dll_import -GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import -ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import -GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import -GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import -PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import +GetLastError :: proc() -> i32 #foreign #dll_import +ExitProcess :: proc(exit_code: u32) #foreign #dll_import +GetDesktopWindow :: proc() -> HWND #foreign #dll_import +GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import +ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import +GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import +GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import +PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import +SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import @@ -122,7 +123,7 @@ AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign # GetQueryPerformanceFrequency :: proc() -> i64 { r: i64 - _ = QueryPerformanceFrequency(^r) + QueryPerformanceFrequency(^r) return r } @@ -287,6 +288,7 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import +GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import is_key_down :: proc(key: Key_Code) -> bool { diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index bf0454668..f6fb6a381 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -1034,7 +1034,9 @@ void check_parsed_files(Checker *c) { Entity *e = scope->elements.entries[elem_index].value; // NOTE(bill): Do not add other imported entities if (e->scope == scope && e->kind != Entity_ImportName) { - add_entity(c, file_scope, NULL, e); + if (is_entity_exported(e)) { + add_entity(c, file_scope, NULL, e); + } } } } else { diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index 3814f38f0..3a4ffb191 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -51,7 +51,7 @@ struct Entity { b8 is_field; // Is struct field } Variable; struct { - struct DeclInfo *decl; // Usually NULL + // struct DeclInfo *decl; // Usually NULL } TypeName; struct { b8 pure; @@ -66,6 +66,15 @@ struct Entity { }; }; +b32 is_entity_exported(Entity *e) { + // TODO(bill): Do I really want non-exported entities? + // if (e->token.string.len >= 1 && + // e->token.string.text[0] == '_') { + // return false; + // } + return true; +} + gb_global gbAtomic64 entity_guid_counter = {0}; EntityGuid next_entity_guid(void) { diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 982c28942..8b207b373 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -835,27 +835,28 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl } i64 check_array_count(Checker *c, AstNode *e) { - if (e) { - Operand o = {}; - check_expr(c, &o, e); - if (o.mode != Addressing_Constant) { - if (o.mode != Addressing_Invalid) { - error(&c->error_collector, ast_node_token(e), "Array count must be a constant"); - } + if (e == NULL) { + return 0; + } + Operand o = {}; + check_expr(c, &o, e); + if (o.mode != Addressing_Constant) { + if (o.mode != Addressing_Invalid) { + error(&c->error_collector, ast_node_token(e), "Array count must be a constant"); + } + return 0; + } + if (is_type_untyped(o.type) || is_type_integer(o.type)) { + if (o.value.kind == ExactValue_Integer) { + i64 count = o.value.value_integer; + if (count >= 0) + return count; + error(&c->error_collector, ast_node_token(e), "Invalid array count"); return 0; } - if (is_type_untyped(o.type) || is_type_integer(o.type)) { - if (o.value.kind == ExactValue_Integer) { - i64 count = o.value.value_integer; - if (count >= 0) - return count; - error(&c->error_collector, ast_node_token(e), "Invalid array count"); - return 0; - } - } - - error(&c->error_collector, ast_node_token(e), "Array count must be an integer"); } + + error(&c->error_collector, ast_node_token(e), "Array count must be an integer"); return 0; } @@ -2001,17 +2002,24 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { if (e != NULL && e->kind == Entity_ImportName) { check_op_expr = false; entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string); - add_entity_use(&c->info, selector, entity); if (entity == NULL) { gbString sel_str = expr_to_string(selector); defer (gb_string_free(sel_str)); - error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared in `%.*s`", sel_str, LIT(name)); + error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared by `%.*s`", sel_str, LIT(name)); goto error; } if (entity->type == NULL) { // Not setup yet check_entity_decl(c, entity, NULL, NULL); } GB_ASSERT(entity->type != NULL); + if (!is_entity_exported(entity)) { + gbString sel_str = expr_to_string(selector); + defer (gb_string_free(sel_str)); + error(&c->error_collector, ast_node_token(op_expr), "`%s` is not exported by `%.*s`", sel_str, LIT(name)); + // NOTE(bill): Not really an error so don't goto error + } + + add_entity_use(&c->info, selector, entity); } } if (check_op_expr) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 1f57519e0..cf040c223 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -8,6 +8,7 @@ enum StmtFlag : u32 { void check_stmt(Checker *c, AstNode *node, u32 flags); +void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later); void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0; @@ -437,6 +438,44 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod check_scope_usage(c, c->context.scope); } +b32 are_signatures_similar_enough(Type *a_, Type *b_) { + GB_ASSERT(a_->kind == Type_Proc); + GB_ASSERT(b_->kind == Type_Proc); + auto *a = &a_->Proc; + auto *b = &b_->Proc; + + if (a->param_count != b->param_count) { + return false; + } + if (a->result_count != b->result_count) { + return false; + } + for (isize i = 0; i < a->param_count; i++) { + Type *x = get_base_type(a->params->Tuple.variables[i]->type); + Type *y = get_base_type(b->params->Tuple.variables[i]->type); + if (is_type_pointer(x) && is_type_pointer(y)) { + continue; + } + + if (!are_types_identical(x, y)) { + return false; + } + } + for (isize i = 0; i < a->result_count; i++) { + Type *x = get_base_type(a->results->Tuple.variables[i]->type); + Type *y = get_base_type(b->results->Tuple.variables[i]->type); + if (is_type_pointer(x) && is_type_pointer(y)) { + continue; + } + + if (!are_types_identical(x, y)) { + return false; + } + } + + return true; +} + void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { GB_ASSERT(e->type == NULL); @@ -446,13 +485,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { check_open_scope(c, pd->type); defer (check_close_scope(c)); check_procedure_type(c, proc_type, pd->type); - // add_proc_entity(c, d->scope, pd->name, e); - if (d->scope->is_proc) { - // Nested procedures - add_entity(c, d->scope->parent, pd->name, e); - } - - b32 is_foreign = (pd->tags & ProcTag_foreign) != 0; @@ -460,8 +492,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0; - - if (d->scope == c->global_scope && + if ((d->scope->is_file || d->scope->is_global) && are_strings_equal(e->token.string, make_string("main"))) { if (proc_type != NULL) { auto *pt = &proc_type->Proc; @@ -511,7 +542,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { TokenPos pos = f->token.pos; Type *this_type = get_base_type(e->type); Type *other_type = get_base_type(f->type); - if (!are_types_identical(this_type, other_type)) { + if (!are_signatures_similar_enough(this_type, other_type)) { error(&c->error_collector, ast_node_token(d->proc_decl), "Redeclaration of #foreign procedure `%.*s` with different type signatures\n" "\tat %.*s(%td:%td)", @@ -577,7 +608,10 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc } } - c->context.decl = d; + // c->context.decl = d; + // Scope *prev = c->context.scope; + // c->context.scope = d->scope; + // defer (c->context.scope = prev); if (e->kind == Entity_Procedure) { check_proc_decl(c, e, d, true); @@ -759,6 +793,12 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { default: { gbString expr_str = expr_to_string(operand.expr); defer (gb_string_free(expr_str)); + if (kind == Expr_Stmt) { + return; + } + if (operand.expr->kind == AstNode_CallExpr) { + return; + } error(&c->error_collector, ast_node_token(node), "Expression is not used: `%s`", expr_str); } break; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index bcbe35634..f1c888fa7 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -2535,6 +2535,23 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { } Entity *e = entity_of_ident(proc->module->info, expr); + + if (e->kind == Entity_Constant) { + if (get_base_type(e->type) == t_string) { + // HACK TODO(bill): This is lazy but it works + String str = e->Constant.value.value_string; + ssaValue *global_array = ssa_add_global_string_array(proc->module, str); + ssaValue *elem = ssa_array_elem(proc, global_array); + ssaValue *len = ssa_make_const_int(proc->module->allocator, str.len); + ssaValue *v = ssa_add_local_generated(proc, e->type); + ssaValue *str_elem = ssa_emit_struct_gep(proc, v, v_zero32, ssa_type(elem)); + ssaValue *str_len = ssa_emit_struct_gep(proc, v, v_one32, t_int); + ssa_emit_store(proc, str_elem, elem); + ssa_emit_store(proc, str_len, len); + return ssa_make_addr(v, expr); + } + } + ssaValue *v = NULL; ssaValue **found = map_get(&proc->module->values, hash_pointer(e)); if (found) { @@ -2555,20 +2572,35 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { case_ast_node(se, SelectorExpr, expr); ssa_emit_comment(proc, make_string("SelectorExpr")); - Type *type = get_base_type(type_of_expr(proc->module->info, se->expr)); String selector = unparen_expr(se->selector)->Ident.string; + Type *type = get_base_type(type_of_expr(proc->module->info, se->expr)); + + if (type == t_invalid) { + // Imports Entity *imp = entity_of_ident(proc->module->info, se->expr); - GB_ASSERT(imp->kind == Entity_ImportName); - // Entity *e = scope_lookup_entity(e->ImportName.scope, selector); + if (imp != NULL) { + GB_ASSERT(imp->kind == Entity_ImportName); + } return ssa_build_addr(proc, unparen_expr(se->selector)); - } else { + } /* else if (type == t_string) { Selection sel = lookup_field(type, selector, false); GB_ASSERT(sel.entity != NULL); - ssaValue *e = ssa_build_addr(proc, se->expr).addr; - e = ssa_emit_deep_field_gep(proc, type, e, sel); - return ssa_make_addr(e, expr); + // NOTE(bill): This could a constant and the only non constant + // selector is the `.data`, so build the expression instead + ssaValue *e = ssa_build_expr(proc, se->expr); + ssaValue *a = ssa_build_addr(proc, se->expr).addr; + + a = ssa_emit_deep_field_gep(proc, type, a, sel); + return ssa_make_addr(a, expr); + } */else { + Selection sel = lookup_field(type, selector, false); + GB_ASSERT(sel.entity != NULL); + + ssaValue *a = ssa_build_addr(proc, se->expr).addr; + a = ssa_emit_deep_field_gep(proc, type, a, sel); + return ssa_make_addr(a, expr); } case_end; diff --git a/src/main.cpp b/src/main.cpp index a0984cbd7..578b59121 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,10 +128,10 @@ int main(int argc, char **argv) { exit_code = win32_exec_command_line_app( // "../misc/llvm-bin/opt %s -o %.*s.bc " "opt %s -o %.*s.bc " - // "-memcpyopt " - // "-mem2reg " - // "-die -dse " - // "-dce " + "-memcpyopt " + "-mem2reg " + "-die -dse " + "-dce " // "-S " // "-debug-pass=Arguments " "", diff --git a/src/parser.cpp b/src/parser.cpp index 9ecce6778..61c4b397a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -45,6 +45,7 @@ struct AstFile { struct ImportedFile { String path; + String rel_path; TokenPos pos; // #import }; @@ -2736,7 +2737,7 @@ void destroy_parser(Parser *p) { } // NOTE(bill): Returns true if it's added -b32 try_add_import_path(Parser *p, String path, TokenPos pos) { +b32 try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) { gb_for_array(i, p->imports) { String import = p->imports[i].path; if (are_strings_equal(import, path)) { @@ -2746,6 +2747,7 @@ b32 try_add_import_path(Parser *p, String path, TokenPos pos) { ImportedFile item; item.path = path; + item.rel_path = rel_path; item.pos = pos; gb_array_append(p->imports, item); return true; @@ -2807,8 +2809,10 @@ void parse_file(Parser *p, AstFile *f) { String filepath = f->tokenizer.fullpath; String base_dir = filepath; for (isize i = filepath.len-1; i >= 0; i--) { - if (base_dir.text[i] == GB_PATH_SEPARATOR) + if (base_dir.text[i] == '\\' || + base_dir.text[i] == '/') { break; + } base_dir.len--; } @@ -2843,7 +2847,7 @@ void parse_file(Parser *p, AstFile *f) { String import_file = make_string(path_str); id->fullpath = import_file; - if (!try_add_import_path(p, import_file, ast_node_token(node).pos)) { + if (!try_add_import_path(p, import_file, file_str, ast_node_token(node).pos)) { // gb_free(gb_heap_allocator(), import_file.text); } } else if (node->kind == AstNode_ForeignSystemLibrary) { @@ -2866,15 +2870,40 @@ ParseFileError parse_files(Parser *p, char *init_filename) { char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename); String init_fullpath = make_string(fullpath_str); TokenPos init_pos = {}; - ImportedFile init_imported_file = {init_fullpath, init_pos}; + ImportedFile init_imported_file = {init_fullpath, init_fullpath, init_pos}; gb_array_append(p->imports, init_imported_file); p->init_fullpath = init_fullpath; + // { + // // IMPORTANT TODO(bill): Don't embed this, do it relative to the .exe + // char *path = gb_path_get_full_name(gb_heap_allocator(), "W:/Odin/core/__runtime.odin"); + // String s = make_string(path); + // ImportedFile runtime_file = {s, s, init_pos}; + // gb_array_append(p->imports, runtime_file); + // } + gb_for_array(i, p->imports) { String import_path = p->imports[i].path; + String import_rel_path = p->imports[i].rel_path; TokenPos pos = p->imports[i].pos; AstFile file = {}; ParseFileError err = init_ast_file(&file, import_path); + + // if (err == ParseFile_NotFound) { + // // HACK(bill): Check core directory + // char buf[300] = {}; + // char core[] = "W:/Odin/core/"; + // isize len = gb_size_of(core)-1; + // gb_memcopy(buf, core, len); + // gb_memcopy(buf+len, import_rel_path.text, import_rel_path.len); + // char *path = gb_path_get_full_name(gb_heap_allocator(), buf); + // gb_printf_err("%s\n", path); + + // import_path = make_string(path); + // err = init_ast_file(&file, import_path); + // p->imports[i].path = import_path; + // } + if (err != ParseFile_None) { if (pos.line != 0) { gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column);