From 291bf0c143081c5b3e577f6a6fbf90781de95096 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Mar 2019 23:25:55 +0000 Subject: [PATCH 01/18] Fix #raw_union bug caused by typo #349 --- src/ir_print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 97194e794..53c318e47 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -471,7 +471,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { i64 align_of_union = type_align_of(t); ir_write_byte(f, '{'); ir_print_alignment_prefix_hack(f, align_of_union); - ir_fprintf(f, ", [%lld x i8]}", align_of_union, size_of_union); + ir_fprintf(f, ", [%lld x i8]}", size_of_union); return; } else { if (t->Struct.is_packed) { From dbcd49acfc853d136935605222e5c824b621dbd9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Mar 2019 23:26:32 +0000 Subject: [PATCH 02/18] Add -pdb-name for custom names of PDBs --- core/sys/win32/kernel32.odin | 21 +++++-- src/build_settings.cpp | 1 + src/main.cpp | 103 ++++++++++++++++++++++++----------- 3 files changed, 86 insertions(+), 39 deletions(-) diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin index 33ef0e8b7..479e116a0 100644 --- a/core/sys/win32/kernel32.odin +++ b/core/sys/win32/kernel32.odin @@ -18,8 +18,12 @@ foreign kernel32 { process_information: ^Process_Information) -> Bool ---; @(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---; @(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---; - @(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hinstance ---; - @(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hinstance ---; + @(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hmodule ---; + @(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hmodule ---; + + @(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---; + @(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---; + @(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---; @(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---; @(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---; @@ -54,10 +58,6 @@ foreign kernel32 { @(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---; @(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---; - @(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---; - @(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---; - @(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; - @(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; @(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---; @(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---; @@ -117,6 +117,15 @@ foreign kernel32 { @(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---; } +@(default_calling_convention = "c") +foreign kernel32 { + @(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---; + @(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---; + @(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; + @(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; + @(link_name="CompareFileTime") compare_file_time :: proc(a, b: ^Filetime) -> i32 ---; +} + @(default_calling_convention = "c") foreign kernel32 { @(link_name="InterlockedCompareExchange") interlocked_compare_exchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 ---; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d7b85644d..2b8f99e4c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -92,6 +92,7 @@ struct BuildContext { String out_filepath; String resource_filepath; + String pdb_filepath; bool has_resource; String opt_flags; String llc_flags; diff --git a/src/main.cpp b/src/main.cpp index beda80cad..83397fa48 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,7 @@ #include "ir_print.cpp" // NOTE(bill): 'name' is used in debugging and profiling modes -i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) { +i32 system_exec_command_line_app(char *name, char *fmt, ...) { #if defined(GB_SYSTEM_WINDOWS) STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)}; PROCESS_INFORMATION pi = {0}; @@ -201,7 +201,6 @@ enum BuildFlagKind { BuildFlag_Invalid, BuildFlag_OutFile, - BuildFlag_ResourceFile, BuildFlag_OptimizationLevel, BuildFlag_ShowTimings, BuildFlag_ThreadCount, @@ -218,6 +217,11 @@ enum BuildFlagKind { BuildFlag_Vet, BuildFlag_IgnoreUnknownAttributes, +#if defined(GB_SYSTEM_WINDOWS) + BuildFlag_ResourceFile, + BuildFlag_WindowsPdbName, +#endif + BuildFlag_COUNT, }; @@ -281,7 +285,6 @@ ExactValue build_param_to_exact_value(String name, String param) { bool parse_build_flags(Array args) { auto build_flags = array_make(heap_allocator(), 0, BuildFlag_COUNT); add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String); - add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer); add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer); @@ -298,6 +301,11 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("-ignore-unknown-attributes"), BuildFlagParam_None); +#if defined(GB_SYSTEM_WINDOWS) + add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String); + add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"), BuildFlagParam_String); +#endif + GB_ASSERT(args.count >= 3); Array flag_args = array_slice(args, 3, args.count); @@ -436,24 +444,6 @@ bool parse_build_flags(Array args) { } break; } - case BuildFlag_ResourceFile: { - GB_ASSERT(value.kind == ExactValue_String); - String path = value.value_string; - path = string_trim_whitespace(path); - if (is_import_path_valid(path)) { - if(!string_ends_with(path, str_lit(".rc"))) { - gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); - bad_flags = true; - break; - } - build_context.resource_filepath = substring(path, 0, string_extension_position(path)); - build_context.has_resource = true; - } else { - gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path)); - bad_flags = true; - } - break; - } case BuildFlag_OptimizationLevel: GB_ASSERT(value.kind == ExactValue_Integer); build_context.optimization_level = cast(i32)big_int_to_i64(&value.value_integer); @@ -671,6 +661,48 @@ bool parse_build_flags(Array args) { case BuildFlag_IgnoreUnknownAttributes: build_context.ignore_unknown_attributes = true; break; + + #if defined(GB_SYSTEM_WINDOWS) + case BuildFlag_ResourceFile: { + GB_ASSERT(value.kind == ExactValue_String); + String path = value.value_string; + path = string_trim_whitespace(path); + if (is_import_path_valid(path)) { + if(!string_ends_with(path, str_lit(".rc"))) { + gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); + bad_flags = true; + break; + } + build_context.resource_filepath = substring(path, 0, string_extension_position(path)); + build_context.has_resource = true; + } else { + gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path)); + bad_flags = true; + } + break; + } + case BuildFlag_WindowsPdbName: { + GB_ASSERT(value.kind == ExactValue_String); + String path = value.value_string; + path = string_trim_whitespace(path); + if (is_import_path_valid(path)) { + // #if defined(GB_SYSTEM_WINDOWS) + // String ext = path_extension(path); + // if (ext != ".pdb") { + // path = substring(path, 0, string_extension_position(path)); + // } + // #endif + build_context.pdb_filepath = path; + } else { + gb_printf_err("Invalid -pdb-name path, got %.*s\n", LIT(path)); + bad_flags = true; + } + break; + + break; + } + #endif + } } @@ -784,7 +816,7 @@ void remove_temp_files(String output_base) { i32 exec_llvm_opt(String output_base) { #if defined(GB_SYSTEM_WINDOWS) // For more passes arguments: http://llvm.org/docs/Passes.html - return system_exec_command_line_app("llvm-opt", false, + return system_exec_command_line_app("llvm-opt", "\"%.*sbin/opt\" \"%.*s.ll\" -o \"%.*s.bc\" %.*s " "", LIT(build_context.ODIN_ROOT), @@ -804,10 +836,10 @@ i32 exec_llvm_opt(String output_base) { i32 exec_llvm_llc(String output_base) { #if defined(GB_SYSTEM_WINDOWS) // For more arguments: http://llvm.org/docs/CommandGuide/llc.html - return system_exec_command_line_app("llvm-llc", false, + return system_exec_command_line_app("llvm-llc", "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d " "-o \"%.*s.obj\" " - "%.*s " + "%.*s" "", LIT(build_context.ODIN_ROOT), LIT(output_base), @@ -817,7 +849,7 @@ i32 exec_llvm_llc(String output_base) { #else // NOTE(zangent): Linux / Unix is unfinished and not tested very well. // For more arguments: http://llvm.org/docs/CommandGuide/llc.html - return system_exec_command_line_app("llc", false, + return system_exec_command_line_app("llc", "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " "%.*s " "%s" @@ -1041,6 +1073,11 @@ int main(int arg_count, char **arg_ptr) { } else { link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); } + + if (build_context.pdb_filepath != "") { + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + } + if (build_context.no_crt) { link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); } else { @@ -1052,7 +1089,7 @@ int main(int arg_count, char **arg_ptr) { } if (!build_context.use_lld) { // msvc if (build_context.has_resource) { - exit_code = system_exec_command_line_app("msvc-link", true, + exit_code = system_exec_command_line_app("msvc-link", "rc /nologo /fo \"%.*s.res\" \"%.*s.rc\"", LIT(output_base), LIT(build_context.resource_filepath) @@ -1062,7 +1099,7 @@ int main(int arg_count, char **arg_ptr) { return exit_code; } - exit_code = system_exec_command_line_app("msvc-link", true, + exit_code = system_exec_command_line_app("msvc-link", "link \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:CONSOLE " " %.*s " @@ -1073,7 +1110,7 @@ int main(int arg_count, char **arg_ptr) { link_settings ); } else { - exit_code = system_exec_command_line_app("msvc-link", true, + exit_code = system_exec_command_line_app("msvc-link", "link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:CONSOLE " " %.*s " @@ -1085,7 +1122,7 @@ int main(int arg_count, char **arg_ptr) { ); } } else { // lld - exit_code = system_exec_command_line_app("msvc-link", true, + exit_code = system_exec_command_line_app("msvc-link", "\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:CONSOLE " " %.*s " @@ -1109,7 +1146,7 @@ int main(int arg_count, char **arg_ptr) { remove_temp_files(output_base); if (run_output) { - system_exec_command_line_app("odin run", false, "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); + system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); } #else timings_start_section(&timings, str_lit("ld-link")); @@ -1206,7 +1243,7 @@ int main(int arg_count, char **arg_ptr) { } #endif - exit_code = system_exec_command_line_app("ld-link", true, + exit_code = system_exec_command_line_app("ld-link", "%s \"%.*s.o\" -o \"%.*s%.*s\" %s " " %s " " %.*s " @@ -1235,7 +1272,7 @@ int main(int arg_count, char **arg_ptr) { if (build_context.ODIN_DEBUG) { // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe // to the symbols in the object file - exit_code = system_exec_command_line_app("dsymutil", true, + exit_code = system_exec_command_line_app("dsymutil", "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) ); @@ -1256,7 +1293,7 @@ int main(int arg_count, char **arg_ptr) { //NOTE(thebirk): This whole thing is a little leaky String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); complete_path = path_to_full_path(heap_allocator(), complete_path); - system_exec_command_line_app("odin run", false, "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); } #endif #endif From 712744ef367045f21c017137ad1856dca8814e7b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Mar 2019 23:41:48 +0000 Subject: [PATCH 03/18] Fix `ir_copy_value_to_ptr` usage in `ir_emit_call` #350 --- src/ir.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 0d5e3fc36..0d9a165cf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2875,12 +2875,12 @@ irValue *ir_copy_value_to_ptr(irProcedure *proc, irValue *val, Type *new_type, i if (alignment < type_alignment) { alignment = type_alignment; } + GB_ASSERT_MSG(are_types_identical(new_type, ir_type(val)), "%s %s", type_to_string(new_type), type_to_string(ir_type(val))); + irValue *ptr = ir_add_local_generated(proc, new_type, false); ptr->Instr.Local.alignment = alignment; ir_emit_store(proc, ptr, val); - if (val) val->uses += 1; - return ptr; } @@ -2972,12 +2972,18 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro Type *original_type = e->type; Type *new_type = pt->Proc.abi_compat_params[i]; - if (original_type != new_type) { + if (!are_types_identical(original_type, new_type)) { + Type *arg_type = ir_type(args[i]); + if (is_type_pointer(new_type)) { if (e->flags&EntityFlag_Value) { args[i] = ir_address_from_load_or_generate_local(p, args[i]); } else { - args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); + if (is_type_pointer(arg_type)) { + args[i] = ir_copy_value_to_ptr(p, ir_emit_load(p, args[i]), original_type, 16); + } else { + args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); + } } } else if (is_type_integer(new_type)) { args[i] = ir_emit_transmute(p, args[i], new_type); From 61b07335d86a5f48475d496a14f23185964633ed Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 15 Mar 2019 07:37:20 +0100 Subject: [PATCH 04/18] Fix build error on !Windows. --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 83397fa48..4d5384a56 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -825,7 +825,7 @@ i32 exec_llvm_opt(String output_base) { #else // NOTE(zangent): This is separate because it seems that LLVM tools are packaged // with the Windows version, while they will be system-provided on MacOS and GNU/Linux - return system_exec_command_line_app("llvm-opt", false, + return system_exec_command_line_app("llvm-opt", "opt \"%.*s.ll\" -o \"%.*s.bc\" %.*s " "", LIT(output_base), LIT(output_base), From 3d86fc2f2f4577c5eb708f7519d7f908a1d9d5bc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 15:41:06 +0000 Subject: [PATCH 05/18] Minor adjustments --- src/ir.cpp | 4 ++-- src/main.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 0d9a165cf..6d44282be 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2975,12 +2975,12 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro if (!are_types_identical(original_type, new_type)) { Type *arg_type = ir_type(args[i]); - if (is_type_pointer(new_type)) { + if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { if (e->flags&EntityFlag_Value) { args[i] = ir_address_from_load_or_generate_local(p, args[i]); } else { if (is_type_pointer(arg_type)) { - args[i] = ir_copy_value_to_ptr(p, ir_emit_load(p, args[i]), original_type, 16); + // args[i] = ir_copy_value_to_ptr(p, ir_emit_load(p, args[i]), original_type, 16); } else { args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); } diff --git a/src/main.cpp b/src/main.cpp index 83397fa48..b73d9585f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -299,7 +299,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None); - add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("-ignore-unknown-attributes"), BuildFlagParam_None); + add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None); #if defined(GB_SYSTEM_WINDOWS) add_flag(&build_flags, BuildFlag_ResourceFile, str_lit("resource"), BuildFlagParam_String); From 885c5dc8b75dd88d376627195a5468d12264bcc5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 16:39:49 +0000 Subject: [PATCH 06/18] Fix issue with `deferred_*` attributes --- src/checker.cpp | 8 ++++---- src/ir.cpp | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 0253bc86b..8e8afc621 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2005,7 +2005,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (value != nullptr) { Operand o = {}; check_expr(c, &o, value); - Entity *e = entity_of_ident(o.expr); + Entity *e = entity_of_node(o.expr); if (e != nullptr && e->kind == Entity_Procedure) { warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name)); if (ac->deferred_procedure.entity != nullptr) { @@ -2022,7 +2022,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (value != nullptr) { Operand o = {}; check_expr(c, &o, value); - Entity *e = entity_of_ident(o.expr); + Entity *e = entity_of_node(o.expr); if (e != nullptr && e->kind == Entity_Procedure) { ac->deferred_procedure.kind = DeferredProcedure_none; ac->deferred_procedure.entity = e; @@ -2035,7 +2035,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (value != nullptr) { Operand o = {}; check_expr(c, &o, value); - Entity *e = entity_of_ident(o.expr); + Entity *e = entity_of_node(o.expr); if (e != nullptr && e->kind == Entity_Procedure) { if (ac->deferred_procedure.entity != nullptr) { error(elem, "Previous usage of a 'deferred_*' attribute"); @@ -2051,7 +2051,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (value != nullptr) { Operand o = {}; check_expr(c, &o, value); - Entity *e = entity_of_ident(o.expr); + Entity *e = entity_of_node(o.expr); if (e != nullptr && e->kind == Entity_Procedure) { if (ac->deferred_procedure.entity != nullptr) { error(elem, "Previous usage of a 'deferred_*' attribute"); diff --git a/src/ir.cpp b/src/ir.cpp index 6d44282be..6631711b5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2972,18 +2972,16 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro Type *original_type = e->type; Type *new_type = pt->Proc.abi_compat_params[i]; - if (!are_types_identical(original_type, new_type)) { - Type *arg_type = ir_type(args[i]); + Type *arg_type = ir_type(args[i]); + if (are_types_identical(arg_type, new_type)) { + // NOTE(bill): Done + } else if (!are_types_identical(original_type, new_type)) { if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { if (e->flags&EntityFlag_Value) { args[i] = ir_address_from_load_or_generate_local(p, args[i]); - } else { - if (is_type_pointer(arg_type)) { - // args[i] = ir_copy_value_to_ptr(p, ir_emit_load(p, args[i]), original_type, 16); - } else { - args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); - } + } else if (!is_type_pointer(arg_type)) { + args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); } } else if (is_type_integer(new_type)) { args[i] = ir_emit_transmute(p, args[i], new_type); From fdb60b2d511f99dd9b8b427d032333992b10fd6a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 18:30:39 +0000 Subject: [PATCH 07/18] Improve package strings --- core/strings/builder.odin | 4 + core/strings/strings.odin | 200 +++++++++++++++++++++++++++++++++++++- core/sync/atomic.odin | 146 +++++++++++++--------------- src/check_stmt.cpp | 3 +- src/checker.cpp | 19 ++-- 5 files changed, 285 insertions(+), 87 deletions(-) diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 547c456ba..922412638 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -17,6 +17,10 @@ destroy_builder :: proc(b: ^Builder) { clear(&b.buf); } +grow_builder :: proc(b: ^Builder, cap: int) { + reserve(&b.buf, cap); +} + builder_from_slice :: proc(backing: []byte) -> Builder { s := transmute(mem.Raw_Slice)backing; d := mem.Raw_Dynamic_Array{ diff --git a/core/strings/strings.odin b/core/strings/strings.odin index edf288c16..df3d69732 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -3,6 +3,21 @@ package strings import "core:mem" import "core:unicode/utf8" +clone :: proc(s: string, allocator := context.allocator) -> string { + c := make([]byte, len(s)+1, allocator); + copy(c, cast([]byte)s); + c[len(s)] = 0; + return string(c[:len(s)]); +} + +clone_to_cstring :: proc(s: string, allocator := context.allocator) -> cstring { + c := make([]byte, len(s)+1, allocator); + copy(c, cast([]byte)s); + c[len(s)] = 0; + return cstring(&c[0]); +} + +@(deprecated="Please use 'strings.clone'") new_string :: proc(s: string, allocator := context.allocator) -> string { c := make([]byte, len(s)+1, allocator); copy(c, cast([]byte)s); @@ -10,6 +25,7 @@ new_string :: proc(s: string, allocator := context.allocator) -> string { return string(c[:len(s)]); } +@(deprecated="Please use 'strings.clone_to_cstring'") new_cstring :: proc(s: string, allocator := context.allocator) -> cstring { c := make([]byte, len(s)+1, allocator); copy(c, cast([]byte)s); @@ -46,6 +62,10 @@ contains_any :: proc(s, chars: string) -> bool { } +rune_count :: proc(s: string) -> int { + return utf8.rune_count_in_string(s); +} + equal_fold :: proc(s, t: string) -> bool { loop: for s != "" && t != "" { @@ -209,7 +229,7 @@ last_index_any :: proc(s, chars: string) -> int { count :: proc(s, substr: string) -> int { if len(substr) == 0 { // special case - return utf8.rune_count_in_string(s) + 1; + return rune_count(s) + 1; } if len(substr) == 1 { c := substr[0]; @@ -493,3 +513,181 @@ trim_null :: proc(s: string) -> string { return trim_right_null(trim_left_null(s)); } +// scrub scruvs invalid utf-8 characters and replaces them with the replacement string +// Adjacent invalid bytes are only replaced once +scrub :: proc(str: string, replacement: string, allocator := context.allocator) -> string { + b := make_builder(allocator);; + grow_builder(&b, len(str)); + + has_error := false; + cursor := 0; + origin := str; + + for len(str) > 0 { + r, w := utf8.decode_rune_in_string(str); + + if r == utf8.RUNE_ERROR { + if !has_error { + has_error = true; + write_string(&b, origin[:cursor]); + } + } else if has_error { + has_error = false; + write_string(&b, replacement); + + origin = origin[cursor:]; + cursor = 0; + } + + cursor += w; + str = str[w:]; + } + + return to_string(b); +} + + +reverse :: proc(str: string, allocator := context.allocator) -> string { + n := len(str); + buf := make([]byte, n); + i := 0; + + for len(str) > 0 { + _, w := utf8.decode_rune_in_string(str); + copy(buf[i:], cast([]byte)str[:w]); + str = str[w:]; + } + return string(buf); +} + +expand_tabs :: proc(str: string, tab_size: int, allocator := context.allocator) -> string { + if tab_size <= 0 { + panic("tab size must be positive"); + } + + if str == "" { + return ""; + } + + b := make_builder(allocator); + + column: int; + + for len(str) > 0 { + r, w := utf8.decode_rune_in_string(str); + + if r == '\t' { + expand := tab_size - column%tab_size; + + for i := 0; i < expand; i += 1 { + write_byte(&b, ' '); + } + + column += expand; + } else { + if r == '\n' { + column = 0; + } else { + column += w; + } + + write_rune(&b, r); + } + + str = str[w:]; + } + + return to_string(b); +} + + +partition :: proc(str, sep: string) -> (head, match, tail: string) { + i := index(str, sep); + if i == -1 { + head = str; + return; + } + + head = str[:i]; + match = str[i:i+len(sep)]; + tail = str[i+len(sep):]; + return; +} + +center_justify :: centre_justify; // NOTE(bill): Because Americans exist + +// centre_justify returns a string with a pad string at boths sides if the str's rune length is smaller than length +centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string { + n := rune_count(str); + if n >= length || pad == "" { + return clone(str, allocator); + } + + remains := length-1; + pad_len := rune_count(pad); + + b := make_builder(allocator); + grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad)); + + write_pad_string(&b, pad, pad_len, remains/2); + write_string(&b, str); + write_pad_string(&b, pad, pad_len, (remains+1)/2); + + return to_string(b); +} + +// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length +left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string { + n := rune_count(str); + if n >= length || pad == "" { + return clone(str, allocator); + } + + remains := length-1; + pad_len := rune_count(pad); + + b := make_builder(allocator); + grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad)); + + write_string(&b, str); + write_pad_string(&b, pad, pad_len, remains); + + return to_string(b); +} + +// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length +right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string { + n := rune_count(str); + if n >= length || pad == "" { + return clone(str, allocator); + } + + remains := length-1; + pad_len := rune_count(pad); + + b := make_builder(allocator); + grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad)); + + write_pad_string(&b, pad, pad_len, remains); + write_string(&b, str); + + return to_string(b); +} + + +@private +write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) { + repeats := remains / pad_len; + + for i := 0; i < repeats; i += 1 { + write_string(b, pad); + } + + remains = remains % pad_len; + + if remains != 0 do for i := 0; i < remains; i += 1 { + r, w := utf8.decode_rune_in_string(pad); + write_rune(b, r); + pad = pad[w:]; + } +} diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index 4ea715bb4..9b2a0b3d1 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -11,92 +11,86 @@ Ordering :: enum { } strongest_failure_ordering :: inline proc "contextless" (order: Ordering) -> Ordering { - using Ordering; #complete switch order { - case Relaxed: return Relaxed; - case Release: return Relaxed; - case Acquire: return Acquire; - case Acquire_Release: return Acquire; - case Sequentially_Consistent: return Sequentially_Consistent; + case .Relaxed: return .Relaxed; + case .Release: return .Relaxed; + case .Acquire: return .Acquire; + case .Acquire_Release: return .Acquire; + case .Sequentially_Consistent: return .Sequentially_Consistent; } - return Relaxed; + return .Relaxed; } fence :: inline proc "contextless" (order: Ordering) { - using Ordering; #complete switch order { - case Relaxed: panic("there is no such thing as a relaxed fence"); - case Release: intrinsics.atomic_fence_rel(); - case Acquire: intrinsics.atomic_fence_acq(); - case Acquire_Release: intrinsics.atomic_fence_acqrel(); - case Sequentially_Consistent: intrinsics.atomic_fence(); + case .Relaxed: panic("there is no such thing as a relaxed fence"); + case .Release: intrinsics.atomic_fence_rel(); + case .Acquire: intrinsics.atomic_fence_acq(); + case .Acquire_Release: intrinsics.atomic_fence_acqrel(); + case .Sequentially_Consistent: intrinsics.atomic_fence(); case: panic("unknown order"); } } atomic_store :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) { - using Ordering; #complete switch order { - case Relaxed: intrinsics.atomic_store_relaxed(dst, val); - case Release: intrinsics.atomic_store_rel(dst, val); - case Sequentially_Consistent: intrinsics.atomic_store(dst, val); - case Acquire: panic("there is not such thing as an acquire store"); - case Acquire_Release: panic("there is not such thing as an acquire/release store"); + case .Relaxed: intrinsics.atomic_store_relaxed(dst, val); + case .Release: intrinsics.atomic_store_rel(dst, val); + case .Sequentially_Consistent: intrinsics.atomic_store(dst, val); + case .Acquire: panic("there is not such thing as an acquire store"); + case .Acquire_Release: panic("there is not such thing as an acquire/release store"); case: panic("unknown order"); } } atomic_load :: inline proc "contextless" (dst: ^$T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_load_relaxed(dst); - case Acquire: return intrinsics.atomic_load_acq(dst); - case Sequentially_Consistent: return intrinsics.atomic_load(dst); - case Release: panic("there is no such thing as a release load"); - case Acquire_Release: panic("there is no such thing as an acquire/release load"); + case .Relaxed: return intrinsics.atomic_load_relaxed(dst); + case .Acquire: return intrinsics.atomic_load_acq(dst); + case .Sequentially_Consistent: return intrinsics.atomic_load(dst); + case .Release: panic("there is no such thing as a release load"); + case .Acquire_Release: panic("there is no such thing as an acquire/release load"); } panic("unknown order"); return T{}; } atomic_swap :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val); - case Release: return intrinsics.atomic_xchg_rel(dst, val); - case Acquire: return intrinsics.atomic_xchg_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val); + case .Relaxed: return intrinsics.atomic_xchg_relaxed(dst, val); + case .Release: return intrinsics.atomic_xchg_rel(dst, val); + case .Acquire: return intrinsics.atomic_xchg_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_xchg_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val); } panic("unknown order"); return T{}; } atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, success, failure: Ordering) -> (val: T, ok: bool) { - using Ordering; switch failure { - case Relaxed: + case .Relaxed: switch success { - case Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new); - case Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new); - case Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new); - case Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new); + case .Relaxed: return intrinsics.atomic_cxchg_relaxed(dst, old, new); + case .Acquire: return intrinsics.atomic_cxchg_acq_failrelaxed(dst, old, new); + case .Acquire_Release: return intrinsics.atomic_cxchg_acqrel_failrelaxed(dst, old, new); + case .Sequentially_Consistent: return intrinsics.atomic_cxchg_failrelaxed(dst, old, new); case: panic("an unknown ordering combination"); } - case Acquire: + case .Acquire: switch success { - case Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new); + case .Acquire: return intrinsics.atomic_cxchg_acq(dst, old, new); case: panic("an unknown ordering combination"); } - case Sequentially_Consistent: + case .Sequentially_Consistent: switch success { - case Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new); + case .Sequentially_Consistent: return intrinsics.atomic_cxchg(dst, old, new); case: panic("an unknown ordering combination"); } - case Acquire_Release: + case .Acquire_Release: panic("there is not such thing as an acquire/release failure ordering"); - case Release: + case .Release: panic("there is not such thing as an release failure ordering"); } return T{}, false; @@ -105,78 +99,72 @@ atomic_compare_exchange :: inline proc "contextless" (dst: ^$T, old, new: T, suc atomic_add :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_add_relaxed(dst, val); - case Release: return intrinsics.atomic_add_rel(dst, val); - case Acquire: return intrinsics.atomic_add_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_add(dst, val); + case .Relaxed: return intrinsics.atomic_add_relaxed(dst, val); + case .Release: return intrinsics.atomic_add_rel(dst, val); + case .Acquire: return intrinsics.atomic_add_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_add_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_add(dst, val); } panic("unknown order"); return T{}; } atomic_sub :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_sub_relaxed(dst, val); - case Release: return intrinsics.atomic_sub_rel(dst, val); - case Acquire: return intrinsics.atomic_sub_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_sub(dst, val); + case .Relaxed: return intrinsics.atomic_sub_relaxed(dst, val); + case .Release: return intrinsics.atomic_sub_rel(dst, val); + case .Acquire: return intrinsics.atomic_sub_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_sub_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_sub(dst, val); } panic("unknown order"); return T{}; } atomic_and :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_and_relaxed(dst, val); - case Release: return intrinsics.atomic_and_rel(dst, val); - case Acquire: return intrinsics.atomic_and_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_and(dst, val); + case .Relaxed: return intrinsics.atomic_and_relaxed(dst, val); + case .Release: return intrinsics.atomic_and_rel(dst, val); + case .Acquire: return intrinsics.atomic_and_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_and_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_and(dst, val); } panic("unknown order"); return T{}; } atomic_nand :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_nand_relaxed(dst, val); - case Release: return intrinsics.atomic_nand_rel(dst, val); - case Acquire: return intrinsics.atomic_nand_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_nand(dst, val); + case .Relaxed: return intrinsics.atomic_nand_relaxed(dst, val); + case .Release: return intrinsics.atomic_nand_rel(dst, val); + case .Acquire: return intrinsics.atomic_nand_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_nand_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_nand(dst, val); } panic("unknown order"); return T{}; } atomic_or :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_or_relaxed(dst, val); - case Release: return intrinsics.atomic_or_rel(dst, val); - case Acquire: return intrinsics.atomic_or_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_or(dst, val); + case .Relaxed: return intrinsics.atomic_or_relaxed(dst, val); + case .Release: return intrinsics.atomic_or_rel(dst, val); + case .Acquire: return intrinsics.atomic_or_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_or_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_or(dst, val); } panic("unknown order"); return T{}; } atomic_xor :: inline proc "contextless" (dst: ^$T, val: T, order: Ordering) -> T { - using Ordering; #complete switch order { - case Relaxed: return intrinsics.atomic_xor_relaxed(dst, val); - case Release: return intrinsics.atomic_xor_rel(dst, val); - case Acquire: return intrinsics.atomic_xor_acq(dst, val); - case Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val); - case Sequentially_Consistent: return intrinsics.atomic_xor(dst, val); + case .Relaxed: return intrinsics.atomic_xor_relaxed(dst, val); + case .Release: return intrinsics.atomic_xor_rel(dst, val); + case .Acquire: return intrinsics.atomic_xor_acq(dst, val); + case .Acquire_Release: return intrinsics.atomic_xor_acqrel(dst, val); + case .Sequentially_Consistent: return intrinsics.atomic_xor(dst, val); } panic("unknown order"); return T{}; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index cead61ce8..07de5dc2e 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -474,10 +474,11 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b case Entity_ImportName: { Scope *scope = e->ImportName.scope; for_array(i, scope->elements.entries) { + String name = scope->elements.entries[i].key.string; Entity *decl = scope->elements.entries[i].value; if (!is_entity_exported(decl)) continue; - Entity *found = scope_insert(ctx->scope, decl); + Entity *found = scope_insert_with_name(ctx->scope, name, decl); if (found != nullptr) { gbString expr_str = expr_to_string(expr); error(us->token, diff --git a/src/checker.cpp b/src/checker.cpp index 8e8afc621..887f1af67 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -388,8 +388,7 @@ Entity *scope_lookup(Scope *s, String name) { -Entity *scope_insert(Scope *s, Entity *entity) { - String name = entity->token.string; +Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) { if (name == "") { return nullptr; } @@ -406,6 +405,11 @@ Entity *scope_insert(Scope *s, Entity *entity) { return nullptr; } +Entity *scope_insert(Scope *s, Entity *entity) { + String name = entity->token.string; + return scope_insert_with_name(s, name, entity); +} + GB_COMPARE_PROC(entity_variable_pos_cmp) { Entity *x = *cast(Entity **)a; @@ -1023,11 +1027,10 @@ void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { array_add(&i->definitions, entity); } -bool add_entity(Checker *c, Scope *scope, Ast *identifier, Entity *entity) { +bool add_entity_with_name(Checker *c, Scope *scope, Ast *identifier, Entity *entity, String name) { if (scope == nullptr) { return false; } - String name = entity->token.string; if (!is_blank_ident(name)) { Entity *ie = scope_insert(scope, entity); if (ie != nullptr) { @@ -1063,6 +1066,9 @@ bool add_entity(Checker *c, Scope *scope, Ast *identifier, Entity *entity) { } return true; } +bool add_entity(Checker *c, Scope *scope, Ast *identifier, Entity *entity) { + return add_entity_with_name(c, scope, identifier, entity, entity->token.string); +} void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) { if (entity == nullptr) { @@ -3050,12 +3056,13 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { // NOTE(bill): Add imported entities to this file's scope for_array(elem_index, scope->elements.entries) { + String name = scope->elements.entries[elem_index].key.string; Entity *e = scope->elements.entries[elem_index].value; if (e->scope == parent_scope) continue; if (is_entity_exported(e)) { - Entity *prev = scope_lookup(parent_scope, e->token.string); - add_entity(ctx->checker, parent_scope, e->identifier, e); + Entity *prev = scope_lookup(parent_scope, name); + add_entity_with_name(ctx->checker, parent_scope, e->identifier, e, name); } } } From 716373836ca8139a952b79a6df2a67fd22b7c2c8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 19:01:36 +0000 Subject: [PATCH 08/18] Disallow attributes on alias declarations --- src/check_decl.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index c2796e1da..3f5ef042f 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -391,8 +391,18 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, case Entity_Procedure: case Entity_LibraryName: case Entity_ImportName: - override_entity_in_scope(e, entity); - return; + { + override_entity_in_scope(e, entity); + + DeclInfo *decl = decl_info_of_entity(e); + if (decl != nullptr) { + if (decl->attributes.count > 0) { + error(decl->attributes[0], "Constant alias declarations cannot have attributes"); + } + } + + return; + } } } } From 332e59835725b931b1b04e741a4f12bfe9a29748 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 23:13:06 +0000 Subject: [PATCH 09/18] %e and %g support in fmt.printf --- core/decimal/decimal.odin | 25 +++++++---- core/fmt/fmt.odin | 37 ++++++++++++++-- core/strconv/strconv.odin | 90 ++++++++++++++++++++++++++++++++------- 3 files changed, 126 insertions(+), 26 deletions(-) diff --git a/core/decimal/decimal.odin b/core/decimal/decimal.odin index 22498cb8a..2acf7a03d 100644 --- a/core/decimal/decimal.odin +++ b/core/decimal/decimal.odin @@ -130,10 +130,15 @@ shift_right :: proc(a: ^Decimal, k: uint) { } shift_left :: proc(a: ^Decimal, k: uint) { - delta := int(k/4); + // NOTE(bill): used to determine buffer size required for the decimal from the binary shift + // 'k' means `1<= 0; r -= 1 { @@ -141,7 +146,7 @@ shift_left :: proc(a: ^Decimal, k: uint) { quo := n/10; rem := n - 10*quo; w -= 1; - if w < len(a.digits) { + if w < d { a.digits[w] = byte('0' + rem); } else if rem != 0 { a.trunc = true; @@ -153,7 +158,7 @@ shift_left :: proc(a: ^Decimal, k: uint) { quo := n/10; rem := n - 10*quo; w -= 1; - if 0 <= w && w < len(a.digits) { + if w < d { a.digits[w] = byte('0' + rem); } else if rem != 0 { a.trunc = true; @@ -161,9 +166,12 @@ shift_left :: proc(a: ^Decimal, k: uint) { n = quo; } - a.count += delta; - a.count = min(a.count, len(a.digits)); - a.decimal_point += delta; + // NOTE(bill): Remove unused buffer size + assert(w >= 0); + capacity -= w; + + a.count = min(a.count+capacity, d); + a.decimal_point += capacity; trim(a); } @@ -253,3 +261,4 @@ rounded_integer :: proc(a: ^Decimal) -> u64 { } return n; } + diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 344f61e80..db825663d 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -551,9 +551,6 @@ _pad :: proc(fi: ^Info, s: string) { fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { switch verb { - // case 'e', 'E', 'f', 'F', 'g', 'G', 'v': - // case 'f', 'F', 'v': - case 'f', 'F', 'v': prec: int = 3; if fi.prec_set do prec = fi.prec; @@ -588,6 +585,40 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { _pad(fi, str[1:]); } + case 'e', 'E': + prec: int = 3; + if fi.prec_set do prec = fi.prec; + buf: [386]byte; + + str := strconv.append_float(buf[1:], v, 'e', prec, bit_size); + str = string(buf[:len(str)+1]); + if str[1] == '+' || str[1] == '-' { + str = str[1:]; + } else { + str[0] = '+'; + } + + if fi.space && !fi.plus && str[0] == '+' { + str[0] = ' '; + } + + if len(str) > 1 && (str[1] == 'N' || str[1] == 'I') { + strings.write_string(fi.buf, str); + return; + } + + if fi.plus || str[0] != '+' { + if fi.zero && fi.width_set && fi.width > len(str) { + strings.write_byte(fi.buf, str[0]); + fmt_write_padding(fi, fi.width - len(str)); + strings.write_string(fi.buf, str[1:]); + } else { + _pad(fi, str); + } + } else { + _pad(fi, str[1:]); + } + case: fmt_bad_verb(fi, verb); } diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index d509d7b6a..07f506b6d 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -213,28 +213,28 @@ append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> str -DecimalSlice :: struct { +Decimal_Slice :: struct { digits: []byte, count: int, decimal_point: int, neg: bool, } -FloatInfo :: struct { +Float_Info :: struct { mantbits: uint, expbits: uint, bias: int, } -_f16_info := FloatInfo{10, 5, -15}; -_f32_info := FloatInfo{23, 8, -127}; -_f64_info := FloatInfo{52, 11, -1023}; +_f16_info := Float_Info{10, 5, -15}; +_f32_info := Float_Info{23, 8, -127}; +_f64_info := Float_Info{52, 11, -1023}; generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte { bits: u64; - flt: ^FloatInfo; + flt: ^Float_Info; switch bit_size { case 32: bits = u64(transmute(u32)f32(val)); @@ -276,11 +276,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ d := &d_; assign(d, mant); shift(d, exp - int(flt.mantbits)); - digs: DecimalSlice; + digs: Decimal_Slice; shortest := prec < 0; if shortest { round_shortest(d, mant, exp, flt); - digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point}; + digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point}; switch fmt { case 'e', 'E': prec = digs.count-1; case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0); @@ -297,14 +297,14 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ round(d, prec); } - digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point}; + digs = Decimal_Slice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point}; } return format_digits(buf, shortest, neg, digs, prec, fmt); } -format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte { +format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte { Buffer :: struct { b: []byte, n: int, @@ -347,12 +347,72 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice return to_bytes(b); case 'e', 'E': - panic("strconv: e/E float printing is not yet supported"); - return to_bytes(b); // TODO + add_bytes(&b, neg ? '-' : '+'); + + ch := byte('0'); + if digs.count != 0 { + ch = digs.digits[0]; + } + add_bytes(&b, ch); + + if prec > 0 { + add_bytes(&b, '.'); + i := 1; + m := min(digs.count, prec+1); + if i < m { + add_bytes(&b, ..digs.digits[i:m]); + i = m; + } + for ; i <= prec; i += 1 { + add_bytes(&b, '0'); + } + } + + add_bytes(&b, fmt); + exp := digs.decimal_point-1; + if digs.count == 0 { + // Zero has exponent of 0 + exp = 0; + } + + ch = '+'; + if exp < 0 { + ch = '-'; + exp = -exp; + } + add_bytes(&b, ch); + + switch { + case exp < 10: add_bytes(&b, '0', byte(exp)+'0'); // add prefix 0 + case exp < 100: add_bytes(&b, byte(exp/10)+'0', byte(exp%10)+'0'); + case: add_bytes(&b, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0'); + } + + return to_bytes(b); case 'g', 'G': - panic("strconv: g/G float printing is not yet supported"); - return to_bytes(b); // TODO + eprec := prec; + if eprec > digs.count && digs.count >= digs.decimal_point { + eprec = digs.count; + } + + if shortest { + eprec = 6; + } + + exp := digs.decimal_point - 1; + if exp < -4 || exp >= eprec { + if prec > digs.count { + prec = digs.count; + } + return format_digits(buf, shortest, neg, digs, prec-1, fmt+'e'-'g'); // keep the same case + } + + if prec > digs.decimal_point { + prec = digs.count; + } + + return format_digits(buf, shortest, neg, digs, max(prec-digs.decimal_point, 0), 'f'); case: add_bytes(&b, '%', fmt); @@ -362,7 +422,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice } -round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) { +round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) { if mant == 0 { // If mantissa is zero, the number is zero d.count = 0; return; From 231f3cc15a063f2516edd507ef385e7cf81afbc0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 23:22:05 +0000 Subject: [PATCH 10/18] %h support in fmt.printf for hexadecimal floats --- core/fmt/fmt.odin | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index db825663d..68cde1ec3 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -619,6 +619,25 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { _pad(fi, str[1:]); } + case 'h', 'H': + prev_fi := fi^; + defer fi^ = prev_fi; + fi.hash = false; + fi.width = bit_size; + fi.zero = true; + fi.plus = false; + + u: u64; + switch bit_size { + case 32: u = u64(transmute(u32)f32(v)); + case 64: u = transmute(u64)v; + case: panic("Unhandled float size"); + } + + strings.write_string(fi.buf, "0h"); + _fmt_int(fi, u, 16, false, bit_size, verb == 'h' ? __DIGITS_LOWER : __DIGITS_UPPER); + + case: fmt_bad_verb(fi, verb); } From 14c6f2f258491a13164129d94240f13679cf1faa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 15 Mar 2019 23:49:47 +0000 Subject: [PATCH 11/18] Add extra pointer printing options to fmt.printf --- core/fmt/fmt.odin | 48 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 68cde1ec3..867d1c7bb 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -673,13 +673,20 @@ fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) { } fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) { + u := u64(uintptr(p)); switch verb { case 'p', 'v': - u := u64(uintptr(p)); if !fi.hash || verb == 'v' { strings.write_string(fi.buf, "0x"); } _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER); + + case 'b': _fmt_int(fi, u, 2, false, 8*size_of(rawptr), __DIGITS_UPPER); + case 'o': _fmt_int(fi, u, 8, false, 8*size_of(rawptr), __DIGITS_UPPER); + case 'd': _fmt_int(fi, u, 10, false, 8*size_of(rawptr), __DIGITS_UPPER); + case 'x': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER); + case 'X': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER); + case: fmt_bad_verb(fi, verb); } @@ -1046,14 +1053,19 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Dynamic_Array: - strings.write_byte(fi.buf, '['); - defer strings.write_byte(fi.buf, ']'); - array := cast(^mem.Raw_Dynamic_Array)v.data; - for i in 0..array.len-1 { - if i > 0 do strings.write_string(fi.buf, ", "); + if verb == 'p' { + slice := cast(^mem.Raw_Dynamic_Array)v.data; + fmt_pointer(fi, slice.data, 'p'); + } else { + strings.write_byte(fi.buf, '['); + defer strings.write_byte(fi.buf, ']'); + array := cast(^mem.Raw_Dynamic_Array)v.data; + for i in 0..array.len-1 { + if i > 0 do strings.write_string(fi.buf, ", "); - data := uintptr(array.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + data := uintptr(array.data) + uintptr(i*info.elem_size); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + } } case runtime.Type_Info_Simd_Vector: @@ -1071,16 +1083,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Slice: - strings.write_byte(fi.buf, '['); - defer strings.write_byte(fi.buf, ']'); - slice := cast(^mem.Raw_Slice)v.data; - for i in 0..slice.len-1 { - if i > 0 do strings.write_string(fi.buf, ", "); + if verb == 'p' { + slice := cast(^mem.Raw_Slice)v.data; + fmt_pointer(fi, slice.data, 'p'); + } else { + strings.write_byte(fi.buf, '['); + defer strings.write_byte(fi.buf, ']'); + slice := cast(^mem.Raw_Slice)v.data; + for i in 0..slice.len-1 { + if i > 0 do strings.write_string(fi.buf, ", "); - data := uintptr(slice.data) + uintptr(i*info.elem_size); - fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + data := uintptr(slice.data) + uintptr(i*info.elem_size); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + } } - case runtime.Type_Info_Map: if verb != 'v' { fmt_bad_verb(fi, verb); From f7efaf2ba2236329a67103cd5a25524907180987 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 16 Mar 2019 00:10:57 +0000 Subject: [PATCH 12/18] fmt.printf support for pointer to container (one level deep) --- core/fmt/fmt.odin | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 867d1c7bb..21cc6c79a 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -31,6 +31,7 @@ Info :: struct { buf: ^strings.Builder, arg: any, // Temporary + record_level: int, } fprint :: proc(fd: os.Handle, args: ..any) -> int { @@ -1039,6 +1040,32 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { if v.id == typeid_of(^runtime.Type_Info) { write_type(fi.buf, (^^runtime.Type_Info)(v.data)^); } else { + if verb != 'p' { + elem := runtime.type_info_base(info.elem); + if elem != nil do switch e in elem.variant { + case runtime.Type_Info_Array, + runtime.Type_Info_Slice, + runtime.Type_Info_Dynamic_Array, + runtime.Type_Info_Map: + if fi.record_level == 0 { + fi.record_level += 1; + defer fi.record_level -= 1; + strings.write_byte(fi.buf, '&'); + fmt_value(fi, any{(^rawptr)(v.data)^, info.elem.id}, verb); + return; + } + + case runtime.Type_Info_Struct, + runtime.Type_Info_Union: + if fi.record_level == 0 { + fi.record_level += 1; + defer fi.record_level -= 1; + strings.write_byte(fi.buf, '&'); + fmt_value(fi, any{(^rawptr)(v.data)^, info.elem.id}, verb); + return; + } + } + } fmt_pointer(fi, (^rawptr)(v.data)^, verb); } From 3a31444656dcd6f24c2909e2b72a0099a066353b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 16 Mar 2019 11:00:37 +0000 Subject: [PATCH 13/18] Minor changes to fmt of auto deferencing --- core/fmt/fmt.odin | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 21cc6c79a..9c4759c4f 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -10,7 +10,7 @@ import "core:strconv" import "core:strings" -@(private) +@private DEFAULT_BUFFER_SIZE :: 1<<12; Info :: struct { @@ -1041,27 +1041,38 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { write_type(fi.buf, (^^runtime.Type_Info)(v.data)^); } else { if verb != 'p' { + ptr := (^rawptr)(v.data)^; + a := any{ptr, info.elem.id}; + elem := runtime.type_info_base(info.elem); if elem != nil do switch e in elem.variant { case runtime.Type_Info_Array, runtime.Type_Info_Slice, runtime.Type_Info_Dynamic_Array, runtime.Type_Info_Map: - if fi.record_level == 0 { - fi.record_level += 1; + if ptr == nil { + strings.write_string(fi.buf, ""); + return; + } + if fi.record_level < 1 { + fi.record_level += 1; defer fi.record_level -= 1; strings.write_byte(fi.buf, '&'); - fmt_value(fi, any{(^rawptr)(v.data)^, info.elem.id}, verb); + fmt_value(fi, a, verb); return; } case runtime.Type_Info_Struct, runtime.Type_Info_Union: - if fi.record_level == 0 { + if ptr == nil { + strings.write_string(fi.buf, ""); + return; + } + if fi.record_level < 1 { fi.record_level += 1; defer fi.record_level -= 1; strings.write_byte(fi.buf, '&'); - fmt_value(fi, any{(^rawptr)(v.data)^, info.elem.id}, verb); + fmt_value(fi, a, verb); return; } } @@ -1254,7 +1265,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { switch verb { - case 'f', 'F', 'v': + case 'f', 'F', 'v', 'h', 'H': r, i := real(c), imag(c); fmt_float(fi, r, bits/2, verb); if !fi.plus && i >= 0 { From 1eaa47ebae4daf31ad2071a39d978fdbf32f1082 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 17 Mar 2019 13:03:39 +0000 Subject: [PATCH 14/18] Fix `using import` behaviour - #352 --- core/sys/win32/kernel32.odin | 3 +- src/checker.cpp | 65 +++++++++++++++++++++--------------- src/tokenizer.cpp | 8 +++-- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin index 479e116a0..3cedf72e4 100644 --- a/core/sys/win32/kernel32.odin +++ b/core/sys/win32/kernel32.odin @@ -5,7 +5,6 @@ foreign import "system:kernel32.lib" @(default_calling_convention = "std") foreign kernel32 { - @(link_name="GetLastError") get_last_error :: proc() -> i32 ---; @(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: cstring, process_attributes, thread_attributes: ^Security_Attributes, inherit_handle: Bool, creation_flags: u32, environment: rawptr, @@ -119,6 +118,8 @@ foreign kernel32 { @(default_calling_convention = "c") foreign kernel32 { + @(link_name="GetLastError") get_last_error :: proc() -> i32 ---; + @(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---; @(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---; @(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; diff --git a/src/checker.cpp b/src/checker.cpp index 887f1af67..3b161d95a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1027,6 +1027,33 @@ void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { array_add(&i->definitions, entity); } +bool redeclaration_error(String name, Entity *prev, Entity *found) { + TokenPos pos = found->token.pos; + Entity *up = found->using_parent; + if (up != nullptr) { + if (pos == up->token.pos) { + // NOTE(bill): Error should have been handled already + return false; + } + error(prev->token, + "Redeclaration of '%.*s' in this scope through 'using'\n" + "\tat %.*s(%td:%td)", + LIT(name), + LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); + } else { + if (pos == prev->token.pos) { + // NOTE(bill): Error should have been handled already + return false; + } + error(prev->token, + "Redeclaration of '%.*s' in this scope\n" + "\tat %.*s(%td:%td)", + LIT(name), + LIT(pos.file), pos.line, pos.column); + } + return false; +} + bool add_entity_with_name(Checker *c, Scope *scope, Ast *identifier, Entity *entity, String name) { if (scope == nullptr) { return false; @@ -1034,31 +1061,7 @@ bool add_entity_with_name(Checker *c, Scope *scope, Ast *identifier, Entity *ent if (!is_blank_ident(name)) { Entity *ie = scope_insert(scope, entity); if (ie != nullptr) { - TokenPos pos = ie->token.pos; - Entity *up = ie->using_parent; - if (up != nullptr) { - if (pos == up->token.pos) { - // NOTE(bill): Error should have been handled already - return false; - } - error(entity->token, - "Redeclaration of '%.*s' in this scope through 'using'\n" - "\tat %.*s(%td:%td)", - LIT(name), - LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); - return false; - } else { - if (pos == entity->token.pos) { - // NOTE(bill): Error should have been handled already - return false; - } - error(entity->token, - "Redeclaration of '%.*s' in this scope\n" - "\tat %.*s(%td:%td)", - LIT(name), - LIT(pos.file), pos.line, pos.column); - return false; - } + return redeclaration_error(name, entity, ie); } } if (identifier != nullptr) { @@ -3061,8 +3064,16 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { if (e->scope == parent_scope) continue; if (is_entity_exported(e)) { - Entity *prev = scope_lookup(parent_scope, name); - add_entity_with_name(ctx->checker, parent_scope, e->identifier, e, name); + Entity *found = scope_lookup(parent_scope, name); + if (found != nullptr) { + // NOTE(bill): + // Date: 2019-03-17 + // The order has to be the other way around as `using` adds the entity into the that + // file scope otherwise the error would be the wrong way around + redeclaration_error(name, found, e); + } else { + add_entity_with_name(ctx->checker, parent_scope, e->identifier, e, name); + } } } } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d7a39e824..48f7af19c 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -212,6 +212,8 @@ void warning_va(Token token, char *fmt, va_list va) { gb_mutex_unlock(&global_error_collector.mutex); } +#define MAX_ERROR_COLLECTOR_COUNT (36) + void error_va(Token token, char *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); global_error_collector.count++; @@ -225,7 +227,7 @@ void error_va(Token token, char *fmt, va_list va) { gb_bprintf_va(fmt, va)); } gb_mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > 20) { + if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { gb_exit(1); } } @@ -243,7 +245,7 @@ void error_no_newline_va(Token token, char *fmt, va_list va) { gb_bprintf_va(fmt, va)); } gb_mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > 20) { + if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { gb_exit(1); } } @@ -263,7 +265,7 @@ void syntax_error_va(Token token, char *fmt, va_list va) { } gb_mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > 20) { + if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { gb_exit(1); } } From 4e93b70f8aefbba18f8db70e5e388bdbcf7b0a38 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 17 Mar 2019 14:48:32 +0000 Subject: [PATCH 15/18] Fix bit_field scoping bug --- src/check_type.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/check_type.cpp b/src/check_type.cpp index 451a388fb..1721ed881 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2507,7 +2507,9 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t case_ast_node(et, BitFieldType, e); *type = alloc_type_bit_field(); set_base_type(named_type, *type); + check_open_scope(ctx, e); check_bit_field_type(ctx, *type, e); + check_close_scope(ctx); return true; case_end; From a6fb2dd5877cf1af1911451d31bf3ba042315c57 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 17 Mar 2019 20:43:54 +0000 Subject: [PATCH 16/18] Fix Erroneous redeclaration error with `using import` #354 --- src/checker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/checker.cpp b/src/checker.cpp index 3b161d95a..130c4aee5 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3064,7 +3064,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { if (e->scope == parent_scope) continue; if (is_entity_exported(e)) { - Entity *found = scope_lookup(parent_scope, name); + Entity *found = scope_lookup_current(parent_scope, name); if (found != nullptr) { // NOTE(bill): // Date: 2019-03-17 From dc706d8a6b47c3560bace40061ce60c7e9ef49c6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 17 Mar 2019 23:27:13 +0100 Subject: [PATCH 17/18] Vet CEL --- core/encoding/cel/cel.odin | 38 +++++++++++++++++------------------- core/encoding/cel/token.odin | 10 +++++----- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/core/encoding/cel/cel.odin b/core/encoding/cel/cel.odin index 3f7362203..631157d3c 100644 --- a/core/encoding/cel/cel.odin +++ b/core/encoding/cel/cel.odin @@ -2,8 +2,6 @@ package cel; import "core:fmt" import "core:strconv" -import "core:os" -import "core:mem" import "core:unicode/utf8" import "core:strings" @@ -34,7 +32,7 @@ Parser :: struct { print_value :: proc(value: Value, pretty := true, indent := 0) { print_indent :: proc(indent: int) { - for i in 0..indent-1 do fmt.print("\t"); + for _ in 0..indent-1 do fmt.print("\t"); } switch v in value { @@ -62,16 +60,16 @@ print_value :: proc(value: Value, pretty := true, indent := 0) { if pretty do fmt.println(); i := 0; - for name, value in v { + for name, val in v { if pretty { print_indent(indent+1); fmt.printf("%s = ", name); - print_value(value, pretty, indent+1); + print_value(val, pretty, indent+1); fmt.println(","); } else { if i > 0 do fmt.print(", "); fmt.printf("%s = ", name); - print_value(value, pretty, indent+1); + print_value(val, pretty, indent+1); i += 1; } } @@ -155,7 +153,7 @@ destroy :: proc(p: ^Parser) { delete(v); case Dict: - for key, value in v do destroy_value(value); + for _, dv in v do destroy_value(dv); delete(v); } } @@ -201,11 +199,12 @@ unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool, } return -1; } + w: int; if s[0] == quote && quote == '"' { return; } else if s[0] >= 0x80 { - r, w := utf8.decode_rune_in_string(s); + r, w = utf8.decode_rune_in_string(s); return r, true, s[w:], true; } else if s[0] != '\\' { return rune(s[0]), false, s[1:], true; @@ -291,7 +290,6 @@ unquote_string :: proc(p: ^Parser, t: Token) -> (string, bool) { return t.lit, true; } s := t.lit; - n := len(s); quote := '"'; if s == `""` { @@ -442,7 +440,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) { case Kind.Open_Paren: expect_token(p, Kind.Open_Paren); - expr, pos := parse_expr(p); + expr, _ := parse_expr(p); expect_token(p, Kind.Close_Paren); return expr, tok.pos; @@ -451,7 +449,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) { elems := make([dynamic]Value, 0, 4); for p.curr_token.kind != Kind.Close_Bracket && p.curr_token.kind != Kind.EOF { - elem, pos := parse_expr(p); + elem, _ := parse_expr(p); append(&elems, elem); if p.curr_token.kind == Kind.Semicolon && p.curr_token.lit == "\n" { @@ -481,9 +479,9 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) { name, ok := unquote_string(p, name_tok); if !ok do error(p, tok.pos, "Unable to unquote string"); expect_token(p, Kind.Assign); - elem, pos := parse_expr(p); + elem, _ := parse_expr(p); - if _, ok := dict[name]; ok { + if _, ok2 := dict[name]; ok2 { error(p, name_tok.pos, "Previous declaration of %s in this scope", name); } else { dict[name] = elem; @@ -533,9 +531,9 @@ parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) { } case Kind.Open_Bracket: - open := expect_token(p, Kind.Open_Bracket); + expect_token(p, Kind.Open_Bracket); index, index_pos := parse_expr(p); - close := expect_token(p, Kind.Close_Bracket); + expect_token(p, Kind.Close_Bracket); switch a in operand { @@ -613,7 +611,7 @@ parse_unary_expr :: proc(p: ^Parser) -> (Value, Pos) { case Kind.Not: next_token(p); - expr, pos := parse_unary_expr(p); + expr, _ := parse_unary_expr(p); if v, ok := expr.(bool); ok { return !v, op.pos; } @@ -757,9 +755,9 @@ parse_binary_expr :: proc(p: ^Parser, prec_in: int) -> (Value, Pos) { if op.kind == Kind.Question { cond := expr; - x, x_pos := parse_expr(p); + x, _ := parse_expr(p); expect_token(p, Kind.Colon); - y, y_pos := parse_expr(p); + y, _ := parse_expr(p); if t, ok := cond.(bool); ok { expr = t ? x : y; @@ -824,9 +822,9 @@ parse_assignment :: proc(p: ^Parser) -> bool { expect_token(p, Kind.Assign); name, ok := unquote_string(p, tok); if !ok do error(p, tok.pos, "Unable to unquote string"); - expr, pos := parse_expr(p); + expr, _ := parse_expr(p); d := top_dict(p); - if _, ok := d[name]; ok { + if _, ok2 := d[name]; ok2 { error(p, tok.pos, "Previous declaration of %s", name); } else { d[name] = expr; diff --git a/core/encoding/cel/token.odin b/core/encoding/cel/token.odin index 9c3bdf715..62e6c75bb 100644 --- a/core/encoding/cel/token.odin +++ b/core/encoding/cel/token.odin @@ -322,7 +322,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { } if t.curr_rune == '0' { - offset := t.offset; + offset = t.offset; advance_to_next_rune(t); switch t.curr_rune { case 'b', 'B': @@ -403,17 +403,17 @@ scan :: proc(t: ^Tokenizer) -> Token { quote := r; tok = String; for { - r := t.curr_rune; - if r == '\n' || r < 0 { + this_r := t.curr_rune; + if this_r == '\n' || r < 0 { token_error(t, "String literal not terminated"); break; } advance_to_next_rune(t); - if r == quote { + if this_r == quote { break; } // TODO(bill); Handle properly - if r == '\\' && t.curr_rune == quote { + if this_r == '\\' && t.curr_rune == quote { advance_to_next_rune(t); } } From 314d5a778e9d6d7bf16ad79502bf2fb024dc8a77 Mon Sep 17 00:00:00 2001 From: matt Date: Mon, 18 Mar 2019 07:13:52 -0700 Subject: [PATCH 18/18] Replace calls to deprecated string functions on linux --- core/os/os_linux.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index a4cb06a71..1587e2ad1 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -212,7 +212,7 @@ get_last_error :: proc() -> int { } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - cstr := strings.new_cstring(path); + cstr := strings.clone_to_cstring(path); handle := _unix_open(cstr, flags, mode); delete(cstr); if handle == -1 { @@ -289,7 +289,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { } stat :: inline proc(path: string) -> (Stat, Errno) { - cstr := strings.new_cstring(path); + cstr := strings.clone_to_cstring(path); defer delete(cstr); s: Stat; @@ -310,7 +310,7 @@ fstat :: inline proc(fd: Handle) -> (Stat, Errno) { } access :: inline proc(path: string, mask: int) -> (bool, Errno) { - cstr := strings.new_cstring(path); + cstr := strings.clone_to_cstring(path); defer delete(cstr); result := _unix_access(cstr, mask); if result == -1 { @@ -333,7 +333,7 @@ heap_free :: proc(ptr: rawptr) { } getenv :: proc(name: string) -> (string, bool) { - path_str := strings.new_cstring(name); + path_str := strings.clone_to_cstring(name); defer delete(path_str); cstr := _unix_getenv(path_str); if cstr == nil { @@ -370,14 +370,14 @@ current_thread_id :: proc "contextless" () -> int { } dlopen :: inline proc(filename: string, flags: int) -> rawptr { - cstr := strings.new_cstring(filename); + cstr := strings.clone_to_cstring(filename); defer delete(cstr); handle := _unix_dlopen(cstr, flags); return handle; } dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr { assert(handle != nil); - cstr := strings.new_cstring(symbol); + cstr := strings.clone_to_cstring(symbol); defer delete(cstr); proc_handle := _unix_dlsym(handle, cstr); return proc_handle;