From 5c52ffe24e86241de2057dbf62c3012432aa1db0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 27 May 2018 21:22:25 +0100 Subject: [PATCH] Reorganize `runtime` package --- core/fmt/fmt.odin | 2 +- core/hash/hash.odin | 2 +- core/mem/alloc.odin | 115 +++ core/mem/mem.odin | 29 +- core/os/os.odin | 8 +- core/os/os_linux.odin | 1 - core/os/os_osx.odin | 1 - core/os/os_windows.odin | 3 +- .../_preload.odin => runtime/core.odin} | 835 +++--------------- core/runtime/internal.odin | 432 +++++++++ .../soft_numbers.odin} | 2 +- src/build_settings.cpp | 4 +- src/check_expr.cpp | 72 +- src/check_stmt.cpp | 2 +- src/check_type.cpp | 2 +- src/checker.cpp | 94 +- src/checker.hpp | 22 +- src/ir.cpp | 28 +- src/main.cpp | 2 +- src/parser.cpp | 90 +- src/parser.hpp | 18 +- 21 files changed, 908 insertions(+), 856 deletions(-) create mode 100644 core/mem/alloc.odin rename core/{builtin/_preload.odin => runtime/core.odin} (51%) create mode 100644 core/runtime/internal.odin rename core/{builtin/_soft_numbers.odin => runtime/soft_numbers.odin} (99%) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 47b30661b..497d23520 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -38,7 +38,7 @@ string_buffer_from_slice :: proc(backing: []byte) -> String_Buffer { data = s.data, len = 0, cap = s.len, - allocator = nil_allocator(), + allocator = mem.nil_allocator(), }; return transmute(String_Buffer)d; } diff --git a/core/hash/hash.odin b/core/hash/hash.odin index 6addcd7f8..17b8b54ca 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -64,7 +64,7 @@ murmur32 :: proc(data: []byte) -> u32 { c2_32: u32 : 0x1b873593; h1: u32 = 0; - nblocks := len(data)/4; + nblocks := uintptr(len(data)/4); p := &data[0]; p1 := mem.ptr_offset(p, 4*nblocks); diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin new file mode 100644 index 000000000..aef740fb1 --- /dev/null +++ b/core/mem/alloc.odin @@ -0,0 +1,115 @@ +package mem + +import "core:raw" +import "core:os" + + +alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr { + a := context.allocator; + return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc); +} + +free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, loc := #caller_location) { + if ptr == nil do return; + if a.procedure == nil do return; + a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc); +} + +free_ptr :: inline proc(ptr: rawptr, loc := #caller_location) do free_ptr_with_allocator(context.allocator, ptr); + +free_all :: inline proc(loc := #caller_location) { + a := context.allocator; + a.procedure(a.data, Allocator_Mode.Free_All, 0, 0, nil, 0, 0, loc); +} + + +resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr { + a := context.allocator; + return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc); +} + + +free_string :: proc(str: string, loc := #caller_location) { + free_ptr(raw.data(str), loc); +} +free_cstring :: proc(str: cstring, loc := #caller_location) { + free_ptr((^byte)(str), loc); +} +free_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) { + free_ptr(raw.data(array), loc); +} +free_slice :: proc(array: $T/[]$E, loc := #caller_location) { + free_ptr(raw.data(array), loc); +} +free_map :: proc(m: $T/map[$K]$V, loc := #caller_location) { + raw := transmute(raw.Map)m; + free_dynamic_array(raw.hashes, loc); + free_ptr(raw.entries.data, loc); +} + + + +default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr { + if old_memory == nil do return alloc(new_size, alignment, loc); + + if new_size == 0 { + free(old_memory, loc); + return nil; + } + + if new_size == old_size do return old_memory; + + new_memory := alloc(new_size, alignment, loc); + if new_memory == nil do return nil; + + __mem_copy(new_memory, old_memory, min(old_size, new_size));; + free(old_memory, loc); + return new_memory; +} + + +default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { + using Allocator_Mode; + + switch mode { + case Alloc: + return os.heap_alloc(size); + + case Free: + os.heap_free(old_memory); + return nil; + + case Free_All: + // NOTE(bill): Does nothing + + case Resize: + ptr := os.heap_resize(old_memory, size); + assert(ptr != nil); + return ptr; + } + + return nil; +} + +default_allocator :: proc() -> Allocator { + return Allocator{ + procedure = default_allocator_proc, + data = nil, + }; +} + +nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { + return nil; +} + +nil_allocator :: proc() -> Allocator { + return Allocator{ + procedure = nil_allocator_proc, + data = nil, + }; +} + diff --git a/core/mem/mem.odin b/core/mem/mem.odin index c125495b2..66c47bd51 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -23,12 +23,19 @@ copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawpt return __mem_copy_non_overlapping(dst, src, len); } compare :: proc "contextless" (a, b: []byte) -> int { - return __mem_compare(&a[0], &b[0], min(len(a), len(b))); + return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b))); +} +compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int { + pa :: ptr_offset; + for i in 0..uintptr(n) do switch { + case pa(a, i)^ < pa(b, i)^: return -1; + case pa(a, i)^ > pa(b, i)^: return +1; + } + return 0; } - -ptr_offset :: proc "contextless" (ptr: $P/^$T, n: int) -> P { - new := uintptr(ptr) + uintptr(size_of(T)*n); +ptr_offset :: proc "contextless" (ptr: $P/^$T, n: uintptr) -> P { + new := uintptr(ptr) + size_of(T)*n; return P(new); } @@ -48,6 +55,18 @@ slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte { return transmute([]byte)s; } + +buffer_from_slice :: proc(backing: $T/[]$E) -> [dynamic]E { + s := transmute(raw.Slice)backing; + d := raw.Dynamic_Array{ + data = s.data, + len = 0, + cap = s.len, + allocator = nil_allocator(), + }; + return transmute([dynamic]E)d; +} + ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte { assert(len >= 0); return transmute([]byte)raw.Slice{ptr, len*size_of(T)}; @@ -89,7 +108,7 @@ allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: in ptr := cast(^uint)(ptr_offset(header, 1)); n := ptr_sub(cast(^uint)data, ptr); - for i in 0..n { + for i in 0..uintptr(n) { ptr_offset(ptr, i)^ = ~uint(0); } } diff --git a/core/os/os.odin b/core/os/os.odin index 34be2437f..f38cad55a 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -1,6 +1,6 @@ package os -import "core:mem" +import "core:raw" write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, cast([]byte)str); @@ -56,9 +56,11 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ } write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { - return write(fd, mem.slice_ptr(cast(^byte)data, len)); + s := transmute([]byte)raw.Slice{data, len}; + return write(fd, s); } read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { - return read(fd, mem.slice_ptr(cast(^byte)data, len)); + s := transmute([]byte)raw.Slice{data, len}; + return read(fd, s); } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index efe9160d3..823c1af8e 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -4,7 +4,6 @@ foreign import dl "system:dl" foreign import libc "system:c" import "core:strings" -import "core:mem" OS :: "linux"; diff --git a/core/os/os_osx.odin b/core/os/os_osx.odin index 1292bfd95..befd97257 100644 --- a/core/os/os_osx.odin +++ b/core/os/os_osx.odin @@ -4,7 +4,6 @@ foreign import dl "system:dl" foreign import libc "system:c" import "core:strings" -import "core:mem" OS :: "osx"; diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 3c1a6d627..0e9ec2a98 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -1,7 +1,6 @@ package os import "core:sys/win32" -import "core:mem" OS :: "windows"; @@ -269,7 +268,7 @@ _alloc_command_line_arguments :: proc() -> []string { arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count); arg_list := make([]string, int(arg_count)); for _, i in arg_list { - wc_str := mem.ptr_offset(arg_list_ptr, i)^; + wc_str := (^win32.Wstring)(uintptr(arg_list_ptr) + size_of(win32.Wstring)*uintptr(i))^; olen := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1, nil, 0, nil, nil); diff --git a/core/builtin/_preload.odin b/core/runtime/core.odin similarity index 51% rename from core/builtin/_preload.odin rename to core/runtime/core.odin index f6174d383..1346d49d1 100644 --- a/core/builtin/_preload.odin +++ b/core/runtime/core.odin @@ -1,4 +1,4 @@ -package builtin +package runtime import "core:os" import "core:unicode/utf8" @@ -146,8 +146,6 @@ Source_Code_Location :: struct { procedure: string, } - - Allocator_Mode :: enum byte { Alloc, Free, @@ -167,8 +165,9 @@ Allocator :: struct { } + Context :: struct { - allocator: Allocator, + allocator: mem.Allocator, thread_id: int, user_data: any, @@ -180,6 +179,9 @@ Context :: struct { DEFAULT_ALIGNMENT :: 2*align_of(rawptr); + + + __INITIAL_MAP_CAP :: 16; __Map_Key :: struct { @@ -212,6 +214,9 @@ __Map_Header :: struct { + + + type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { if info == nil do return nil; @@ -293,7 +298,7 @@ __init_context :: proc "contextless" (c: ^Context) { if c == nil do return; if c.allocator.procedure == nil { - c.allocator = default_allocator(); + c.allocator = mem.default_allocator(); } if c.thread_id == 0 { c.thread_id = os.current_thread_id(); @@ -302,30 +307,6 @@ __init_context :: proc "contextless" (c: ^Context) { -alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr { - a := context.allocator; - return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc); -} - -free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, loc := #caller_location) { - if ptr == nil do return; - if a.procedure == nil do return; - a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc); -} - -free_ptr :: inline proc(ptr: rawptr, loc := #caller_location) do free_ptr_with_allocator(context.allocator, ptr); - -free_all :: inline proc(loc := #caller_location) { - a := context.allocator; - a.procedure(a.data, Allocator_Mode.Free_All, 0, 0, nil, 0, 0, loc); -} - - -resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr { - a := context.allocator; - return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc); -} - copy :: proc "contextless" (dst, src: $T/[]$E) -> int { n := max(0, min(len(dst), len(src))); @@ -334,6 +315,65 @@ copy :: proc "contextless" (dst, src: $T/[]$E) -> int { } + +pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E { + if array == nil do return E{}; + assert(len(array) > 0); + res := array[len(array)-1]; + (^raw.Dynamic_Array)(array).len -= 1; + return res; +} + + + +clear :: proc[clear_dynamic_array, clear_map]; +reserve :: proc[reserve_dynamic_array, reserve_map]; + + + +new :: inline proc(T: type, loc := #caller_location) -> ^T { + ptr := (^T)(mem.alloc(size_of(T), align_of(T), loc)); + ptr^ = T{}; + return ptr; +} +new_clone :: inline proc(data: $T, loc := #caller_location) -> ^T { + ptr := (^T)(mem.alloc(size_of(T), align_of(T), loc)); + ptr^ = data; + return ptr; +} + + +free :: proc[ + mem.free_ptr, + mem.free_string, + mem.free_cstring, + mem.free_dynamic_array, + mem.free_slice, + mem.free_map, +]; + + + + +clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) { + if m == nil do return; + raw_map := (^raw.Map)(m); + hashes := (^raw.Dynamic_Array)(&raw_map.hashes); + entries := (^raw.Dynamic_Array)(&raw_map.entries); + hashes.len = 0; + entries.len = 0; +} + +reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) { + if m != nil do __dynamic_map_reserve(__get_map_header(m), capacity); +} + +delete :: proc(m: ^$T/map[$K]$V, key: K) { + if m != nil do __dynamic_map_delete(__get_map_header(m), __get_map_key(key)); +} + + + append :: proc(array: ^$T/[dynamic]$E, args: ...E, loc := #caller_location) -> int { if array == nil do return 0; @@ -350,7 +390,7 @@ append :: proc(array: ^$T/[dynamic]$E, args: ...E, loc := #caller_location) -> i a := (^raw.Dynamic_Array)(array); data := (^E)(a.data); assert(data != nil); - __mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); + __mem_copy(mem.ptr_offset(data, uintptr(a.len)), &args[0], size_of(E) * arg_len); a.len += arg_len; } return len(array); @@ -363,27 +403,9 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ...string, loc := #caller return len(array); } -pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E { - if array == nil do return E{}; - assert(len(array) > 0); - res := array[len(array)-1]; - (^raw.Dynamic_Array)(array).len -= 1; - return res; -} - clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) { if array != nil do (^raw.Dynamic_Array)(array).len = 0; } -clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) { - if m == nil do return; - raw_map := (^raw.Map)(m); - hashes := (^raw.Dynamic_Array)(&raw_map.hashes); - entries := (^raw.Dynamic_Array)(&raw_map.entries); - hashes.len = 0; - entries.len = 0; -} - -clear :: proc[clear_dynamic_array, clear_map]; reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool { if array == nil do return false; @@ -412,409 +434,9 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal } -__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> __Map_Header { - header := __Map_Header{m = (^raw.Map)(m)}; - Entry :: struct { - key: __Map_Key, - next: int, - value: V, - } - - _, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String); - header.is_key_string = is_string; - header.entry_size = int(size_of(Entry)); - header.entry_align = int(align_of(Entry)); - header.value_offset = uintptr(offset_of(Entry, value)); - header.value_size = int(size_of(V)); - return header; -} - -__get_map_key :: proc "contextless" (key: $K) -> __Map_Key { - map_key: __Map_Key; - ti := type_info_base_without_enum(type_info_of(K)); - switch _ in ti.variant { - case Type_Info_Integer: - switch 8*size_of(key) { - case 8: map_key.hash = u64(( ^u8)(&key)^); - case 16: map_key.hash = u64(( ^u16)(&key)^); - case 32: map_key.hash = u64(( ^u32)(&key)^); - case 64: map_key.hash = u64(( ^u64)(&key)^); - case: panic("Unhandled integer size"); - } - case Type_Info_Rune: - map_key.hash = u64((^rune)(&key)^); - case Type_Info_Pointer: - map_key.hash = u64(uintptr((^rawptr)(&key)^)); - case Type_Info_Float: - switch 8*size_of(key) { - case 32: map_key.hash = u64((^u32)(&key)^); - case 64: map_key.hash = u64((^u64)(&key)^); - case: panic("Unhandled float size"); - } - case Type_Info_String: - str := (^string)(&key)^; - map_key.hash = __default_hash_string(str); - map_key.str = str; - case: - panic("Unhandled map key type"); - } - return map_key; -} - -reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) { - if m != nil do __dynamic_map_reserve(__get_map_header(m), capacity); -} - -delete :: proc(m: ^$T/map[$K]$V, key: K) { - if m != nil do __dynamic_map_delete(__get_map_header(m), __get_map_key(key)); -} - -reserve :: proc[reserve_dynamic_array, reserve_map]; -new :: inline proc(T: type, loc := #caller_location) -> ^T { - ptr := (^T)(alloc(size_of(T), align_of(T), loc)); - ptr^ = T{}; - return ptr; -} -new_clone :: inline proc(data: $T, loc := #caller_location) -> ^T { - ptr := (^T)(alloc(size_of(T), align_of(T), loc)); - ptr^ = data; - return ptr; -} - -free_string :: proc(str: string, loc := #caller_location) { - free_ptr(raw.data(str), loc); -} -free_cstring :: proc(str: cstring, loc := #caller_location) { - free_ptr((^byte)(str), loc); -} -free_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) { - free_ptr(raw.data(array), loc); -} -free_slice :: proc(array: $T/[]$E, loc := #caller_location) { - free_ptr(raw.data(array), loc); -} -free_map :: proc(m: $T/map[$K]$V, loc := #caller_location) { - raw := transmute(raw.Map)m; - free_dynamic_array(raw.hashes, loc); - free_ptr(raw.entries.data, loc); -} - -free :: proc[ - free_ptr, - free_string, free_cstring, - free_dynamic_array, free_slice, free_map, -]; - - -// NOTE(bill): This code works but I will prefer having `make` a built-in procedure -// to have better error messages -/* -make :: proc(T: type/[]$E, len: int, using loc := #caller_location) -> T { - cap := len; - __slice_expr_error(file_path, int(line), int(column), 0, len, cap); - data := cast(^E)alloc(len * size_of(E), align_of(E)); - for i in 0..len do (data+i)^ = E{}; - s := raw.Slice{data = data, len = len}; - return (cast(^T)&s)^; -} -make :: proc(T: type/[dynamic]$E, len: int = 8, using loc := #caller_location) -> T { - cap := len; - __slice_expr_error(file_path, int(line), int(column), 0, len, cap); - data := cast(^E)alloc(cap * size_of(E), align_of(E)); - for i in 0..len do (data+i)^ = E{}; - s := raw.Dynamic_Array{data = data, len = len, cap = cap, allocator = context.allocator}; - return (cast(^T)&s)^; -} -make :: proc(T: type/[dynamic]$E, len, cap: int, using loc := #caller_location) -> T { - __slice_expr_error(file_path, int(line), int(column), 0, len, cap); - data := cast(^E)alloc(cap * size_of(E), align_of(E)); - for i in 0..len do (data+i)^ = E{}; - s := raw.Dynamic_Array{data = data, len = len, cap = cap, allocator = context.allocator}; - return (cast(^T)&s)^; -} - -make :: proc(T: type/map[$K]$V, cap: int = 16, using loc := #caller_location) -> T { - if cap < 0 do cap = 16; - - m: T; - header := __get_map_header(&m); - __dynamic_map_reserve(header, cap); - return m; -} -*/ - - - -default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr { - if old_memory == nil do return alloc(new_size, alignment, loc); - - if new_size == 0 { - free(old_memory, loc); - return nil; - } - - if new_size == old_size do return old_memory; - - new_memory := alloc(new_size, alignment, loc); - if new_memory == nil do return nil; - - __mem_copy(new_memory, old_memory, min(old_size, new_size));; - free(old_memory, loc); - return new_memory; -} - - -default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { - using Allocator_Mode; - - switch mode { - case Alloc: - return os.heap_alloc(size); - - case Free: - os.heap_free(old_memory); - return nil; - - case Free_All: - // NOTE(bill): Does nothing - - case Resize: - ptr := os.heap_resize(old_memory, size); - assert(ptr != nil); - return ptr; - } - - return nil; -} - -default_allocator :: proc() -> Allocator { - return Allocator{ - procedure = default_allocator_proc, - data = nil, - }; -} - -nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { - return nil; -} - -nil_allocator :: proc() -> Allocator { - return Allocator{ - procedure = nil_allocator_proc, - data = nil, - }; -} - - -__print_u64 :: proc(fd: os.Handle, u: u64) { - digits := "0123456789"; - - a: [129]byte; - i := len(a); - b := u64(10); - for u >= b { - i -= 1; a[i] = digits[u % b]; - u /= b; - } - i -= 1; a[i] = digits[u % b]; - - os.write(fd, a[i..]); -} - -__print_i64 :: proc(fd: os.Handle, u: i64) { - digits := "0123456789"; - - neg := u < 0; - u = abs(u); - - a: [129]byte; - i := len(a); - b := i64(10); - for u >= b { - i -= 1; a[i] = digits[u % b]; - u /= b; - } - i -= 1; a[i] = digits[u % b]; - if neg { - i -= 1; a[i] = '-'; - } - - os.write(fd, a[i..]); -} - -__print_caller_location :: proc(fd: os.Handle, using loc: Source_Code_Location) { - os.write_string(fd, file_path); - os.write_byte(fd, '('); - __print_u64(fd, u64(line)); - os.write_byte(fd, ':'); - __print_u64(fd, u64(column)); - os.write_byte(fd, ')'); -} -__print_typeid :: proc(fd: os.Handle, id: typeid) { - ti := type_info_of(id); - __print_type(fd, ti); -} -__print_type :: proc(fd: os.Handle, ti: ^Type_Info) { - if ti == nil { - os.write_string(fd, "nil"); - return; - } - - switch info in ti.variant { - case Type_Info_Named: - os.write_string(fd, info.name); - case Type_Info_Integer: - a := any{typeid = typeid_of(ti)}; - switch _ in a { - case int: os.write_string(fd, "int"); - case uint: os.write_string(fd, "uint"); - case uintptr: os.write_string(fd, "uintptr"); - case: - os.write_byte(fd, info.signed ? 'i' : 'u'); - __print_u64(fd, u64(8*ti.size)); - } - case Type_Info_Rune: - os.write_string(fd, "rune"); - case Type_Info_Float: - os.write_byte(fd, 'f'); - __print_u64(fd, u64(8*ti.size)); - case Type_Info_Complex: - os.write_string(fd, "complex"); - __print_u64(fd, u64(8*ti.size)); - case Type_Info_String: - os.write_string(fd, "string"); - case Type_Info_Boolean: - a := any{typeid = typeid_of(ti)}; - switch _ in a { - case bool: os.write_string(fd, "bool"); - case: - os.write_byte(fd, 'b'); - __print_u64(fd, u64(8*ti.size)); - } - case Type_Info_Any: - os.write_string(fd, "any"); - case Type_Info_Type_Id: - os.write_string(fd, "typeid"); - - case Type_Info_Pointer: - if info.elem == nil { - os.write_string(fd, "rawptr"); - } else { - os.write_string(fd, "^"); - __print_type(fd, info.elem); - } - case Type_Info_Procedure: - os.write_string(fd, "proc"); - if info.params == nil { - os.write_string(fd, "()"); - } else { - t := info.params.variant.(Type_Info_Tuple); - os.write_string(fd, "("); - for t, i in t.types { - if i > 0 do os.write_string(fd, ", "); - __print_type(fd, t); - } - os.write_string(fd, ")"); - } - if info.results != nil { - os.write_string(fd, " -> "); - __print_type(fd, info.results); - } - case Type_Info_Tuple: - count := len(info.names); - if count != 1 do os.write_string(fd, "("); - for name, i in info.names { - if i > 0 do os.write_string(fd, ", "); - - t := info.types[i]; - - if len(name) > 0 { - os.write_string(fd, name); - os.write_string(fd, ": "); - } - __print_type(fd, t); - } - if count != 1 do os.write_string(fd, ")"); - - case Type_Info_Array: - os.write_string(fd, "["); - __print_u64(fd, u64(info.count)); - os.write_string(fd, "]"); - __print_type(fd, info.elem); - case Type_Info_Dynamic_Array: - os.write_string(fd, "[dynamic]"); - __print_type(fd, info.elem); - case Type_Info_Slice: - os.write_string(fd, "[]"); - __print_type(fd, info.elem); - - case Type_Info_Map: - os.write_string(fd, "map["); - __print_type(fd, info.key); - os.write_byte(fd, ']'); - __print_type(fd, info.value); - - case Type_Info_Struct: - os.write_string(fd, "struct "); - if info.is_packed do os.write_string(fd, "#packed "); - if info.is_raw_union do os.write_string(fd, "#raw_union "); - if info.custom_align { - os.write_string(fd, "#align "); - __print_u64(fd, u64(ti.align)); - os.write_byte(fd, ' '); - } - os.write_byte(fd, '{'); - for name, i in info.names { - if i > 0 do os.write_string(fd, ", "); - os.write_string(fd, name); - os.write_string(fd, ": "); - __print_type(fd, info.types[i]); - } - os.write_byte(fd, '}'); - - case Type_Info_Union: - os.write_string(fd, "union {"); - for variant, i in info.variants { - if i > 0 do os.write_string(fd, ", "); - __print_type(fd, variant); - } - os.write_string(fd, "}"); - - case Type_Info_Enum: - os.write_string(fd, "enum "); - __print_type(fd, info.base); - os.write_string(fd, " {"); - for name, i in info.names { - if i > 0 do os.write_string(fd, ", "); - os.write_string(fd, name); - } - os.write_string(fd, "}"); - - case Type_Info_Bit_Field: - os.write_string(fd, "bit_field "); - if ti.align != 1 { - os.write_string(fd, "#align "); - __print_u64(fd, u64(ti.align)); - os.write_byte(fd, ' '); - } - os.write_string(fd, " {"); - for name, i in info.names { - if i > 0 do os.write_string(fd, ", "); - os.write_string(fd, name); - os.write_string(fd, ": "); - __print_u64(fd, u64(info.bits[i])); - } - os.write_string(fd, "}"); - } -} - assert :: proc "contextless" (condition: bool, message := "", using loc := #caller_location) -> bool { if !condition { @@ -844,262 +466,8 @@ panic :: proc "contextless" (message := "", using loc := #caller_location) { } -buffer_from_slice :: proc(backing: $T/[]$E) -> [dynamic]E { - s := transmute(raw.Slice)backing; - d := raw.Dynamic_Array{ - data = s.data, - len = 0, - cap = s.len, - allocator = nil_allocator(), - }; - return transmute([dynamic]E)d; -} - - - - - - - - - - - - - - -__string_eq :: proc "contextless" (a, b: string) -> bool { - switch { - case len(a) != len(b): return false; - case len(a) == 0: return true; - case &a[0] == &b[0]: return true; - } - return __string_cmp(a, b) == 0; -} - -__string_cmp :: proc "contextless" (a, b: string) -> int { - return __mem_compare(&a[0], &b[0], min(len(a), len(b))); -} - -__string_ne :: inline proc "contextless" (a, b: string) -> bool { return !__string_eq(a, b); } -__string_lt :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) < 0; } -__string_gt :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) > 0; } -__string_le :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) <= 0; } -__string_ge :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) >= 0; } - -__cstring_len :: proc "contextless" (s: cstring) -> int { - n := 0; - for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) { - n += 1; - } - return n; -} - -__cstring_to_string :: proc "contextless" (s: cstring) -> string { - if s == nil do return ""; - ptr := (^byte)(s); - n := __cstring_len(s); - return transmute(string)raw.String{ptr, n}; -} - - -__complex64_eq :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) == real(b) && imag(a) == imag(b); } -__complex64_ne :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) != real(b) || imag(a) != imag(b); } - -__complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) == real(b) && imag(a) == imag(b); } -__complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); } - - -__bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) { - if 0 <= index && index < count do return; - - fd := os.stderr; - __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); - os.write_string(fd, " Index "); - __print_i64(fd, i64(index)); - os.write_string(fd, " is out of bounds range 0.."); - __print_i64(fd, i64(count)); - os.write_byte(fd, '\n'); - __debug_trap(); -} - -__slice_expr_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) { - if 0 <= lo && lo <= hi && hi <= len do return; - - - fd := os.stderr; - __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); - os.write_string(fd, " Invalid slice indices: "); - __print_i64(fd, i64(lo)); - os.write_string(fd, ".."); - __print_i64(fd, i64(hi)); - os.write_string(fd, ".."); - __print_i64(fd, i64(len)); - os.write_byte(fd, '\n'); - __debug_trap(); -} - -__dynamic_array_expr_error :: proc "contextless" (file: string, line, column: int, low, high, max: int) { - if 0 <= low && low <= high && high <= max do return; - - fd := os.stderr; - __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); - os.write_string(fd, " Invalid dynamic array values: "); - __print_i64(fd, i64(low)); - os.write_string(fd, ".."); - __print_i64(fd, i64(high)); - os.write_string(fd, ".."); - __print_i64(fd, i64(max)); - os.write_byte(fd, '\n'); - __debug_trap(); -} - -__type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: int, from, to: typeid) { - if ok do return; - - fd := os.stderr; - __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); - os.write_string(fd, " Invalid type assertion from"); - __print_typeid(fd, from); - os.write_string(fd, " to "); - __print_typeid(fd, to); - os.write_byte(fd, '\n'); - __debug_trap(); -} - -__string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) { - return utf8.decode_rune_from_string(s); -} - -__bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) { - __bounds_check_error(file_path, int(line), int(column), index, count); -} -__slice_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) { - __slice_expr_error(file_path, int(line), int(column), lo, hi, len); -} - -__mem_set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr { - if data == nil do return nil; - foreign __llvm_core { - when size_of(rawptr) == 8 { - @(link_name="llvm.memset.p0i8.i64") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; - } else { - @(link_name="llvm.memset.p0i8.i32") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; - } - } - llvm_memset(data, byte(value), len, 1, false); - return data; -} -__mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { - return __mem_set(data, 0, len); -} -__mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { - if src == nil do return dst; - // NOTE(bill): This _must_ be implemented like C's memmove - foreign __llvm_core { - when size_of(rawptr) == 8 { - @(link_name="llvm.memmove.p0i8.p0i8.i64") - llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; - } else { - @(link_name="llvm.memmove.p0i8.p0i8.i32") - llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; - } - } - llvm_memmove(dst, src, len, 1, false); - return dst; -} -__mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { - if src == nil do return dst; - // NOTE(bill): This _must_ be implemented like C's memcpy - foreign __llvm_core { - when size_of(rawptr) == 8 { - @(link_name="llvm.memcpy.p0i8.p0i8.i64") - llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; - } else { - @(link_name="llvm.memcpy.p0i8.p0i8.i32") - llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; - } - } - llvm_memcpy(dst, src, len, 1, false); - return dst; -} - -__mem_compare :: proc "contextless" (a, b: ^byte, n: int) -> int { - pa :: mem.ptr_offset; - for i in 0..n do switch { - case pa(a, i)^ < pa(b, i)^: return -1; - case pa(a, i)^ > pa(b, i)^: return +1; - } - return 0; -} - -@(default_calling_convention = "c") -foreign __llvm_core { - @(link_name="llvm.sqrt.f32") __sqrt_f32 :: proc(x: f32) -> f32 ---; - @(link_name="llvm.sqrt.f64") __sqrt_f64 :: proc(x: f64) -> f64 ---; - - @(link_name="llvm.sin.f32") __sin_f32 :: proc(θ: f32) -> f32 ---; - @(link_name="llvm.sin.f64") __sin_f64 :: proc(θ: f64) -> f64 ---; - - @(link_name="llvm.cos.f32") __cos_f32 :: proc(θ: f32) -> f32 ---; - @(link_name="llvm.cos.f64") __cos_f64 :: proc(θ: f64) -> f64 ---; - - @(link_name="llvm.pow.f32") __pow_f32 :: proc(x, power: f32) -> f32 ---; - @(link_name="llvm.pow.f64") __pow_f64 :: proc(x, power: f64) -> f64 ---; - - @(link_name="llvm.fmuladd.f32") fmuladd32 :: proc(a, b, c: f32) -> f32 ---; - @(link_name="llvm.fmuladd.f64") fmuladd64 :: proc(a, b, c: f64) -> f64 ---; -} -__abs_f32 :: inline proc "contextless" (x: f32) -> f32 { - foreign __llvm_core { - @(link_name="llvm.fabs.f32") _abs :: proc "c" (x: f32) -> f32 ---; - } - return _abs(x); -} -__abs_f64 :: inline proc "contextless" (x: f64) -> f64 { - foreign __llvm_core { - @(link_name="llvm.fabs.f64") _abs :: proc "c" (x: f64) -> f64 ---; - } - return _abs(x); -} - -__min_f32 :: proc(a, b: f32) -> f32 { - foreign __llvm_core { - @(link_name="llvm.minnum.f32") _min :: proc "c" (a, b: f32) -> f32 ---; - } - return _min(a, b); -} -__min_f64 :: proc(a, b: f64) -> f64 { - foreign __llvm_core { - @(link_name="llvm.minnum.f64") _min :: proc "c" (a, b: f64) -> f64 ---; - } - return _min(a, b); -} -__max_f32 :: proc(a, b: f32) -> f32 { - foreign __llvm_core { - @(link_name="llvm.maxnum.f32") _max :: proc "c" (a, b: f32) -> f32 ---; - } - return _max(a, b); -} -__max_f64 :: proc(a, b: f64) -> f64 { - foreign __llvm_core { - @(link_name="llvm.maxnum.f64") _max :: proc "c" (a, b: f64) -> f64 ---; - } - return _max(a, b); -} - -__abs_complex64 :: inline proc "contextless" (x: complex64) -> f32 { - r, i := real(x), imag(x); - return __sqrt_f32(r*r + i*i); -} -__abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 { - r, i := real(x), imag(x); - return __sqrt_f64(r*r + i*i); -} - +// Dynamic Array __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) { @@ -1127,7 +495,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: new_size := cap * elem_size; allocator := array.allocator; - new_data := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0, loc); + new_data := allocator.procedure(allocator.data, mem.Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0, loc); if new_data == nil do return false; array.data = new_data; @@ -1186,7 +554,60 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in return array.len; } -// Map stuff + + + +// Map + +__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> __Map_Header { + header := __Map_Header{m = (^raw.Map)(m)}; + Entry :: struct { + key: __Map_Key, + next: int, + value: V, + } + + _, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String); + header.is_key_string = is_string; + header.entry_size = int(size_of(Entry)); + header.entry_align = int(align_of(Entry)); + header.value_offset = uintptr(offset_of(Entry, value)); + header.value_size = int(size_of(V)); + return header; +} + +__get_map_key :: proc "contextless" (key: $K) -> __Map_Key { + map_key: __Map_Key; + ti := type_info_base_without_enum(type_info_of(K)); + switch _ in ti.variant { + case Type_Info_Integer: + switch 8*size_of(key) { + case 8: map_key.hash = u64(( ^u8)(&key)^); + case 16: map_key.hash = u64(( ^u16)(&key)^); + case 32: map_key.hash = u64(( ^u32)(&key)^); + case 64: map_key.hash = u64(( ^u64)(&key)^); + case: panic("Unhandled integer size"); + } + case Type_Info_Rune: + map_key.hash = u64((^rune)(&key)^); + case Type_Info_Pointer: + map_key.hash = u64(uintptr((^rawptr)(&key)^)); + case Type_Info_Float: + switch 8*size_of(key) { + case 32: map_key.hash = u64((^u32)(&key)^); + case 64: map_key.hash = u64((^u64)(&key)^); + case: panic("Unhandled float size"); + } + case Type_Info_String: + str := (^string)(&key)^; + map_key.hash = __default_hash_string(str); + map_key.str = str; + case: + panic("Unhandled map key type"); + } + return map_key; +} + __default_hash :: proc(data: []byte) -> u64 { fnv64a :: proc(data: []byte) -> u64 { @@ -1238,8 +659,8 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int, loc := if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc); } - free_ptr_with_allocator(header_hashes.allocator, header_hashes.data, loc); - free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data, loc); + mem.free_ptr_with_allocator(header_hashes.allocator, header_hashes.data, loc); + mem.free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data, loc); header.m^ = nm; } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin new file mode 100644 index 000000000..47f56997c --- /dev/null +++ b/core/runtime/internal.odin @@ -0,0 +1,432 @@ +package runtime + +import "core:raw" +import "core:mem" +import "core:os" +import "core:unicode/utf8" + + +__print_u64 :: proc(fd: os.Handle, u: u64) { + digits := "0123456789"; + + a: [129]byte; + i := len(a); + b := u64(10); + for u >= b { + i -= 1; a[i] = digits[u % b]; + u /= b; + } + i -= 1; a[i] = digits[u % b]; + + os.write(fd, a[i..]); +} + +__print_i64 :: proc(fd: os.Handle, u: i64) { + digits := "0123456789"; + + neg := u < 0; + u = abs(u); + + a: [129]byte; + i := len(a); + b := i64(10); + for u >= b { + i -= 1; a[i] = digits[u % b]; + u /= b; + } + i -= 1; a[i] = digits[u % b]; + if neg { + i -= 1; a[i] = '-'; + } + + os.write(fd, a[i..]); +} + +__print_caller_location :: proc(fd: os.Handle, using loc: Source_Code_Location) { + os.write_string(fd, file_path); + os.write_byte(fd, '('); + __print_u64(fd, u64(line)); + os.write_byte(fd, ':'); + __print_u64(fd, u64(column)); + os.write_byte(fd, ')'); +} +__print_typeid :: proc(fd: os.Handle, id: typeid) { + ti := type_info_of(id); + __print_type(fd, ti); +} +__print_type :: proc(fd: os.Handle, ti: ^Type_Info) { + if ti == nil { + os.write_string(fd, "nil"); + return; + } + + switch info in ti.variant { + case Type_Info_Named: + os.write_string(fd, info.name); + case Type_Info_Integer: + a := any{typeid = typeid_of(ti)}; + switch _ in a { + case int: os.write_string(fd, "int"); + case uint: os.write_string(fd, "uint"); + case uintptr: os.write_string(fd, "uintptr"); + case: + os.write_byte(fd, info.signed ? 'i' : 'u'); + __print_u64(fd, u64(8*ti.size)); + } + case Type_Info_Rune: + os.write_string(fd, "rune"); + case Type_Info_Float: + os.write_byte(fd, 'f'); + __print_u64(fd, u64(8*ti.size)); + case Type_Info_Complex: + os.write_string(fd, "complex"); + __print_u64(fd, u64(8*ti.size)); + case Type_Info_String: + os.write_string(fd, "string"); + case Type_Info_Boolean: + a := any{typeid = typeid_of(ti)}; + switch _ in a { + case bool: os.write_string(fd, "bool"); + case: + os.write_byte(fd, 'b'); + __print_u64(fd, u64(8*ti.size)); + } + case Type_Info_Any: + os.write_string(fd, "any"); + case Type_Info_Type_Id: + os.write_string(fd, "typeid"); + + case Type_Info_Pointer: + if info.elem == nil { + os.write_string(fd, "rawptr"); + } else { + os.write_string(fd, "^"); + __print_type(fd, info.elem); + } + case Type_Info_Procedure: + os.write_string(fd, "proc"); + if info.params == nil { + os.write_string(fd, "()"); + } else { + t := info.params.variant.(Type_Info_Tuple); + os.write_string(fd, "("); + for t, i in t.types { + if i > 0 do os.write_string(fd, ", "); + __print_type(fd, t); + } + os.write_string(fd, ")"); + } + if info.results != nil { + os.write_string(fd, " -> "); + __print_type(fd, info.results); + } + case Type_Info_Tuple: + count := len(info.names); + if count != 1 do os.write_string(fd, "("); + for name, i in info.names { + if i > 0 do os.write_string(fd, ", "); + + t := info.types[i]; + + if len(name) > 0 { + os.write_string(fd, name); + os.write_string(fd, ": "); + } + __print_type(fd, t); + } + if count != 1 do os.write_string(fd, ")"); + + case Type_Info_Array: + os.write_string(fd, "["); + __print_u64(fd, u64(info.count)); + os.write_string(fd, "]"); + __print_type(fd, info.elem); + case Type_Info_Dynamic_Array: + os.write_string(fd, "[dynamic]"); + __print_type(fd, info.elem); + case Type_Info_Slice: + os.write_string(fd, "[]"); + __print_type(fd, info.elem); + + case Type_Info_Map: + os.write_string(fd, "map["); + __print_type(fd, info.key); + os.write_byte(fd, ']'); + __print_type(fd, info.value); + + case Type_Info_Struct: + os.write_string(fd, "struct "); + if info.is_packed do os.write_string(fd, "#packed "); + if info.is_raw_union do os.write_string(fd, "#raw_union "); + if info.custom_align { + os.write_string(fd, "#align "); + __print_u64(fd, u64(ti.align)); + os.write_byte(fd, ' '); + } + os.write_byte(fd, '{'); + for name, i in info.names { + if i > 0 do os.write_string(fd, ", "); + os.write_string(fd, name); + os.write_string(fd, ": "); + __print_type(fd, info.types[i]); + } + os.write_byte(fd, '}'); + + case Type_Info_Union: + os.write_string(fd, "union {"); + for variant, i in info.variants { + if i > 0 do os.write_string(fd, ", "); + __print_type(fd, variant); + } + os.write_string(fd, "}"); + + case Type_Info_Enum: + os.write_string(fd, "enum "); + __print_type(fd, info.base); + os.write_string(fd, " {"); + for name, i in info.names { + if i > 0 do os.write_string(fd, ", "); + os.write_string(fd, name); + } + os.write_string(fd, "}"); + + case Type_Info_Bit_Field: + os.write_string(fd, "bit_field "); + if ti.align != 1 { + os.write_string(fd, "#align "); + __print_u64(fd, u64(ti.align)); + os.write_byte(fd, ' '); + } + os.write_string(fd, " {"); + for name, i in info.names { + if i > 0 do os.write_string(fd, ", "); + os.write_string(fd, name); + os.write_string(fd, ": "); + __print_u64(fd, u64(info.bits[i])); + } + os.write_string(fd, "}"); + } +} + +__string_eq :: proc "contextless" (a, b: string) -> bool { + switch { + case len(a) != len(b): return false; + case len(a) == 0: return true; + case &a[0] == &b[0]: return true; + } + return __string_cmp(a, b) == 0; +} + +__string_cmp :: proc "contextless" (a, b: string) -> int { + return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b))); +} + +__string_ne :: inline proc "contextless" (a, b: string) -> bool { return !__string_eq(a, b); } +__string_lt :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) < 0; } +__string_gt :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) > 0; } +__string_le :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) <= 0; } +__string_ge :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) >= 0; } + +__cstring_len :: proc "contextless" (s: cstring) -> int { + n := 0; + for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) { + n += 1; + } + return n; +} + +__cstring_to_string :: proc "contextless" (s: cstring) -> string { + if s == nil do return ""; + ptr := (^byte)(s); + n := __cstring_len(s); + return transmute(string)raw.String{ptr, n}; +} + + +__complex64_eq :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) == real(b) && imag(a) == imag(b); } +__complex64_ne :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) != real(b) || imag(a) != imag(b); } + +__complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) == real(b) && imag(a) == imag(b); } +__complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); } + + +__bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) { + if 0 <= index && index < count do return; + + fd := os.stderr; + __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); + os.write_string(fd, " Index "); + __print_i64(fd, i64(index)); + os.write_string(fd, " is out of bounds range 0.."); + __print_i64(fd, i64(count)); + os.write_byte(fd, '\n'); + __debug_trap(); +} + +__slice_expr_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) { + if 0 <= lo && lo <= hi && hi <= len do return; + + + fd := os.stderr; + __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); + os.write_string(fd, " Invalid slice indices: "); + __print_i64(fd, i64(lo)); + os.write_string(fd, ".."); + __print_i64(fd, i64(hi)); + os.write_string(fd, ".."); + __print_i64(fd, i64(len)); + os.write_byte(fd, '\n'); + __debug_trap(); +} + +__dynamic_array_expr_error :: proc "contextless" (file: string, line, column: int, low, high, max: int) { + if 0 <= low && low <= high && high <= max do return; + + fd := os.stderr; + __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); + os.write_string(fd, " Invalid dynamic array values: "); + __print_i64(fd, i64(low)); + os.write_string(fd, ".."); + __print_i64(fd, i64(high)); + os.write_string(fd, ".."); + __print_i64(fd, i64(max)); + os.write_byte(fd, '\n'); + __debug_trap(); +} + +__type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: int, from, to: typeid) { + if ok do return; + + fd := os.stderr; + __print_caller_location(fd, Source_Code_Location{file, line, column, ""}); + os.write_string(fd, " Invalid type assertion from"); + __print_typeid(fd, from); + os.write_string(fd, " to "); + __print_typeid(fd, to); + os.write_byte(fd, '\n'); + __debug_trap(); +} + +__string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) { + return utf8.decode_rune_from_string(s); +} + +__bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) { + __bounds_check_error(file_path, int(line), int(column), index, count); +} +__slice_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) { + __slice_expr_error(file_path, int(line), int(column), lo, hi, len); +} + +__mem_set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr { + if data == nil do return nil; + foreign __llvm_core { + when size_of(rawptr) == 8 { + @(link_name="llvm.memset.p0i8.i64") + llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; + } else { + @(link_name="llvm.memset.p0i8.i32") + llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; + } + } + llvm_memset(data, byte(value), len, 1, false); + return data; +} +__mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { + return __mem_set(data, 0, len); +} +__mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { + if src == nil do return dst; + // NOTE(bill): This _must_ be implemented like C's memmove + foreign __llvm_core { + when size_of(rawptr) == 8 { + @(link_name="llvm.memmove.p0i8.p0i8.i64") + llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + } else { + @(link_name="llvm.memmove.p0i8.p0i8.i32") + llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + } + } + llvm_memmove(dst, src, len, 1, false); + return dst; +} +__mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { + if src == nil do return dst; + // NOTE(bill): This _must_ be implemented like C's memcpy + foreign __llvm_core { + when size_of(rawptr) == 8 { + @(link_name="llvm.memcpy.p0i8.p0i8.i64") + llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + } else { + @(link_name="llvm.memcpy.p0i8.p0i8.i32") + llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + } + } + llvm_memcpy(dst, src, len, 1, false); + return dst; +} + + +@(default_calling_convention = "c") +foreign __llvm_core { + @(link_name="llvm.sqrt.f32") __sqrt_f32 :: proc(x: f32) -> f32 ---; + @(link_name="llvm.sqrt.f64") __sqrt_f64 :: proc(x: f64) -> f64 ---; + + @(link_name="llvm.sin.f32") __sin_f32 :: proc(θ: f32) -> f32 ---; + @(link_name="llvm.sin.f64") __sin_f64 :: proc(θ: f64) -> f64 ---; + + @(link_name="llvm.cos.f32") __cos_f32 :: proc(θ: f32) -> f32 ---; + @(link_name="llvm.cos.f64") __cos_f64 :: proc(θ: f64) -> f64 ---; + + @(link_name="llvm.pow.f32") __pow_f32 :: proc(x, power: f32) -> f32 ---; + @(link_name="llvm.pow.f64") __pow_f64 :: proc(x, power: f64) -> f64 ---; + + @(link_name="llvm.fmuladd.f32") fmuladd32 :: proc(a, b, c: f32) -> f32 ---; + @(link_name="llvm.fmuladd.f64") fmuladd64 :: proc(a, b, c: f64) -> f64 ---; +} +__abs_f32 :: inline proc "contextless" (x: f32) -> f32 { + foreign __llvm_core { + @(link_name="llvm.fabs.f32") _abs :: proc "c" (x: f32) -> f32 ---; + } + return _abs(x); +} +__abs_f64 :: inline proc "contextless" (x: f64) -> f64 { + foreign __llvm_core { + @(link_name="llvm.fabs.f64") _abs :: proc "c" (x: f64) -> f64 ---; + } + return _abs(x); +} + +__min_f32 :: proc(a, b: f32) -> f32 { + foreign __llvm_core { + @(link_name="llvm.minnum.f32") _min :: proc "c" (a, b: f32) -> f32 ---; + } + return _min(a, b); +} +__min_f64 :: proc(a, b: f64) -> f64 { + foreign __llvm_core { + @(link_name="llvm.minnum.f64") _min :: proc "c" (a, b: f64) -> f64 ---; + } + return _min(a, b); +} +__max_f32 :: proc(a, b: f32) -> f32 { + foreign __llvm_core { + @(link_name="llvm.maxnum.f32") _max :: proc "c" (a, b: f32) -> f32 ---; + } + return _max(a, b); +} +__max_f64 :: proc(a, b: f64) -> f64 { + foreign __llvm_core { + @(link_name="llvm.maxnum.f64") _max :: proc "c" (a, b: f64) -> f64 ---; + } + return _max(a, b); +} + +__abs_complex64 :: inline proc "contextless" (x: complex64) -> f32 { + r, i := real(x), imag(x); + return __sqrt_f32(r*r + i*i); +} +__abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 { + r, i := real(x), imag(x); + return __sqrt_f64(r*r + i*i); +} diff --git a/core/builtin/_soft_numbers.odin b/core/runtime/soft_numbers.odin similarity index 99% rename from core/builtin/_soft_numbers.odin rename to core/runtime/soft_numbers.odin index b925eddea..92ec2bfec 100644 --- a/core/builtin/_soft_numbers.odin +++ b/core/runtime/soft_numbers.odin @@ -1,4 +1,4 @@ -package builtin +package runtime /* @(link_name="__multi3") diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 798b94bb8..6e8df52c3 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -351,6 +351,7 @@ String path_to_fullpath(gbAllocator a, String s) { defer (gb_mutex_unlock(&string_buffer_mutex)); 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[0], 0, nullptr, nullptr); @@ -359,8 +360,9 @@ String path_to_fullpath(gbAllocator a, String s) { GetFullPathNameW(&string16[0], len, text, nullptr); text[len] = 0; result = string16_to_string(a, make_string16(text, len)); + result = string_trim_whitespace(result); } - gb_temp_arena_memory_end(tmp); + return result; } #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9e7e2da60..b7a8c2cfc 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1565,25 +1565,25 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { if (is_type_string(x->type) || is_type_string(y->type)) { switch (op) { - case Token_CmpEq: add_preload_dependency(c, "__string_eq"); break; - case Token_NotEq: add_preload_dependency(c, "__string_ne"); break; - case Token_Lt: add_preload_dependency(c, "__string_lt"); break; - case Token_Gt: add_preload_dependency(c, "__string_gt"); break; - case Token_LtEq: add_preload_dependency(c, "__string_le"); break; - case Token_GtEq: add_preload_dependency(c, "__string_gt"); break; + case Token_CmpEq: add_package_dependency(c, "runtime", "__string_eq"); break; + case Token_NotEq: add_package_dependency(c, "runtime", "__string_ne"); break; + case Token_Lt: add_package_dependency(c, "runtime", "__string_lt"); break; + case Token_Gt: add_package_dependency(c, "runtime", "__string_gt"); break; + case Token_LtEq: add_package_dependency(c, "runtime", "__string_le"); break; + case Token_GtEq: add_package_dependency(c, "runtime", "__string_gt"); break; } } else if (is_type_complex(x->type) || is_type_complex(y->type)) { switch (op) { case Token_CmpEq: switch (8*size) { - case 64: add_preload_dependency(c, "__complex64_eq"); break; - case 128: add_preload_dependency(c, "__complex128_eq"); break; + case 64: add_package_dependency(c, "runtime", "__complex64_eq"); break; + case 128: add_package_dependency(c, "runtime", "__complex128_eq"); break; } break; case Token_NotEq: switch (8*size) { - case 64: add_preload_dependency(c, "__complex64_ne"); break; - case 128: add_preload_dependency(c, "__complex128_ne"); break; + case 64: add_package_dependency(c, "runtime", "__complex64_ne"); break; + case 128: add_package_dependency(c, "runtime", "__complex128_ne"); break; } break; } @@ -1845,7 +1845,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { // cstring -> string if (src == t_cstring && dst == t_string) { if (operand->mode != Addressing_Constant) { - add_preload_dependency(c, "__cstring_to_string"); + add_package_dependency(c, "runtime", "__cstring_to_string"); } return true; } @@ -2949,7 +2949,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } else { mode = Addressing_Value; if (is_type_cstring(op_type)) { - add_preload_dependency(c, "__cstring_len"); + add_package_dependency(c, "runtime", "__cstring_len"); } } } else if (is_type_array(op_type)) { @@ -3052,15 +3052,15 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (is_type_slice(type)) { min_args = 2; max_args = 2; - add_preload_dependency(c, "alloc"); + add_package_dependency(c, "mem", "alloc"); } else if (is_type_map(type)) { min_args = 1; max_args = 2; - add_preload_dependency(c, "__dynamic_map_reserve"); + add_package_dependency(c, "runtime", "__dynamic_map_reserve"); } else if (is_type_dynamic_array(type)) { min_args = 1; max_args = 3; - add_preload_dependency(c, "__dynamic_array_make"); + add_package_dependency(c, "runtime", "__dynamic_array_make"); } else { gbString str = type_to_string(type); error(call, "Cannot 'make' %s; type must be a slice, map, or dynamic array", str); @@ -3416,7 +3416,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id add_type_info_type(c, t); if (is_operand_value(o) && is_type_typeid(t)) { - add_preload_dependency(c, "__type_info_of"); + add_package_dependency(c, "runtime", "__type_info_of"); } else if (o.mode != Addressing_Type) { error(expr, "Expected a type or typeid for 'type_info_of'"); return false; @@ -3452,7 +3452,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id t = base_type(t); if (is_operand_value(o) && are_types_identical(t, t_type_info_ptr)) { - add_preload_dependency(c, "__typeid_of"); + add_package_dependency(c, "runtime", "__typeid_of"); } else if (o.mode != Addressing_Type) { error(expr, "Expected a type or type info for 'typeid_of'"); return false; @@ -3802,8 +3802,8 @@ break; { Type *bt = base_type(a.type); - if (bt == t_f32) add_preload_dependency(c, "__min_f32"); - if (bt == t_f64) add_preload_dependency(c, "__min_f64"); + if (bt == t_f32) add_package_dependency(c, "runtime", "__min_f32"); + if (bt == t_f64) add_package_dependency(c, "runtime", "__min_f64"); } } @@ -3879,8 +3879,8 @@ break; { Type *bt = base_type(a.type); - if (bt == t_f32) add_preload_dependency(c, "__max_f32"); - if (bt == t_f64) add_preload_dependency(c, "__max_f64"); + if (bt == t_f32) add_package_dependency(c, "runtime", "__max_f32"); + if (bt == t_f64) add_package_dependency(c, "runtime", "__max_f64"); } } @@ -3921,10 +3921,10 @@ break; { Type *bt = base_type(operand->type); - if (bt == t_f32) add_preload_dependency(c, "__abs_f32"); - if (bt == t_f64) add_preload_dependency(c, "__abs_f64"); - if (bt == t_complex64) add_preload_dependency(c, "__abs_complex64"); - if (bt == t_complex128) add_preload_dependency(c, "__abs_complex128"); + if (bt == t_f32) add_package_dependency(c, "runtime", "__abs_f32"); + if (bt == t_f64) add_package_dependency(c, "runtime", "__abs_f64"); + if (bt == t_complex64) add_package_dependency(c, "runtime", "__abs_complex64"); + if (bt == t_complex128) add_package_dependency(c, "runtime", "__abs_complex128"); } } @@ -4025,12 +4025,12 @@ break; { Type *bt = base_type(x.type); if (bt == t_f32) { - add_preload_dependency(c, "__min_f32"); - add_preload_dependency(c, "__max_f32"); + add_package_dependency(c, "runtime", "__min_f32"); + add_package_dependency(c, "runtime", "__max_f32"); } if (bt == t_f64) { - add_preload_dependency(c, "__min_f64"); - add_preload_dependency(c, "__max_f64"); + add_package_dependency(c, "runtime", "__min_f64"); + add_package_dependency(c, "runtime", "__max_f64"); } } } @@ -5643,8 +5643,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t context_name = str_lit("dynamic array literal"); is_constant = false; - add_preload_dependency(c, "__dynamic_array_reserve"); - add_preload_dependency(c, "__dynamic_array_append"); + add_package_dependency(c, "runtime", "__dynamic_array_reserve"); + add_package_dependency(c, "runtime", "__dynamic_array_append"); } else { GB_PANIC("unreachable"); } @@ -5803,8 +5803,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } } - add_preload_dependency(c, "__dynamic_map_reserve"); - add_preload_dependency(c, "__dynamic_map_set"); + add_package_dependency(c, "runtime", "__dynamic_map_reserve"); + add_package_dependency(c, "runtime", "__dynamic_map_set"); break; } @@ -5927,7 +5927,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return kind; } - add_preload_dependency(c, "__type_assertion_check"); + add_package_dependency(c, "runtime", "__type_assertion_check"); case_end; case_ast_node(tc, TypeCast, node); @@ -6027,8 +6027,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t o->type = t->Map.value; o->expr = node; - add_preload_dependency(c, "__dynamic_map_get"); - add_preload_dependency(c, "__dynamic_map_set"); + add_package_dependency(c, "runtime", "__dynamic_map_get"); + add_package_dependency(c, "runtime", "__dynamic_map_set"); return Expr_Expr; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 4c47385cc..e5096cf02 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1415,7 +1415,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (is_type_string(t)) { val0 = t_rune; val1 = t_int; - add_preload_dependency(c, "__string_decode_rune"); + add_package_dependency(c, "runtime", "__string_decode_rune"); } break; case Type_Array: diff --git a/src/check_type.cpp b/src/check_type.cpp index ca961c133..77a794326 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1733,7 +1733,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { type->Map.value = value; if (is_type_string(key)) { - add_preload_dependency(c, "__default_hash_string"); + add_package_dependency(c, "runtime", "__default_hash_string"); } diff --git a/src/checker.cpp b/src/checker.cpp index 4d1b2c46a..b4fab10bc 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -258,7 +258,7 @@ Scope *create_scope_from_package(Checker *c, AstPackage *p) { s->is_init = p->kind == Package_Init; } - if (p->kind == Package_Builtin) { + if (p->kind == Package_Runtime) { s->is_global = true; universal_scope->shared = s; } @@ -479,9 +479,21 @@ void add_type_info_dependency(DeclInfo *d, Type *type) { ptr_set_add(&d->type_info_deps, type); } -void add_preload_dependency(Checker *c, char *name) { +AstPackage *get_core_package(CheckerInfo *info, String name) { + gbAllocator a = heap_allocator(); + String path = get_fullpath_core(a, name); + defer (gb_free(a, path.text)); + HashKey key = hash_string(path); + auto found = map_get(&info->packages, key); + GB_ASSERT_MSG(found != nullptr, "Missing core package %.*s", LIT(name)); + return *found; +} + + +void add_package_dependency(Checker *c, char *package_name, char *name) { String n = make_string_c(name); - Entity *e = scope_lookup_entity(c->builtin_package->scope, n); + AstPackage *p = get_core_package(&c->info, make_string_c(package_name)); + Entity *e = scope_lookup_entity(p->scope, n); GB_ASSERT(e != nullptr); ptr_set_add(&c->context.decl->deps, e); // add_type_info_type(c, e->type); @@ -913,6 +925,7 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn GB_ASSERT(identifier->kind == AstNode_Ident); GB_ASSERT(e != nullptr && d != nullptr); GB_ASSERT(identifier->Ident.token.string == e->token.string); + if (e->scope != nullptr) { Scope *scope = e->scope; if (scope->is_file) { @@ -924,22 +937,21 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn default: { AstPackage *p = scope->file->package; GB_ASSERT(p->scope == scope->parent); + GB_ASSERT(c->context.package == p); scope = p->scope; - if (e->package != nullptr) { - GB_ASSERT(e->package == p); - } - e->package = p; break; } } } add_entity(c, scope, identifier, e); } + add_entity_definition(&c->info, identifier, e); GB_ASSERT(e->decl_info == nullptr); e->decl_info = d; array_add(&c->info.entities, e); e->order_in_src = c->info.entities.count; + e->package = c->context.package; } @@ -1141,10 +1153,11 @@ void add_curr_ast_file(Checker *c, AstFile *file) { if (file != nullptr) { TokenPos zero_pos = {}; global_error_collector.prev = zero_pos; - c->curr_ast_file = file; - c->context.decl = file->package->decl_info; - c->context.scope = file->scope; - c->context.package_scope = file->package->scope; + c->curr_ast_file = file; + c->context.decl = file->package->decl_info; + c->context.scope = file->scope; + c->context.package = file->package; + c->context.package_scope = file->package->scope; } } @@ -1331,14 +1344,14 @@ void add_dependency_to_set(Checker *c, Entity *entity) { } } + void generate_minimum_dependency_set(Checker *c, Entity *start) { ptr_set_init(&c->info.minimum_dependency_set, heap_allocator()); ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator()); - String required_entities[] = { + String required_builtin_entities[] = { str_lit("__mem_zero"), str_lit("__init_context"), - str_lit("default_allocator"), str_lit("__args__"), str_lit("__type_table"), @@ -1348,8 +1361,16 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("Allocator"), str_lit("Context"), }; - for (isize i = 0; i < gb_count_of(required_entities); i++) { - add_dependency_to_set(c, scope_lookup_entity(c->builtin_package->scope, required_entities[i])); + for (isize i = 0; i < gb_count_of(required_builtin_entities); i++) { + add_dependency_to_set(c, scope_lookup_entity(c->runtime_package->scope, required_builtin_entities[i])); + } + + AstPackage *mem = get_core_package(&c->info, str_lit("mem")); + String required_mem_entities[] = { + str_lit("default_allocator"), + }; + for (isize i = 0; i < gb_count_of(required_mem_entities); i++) { + add_dependency_to_set(c, scope_lookup_entity(mem->scope, required_mem_entities[i])); } if (!build_context.no_bounds_check) { @@ -1359,7 +1380,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("__dynamic_array_expr_error"), }; for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { - add_dependency_to_set(c, scope_lookup_entity(c->builtin_package->scope, bounds_check_entities[i])); + add_dependency_to_set(c, scope_lookup_entity(c->runtime_package->scope, bounds_check_entities[i])); } } @@ -1479,7 +1500,7 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { Entity *find_core_entity(Checker *c, String name) { - Entity *e = current_scope_lookup_entity(c->builtin_package->scope, name); + Entity *e = current_scope_lookup_entity(c->runtime_package->scope, name); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" "Is '_preload.odin' missing from the 'core' directory relative to odin.exe?", LIT(name)); @@ -1489,7 +1510,7 @@ Entity *find_core_entity(Checker *c, String name) { } Type *find_core_type(Checker *c, String name) { - Entity *e = current_scope_lookup_entity(c->builtin_package->scope, name); + Entity *e = current_scope_lookup_entity(c->runtime_package->scope, name); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" "Is '_preload.odin' missing from the 'core' directory relative to odin.exe?", LIT(name)); @@ -1605,7 +1626,8 @@ void init_preload(Checker *c) { } if (t_allocator == nullptr) { - Entity *e = find_core_entity(c, str_lit("Allocator")); + AstPackage *mem = get_core_package(&c->info, str_lit("mem")); + Entity *e = scope_lookup_entity(mem->scope, str_lit("Allocator")); t_allocator = e->type; t_allocator_ptr = alloc_type_pointer(t_allocator); } @@ -2118,6 +2140,8 @@ void check_add_foreign_block_decl(Checker *c, AstNode *decl) { void check_collect_entities(Checker *c, Array nodes) { for_array(decl_index, nodes) { AstNode *decl = nodes[decl_index]; + if (c->context.scope->is_file) { + } if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) { if (c->context.scope->is_file && decl->kind == AstNode_ExprStmt) { @@ -2204,7 +2228,6 @@ void check_all_global_entities(Checker *c) { } - GB_ASSERT(d->scope->is_file); AstFile *file = d->scope->file; add_curr_ast_file(c, file); @@ -2222,7 +2245,6 @@ void check_all_global_entities(Checker *c) { } } - CheckerContext prev_context = c->context; c->context.decl = d; c->context.scope = d->scope; @@ -2394,8 +2416,8 @@ Array generate_import_dependency_graph(Checker *c) { // Calculate edges for graph M for_array(i, c->parser->packages) { AstPackage *p = c->parser->packages[i]; - for_array(j, p->files.entries) { - AstFile *f = p->files.entries[j].value; + for_array(j, p->files) { + AstFile *f = p->files[j]; for_array(k, f->decls) { AstNode *decl = f->decls[k]; add_import_dependency_node(c, decl, &M); @@ -2441,8 +2463,8 @@ Array find_import_path(Checker *c, Scope *start, Scope *end, Ptr AstPackage *p = (*found)->package; GB_ASSERT(p != nullptr); - for_array(i, p->files.entries) { - AstFile *f = p->files.entries[i].value; + for_array(i, p->files) { + AstFile *f = p->files[i]; for_array(j, f->imports) { Scope *s = nullptr; AstNode *decl = f->imports[j]; @@ -2707,8 +2729,8 @@ void check_import_entities(Checker *c) { GB_ASSERT(node->scope->is_package); AstPackage *p = node->scope->package; - for_array(i, p->files.entries) { - AstFile *f = p->files.entries[i].value; + for_array(i, p->files) { + AstFile *f = p->files[i]; CheckerContext prev_context = c->context; defer (c->context = prev_context); add_curr_ast_file(c, f); @@ -2719,8 +2741,8 @@ void check_import_entities(Checker *c) { } } - for_array(i, p->files.entries) { - AstFile *f = p->files.entries[i].value; + for_array(i, p->files) { + AstFile *f = p->files[i]; CheckerContext prev_context = c->context; defer (c->context = prev_context); add_curr_ast_file(c, f); @@ -2903,9 +2925,9 @@ void check_parsed_files(Checker *c) { if (scope->is_init) { c->info.init_scope = scope; } - if (p->kind == Package_Builtin) { - GB_ASSERT(c->builtin_package == nullptr); - c->builtin_package = p; + if (p->kind == Package_Runtime) { + GB_ASSERT(c->runtime_package == nullptr); + c->runtime_package = p; } } @@ -2914,8 +2936,8 @@ void check_parsed_files(Checker *c) { for_array(i, c->parser->packages) { AstPackage *p = c->parser->packages[i]; CheckerContext prev_context = c->context; - for_array(j, p->files.entries) { - AstFile *f = p->files.entries[j].value; + for_array(j, p->files) { + AstFile *f = p->files[j]; create_scope_from_file(c, f); HashKey key = hash_string(f->fullpath); map_set(&c->info.files, key, f); @@ -3029,8 +3051,8 @@ void check_parsed_files(Checker *c) { token.pos.file = s->package->fullpath; token.pos.line = 1; token.pos.column = 1; - if (s->package->files.entries.count > 0) { - AstFile *f = s->package->files.entries[0].value; + if (s->package->files.count > 0) { + AstFile *f = s->package->files[0]; if (f->tokens.count > 0) { token = f->tokens[0]; } diff --git a/src/checker.hpp b/src/checker.hpp index f4ea5b45f..079a8acac 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -274,15 +274,16 @@ struct ForeignContext { typedef Array CheckerTypePath; struct CheckerContext { - Scope * package_scope; - Scope * scope; - DeclInfo * decl; - u32 stmt_state_flags; - bool in_defer; // TODO(bill): Actually handle correctly - String proc_name; - Type * type_hint; - DeclInfo * curr_proc_decl; - Type * curr_proc_sig; + AstPackage * package; + Scope * package_scope; + Scope * scope; + DeclInfo * decl; + u32 stmt_state_flags; + bool in_defer; // TODO(bill): Actually handle correctly + String proc_name; + Type * type_hint; + DeclInfo * curr_proc_decl; + Type * curr_proc_sig; ForeignContext foreign_context; CheckerTypePath *type_path; @@ -312,7 +313,6 @@ struct CheckerInfo { Array type_info_types; Map type_info_map; // Key: Type * - Scope * init_scope; Entity * entry_point; PtrSet minimum_dependency_set; @@ -326,7 +326,7 @@ struct Checker { AstFile * curr_ast_file; - AstPackage * builtin_package; + AstPackage * runtime_package; // NOTE(bill): Procedures to check Array procs; Map package_scopes; // Key: String (fullpath) diff --git a/src/ir.cpp b/src/ir.cpp index ff364602b..0afc0f8f1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1532,7 +1532,9 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na // //////////////////////////////////////////////////////////////// -irValue *ir_emit_global_call(irProcedure *proc, char const *name_, Array args, AstNode *expr = nullptr); +irValue *ir_emit_global_call (irProcedure *proc, char const *name_, Array args, AstNode *expr = nullptr); +irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array args, AstNode *expr = nullptr); + irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) { Type *a = type_deref(ir_type(address)); @@ -1632,7 +1634,7 @@ irValue *ir_find_or_generate_context_ptr(irProcedure *proc) { irValue *ep = ir_emit_struct_ep(proc, c, 0); Array args = {}; - irValue *v = ir_emit_global_call(proc, "default_allocator", args); + irValue *v = ir_emit_package_call(proc, "mem", "default_allocator", args); ir_emit_store(proc, ep, v); return c; @@ -1706,6 +1708,19 @@ irValue *ir_emit_global_call(irProcedure *proc, char const *name_, Array args, AstNode *expr) { + String name = make_string_c(cast(char *)name_); + String package_name = make_string_c(cast(char *)package_name_); + + AstPackage *p = get_core_package(proc->module->info, package_name); + Entity *e = current_scope_lookup_entity(p->scope, name); + irValue **found = map_get(&proc->module->values, hash_entity(e)); + GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name)); + irValue *gp = *found; + irValue *call = ir_emit_call(proc, gp, args); + ir_add_debug_location_to_value(proc, call, expr); + return call; +} @@ -3755,9 +3770,10 @@ void ir_emit_dynamic_array_bounds_check(irProcedure *proc, Token token, irValue // //////////////////////////////////////////////////////////////// -String ir_mangle_name(irGen *s, String path, Entity *e) { +String ir_mangle_name(irGen *s, Entity *e) { // NOTE(bill): prefix names not in the init scope // TODO(bill): make robust and not just rely on the file's name + String path = e->token.pos.file; String name = e->token.string; irModule *m = &s->module; CheckerInfo *info = m->info; @@ -4307,7 +4323,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv args[0] = slice_size; args[1] = elem_align; args[2] = ir_emit_source_code_location(proc, proc_name, pos); - irValue *call = ir_emit_global_call(proc, "alloc", args); + irValue *call = ir_emit_package_call(proc, "mem", "alloc", args); irValue *ptr = ir_emit_conv(proc, call, elem_ptr_type); irValue *slice = ir_add_local_generated(proc, type); @@ -8318,7 +8334,7 @@ void ir_gen_tree(irGen *s) { String name = e->token.string; if (!no_name_mangle) { - name = ir_mangle_name(s, e->token.pos.file, e); + name = ir_mangle_name(s, e); } ir_add_entity_name(m, e, name); @@ -8390,7 +8406,7 @@ void ir_gen_tree(irGen *s) { } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { // Handle later } else { - name = ir_mangle_name(s, e->token.pos.file, e); + name = ir_mangle_name(s, e); } } ir_add_entity_name(m, e, name); diff --git a/src/main.cpp b/src/main.cpp index 733e45c30..4dd8b3983 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -578,7 +578,7 @@ void show_timings(Checker *c, Timings *t) { isize files = 0; isize packages = p->packages.count; for_array(i, p->packages) { - files += p->packages[i]->files.entries.count; + files += p->packages[i]->files.count; } { diff --git a/src/parser.cpp b/src/parser.cpp index ceb7f5c6f..ebdeeba65 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -60,6 +60,7 @@ Token ast_node_token(AstNode *node) { case AstNode_Label: return node->Label.token; case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names[0]); + case AstNode_PackageDecl: return node->PackageDecl.token; case AstNode_ImportDecl: return node->ImportDecl.token; case AstNode_ForeignImportDecl: return node->ForeignImportDecl.token; @@ -998,6 +999,15 @@ AstNode *ast_value_decl(AstFile *f, Array names, AstNode *type, Array return result; } +AstNode *ast_package_decl(AstFile *f, Token token, Token name, CommentGroup docs, CommentGroup comment) { + AstNode *result = make_ast_node(f, AstNode_PackageDecl); + result->PackageDecl.token = token; + result->PackageDecl.name = name; + result->PackageDecl.docs = docs; + result->PackageDecl.comment = comment; + return result; +} + AstNode *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Token import_name, CommentGroup docs, CommentGroup comment) { AstNode *result = make_ast_node(f, AstNode_ImportDecl); @@ -1307,6 +1317,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) { case AstNode_ProcLit: return s->ProcLit.body != nullptr; + case AstNode_PackageDecl: case AstNode_ImportDecl: case AstNode_ForeignImportDecl: return true; @@ -3887,10 +3898,10 @@ void destroy_parser(Parser *p) { // TODO(bill): Fix memory leak for_array(i, p->packages) { AstPackage *package = p->packages[i]; - for_array(j, package->files.entries) { - destroy_ast_file(package->files.entries[j].value); + for_array(j, package->files) { + destroy_ast_file(package->files[j]); } - map_destroy(&package->files); + array_free(&package->files); } #if 0 for_array(i, p->imports) { @@ -4101,12 +4112,12 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Arraytokens.count == 0) { - return; + return true; } if (f->tokens.count > 0 && f->tokens[0].kind == Token_EOF) { - return; + return true; } String filepath = f->tokenizer.fullpath; @@ -4121,23 +4132,30 @@ void parse_file(Parser *p, AstFile *f) { comsume_comment_groups(f, f->prev_token); + CommentGroup docs = f->lead_comment; + f->package_token = expect_token(f, Token_package); Token package_name = expect_token_after(f, Token_Ident, "package"); if (package_name.kind == Token_Ident) { if (package_name.string == "_") { error(package_name, "Invalid package name '_'"); - } else if (f->package->kind != Package_Builtin && package_name.string == "builtin") { + } else if (f->package->kind != Package_Runtime && package_name.string == "runtime") { error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); } } f->package_name = package_name.string; + AstNode *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment); + expect_semicolon(f, pd); + if (f->error_count > 0) { - return; + return false; } f->decls = parse_stmt_list(f); parse_setup_file_decls(p, f, base_dir, f->decls); + + return true; } @@ -4195,38 +4213,41 @@ ParseFileError parse_imported_file(Parser *p, AstPackage *package, FileInfo *fi, skip: - parse_file(p, file); + if (parse_file(p, file)) { + gb_mutex_lock(&p->file_add_mutex); + array_add(&package->files, file); - gb_mutex_lock(&p->file_add_mutex); - HashKey key = hash_string(fi->fullpath); - map_set(&package->files, key, file); + if (package->name.len == 0) { + package->name = file->package_name; + } else if (file->tokens.count > 0 && package->name != file->package_name) { + error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(package->name), LIT(file->package_name)); + } - if (package->name.len == 0) { - package->name = file->package_name; - } else if (file->tokens.count > 0 && package->name != file->package_name) { - error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(package->name), LIT(file->package_name)); + p->total_line_count += file->tokenizer.line_count; + p->total_token_count += file->tokens.count; + gb_mutex_unlock(&p->file_add_mutex); } - - p->total_line_count += file->tokenizer.line_count; - p->total_token_count += file->tokens.count; - gb_mutex_unlock(&p->file_add_mutex); - return ParseFile_None; } +void parser_add_package(Parser *p, AstPackage *package) { + package->id = p->packages.count+1; + array_add(&p->packages, package); +} + ParseFileError parse_import(Parser *p, ImportedPackage imported_package) { String import_path = imported_package.path; String import_rel_path = imported_package.rel_path; TokenPos pos = imported_package.pos; - String const ext = str_lit(".odin"); + String const file_ext = str_lit(".odin"); // NOTE(bill): Single file initial package - if (imported_package.kind == Package_Init && string_ends_with(import_path, ext)) { + if (imported_package.kind == Package_Init && string_ends_with(import_path, file_ext)) { AstPackage *package = gb_alloc_item(heap_allocator(), AstPackage); package->kind = imported_package.kind; package->fullpath = import_path; - map_init(&package->files, heap_allocator()); + array_init(&package->files, heap_allocator()); FileInfo fi = {}; fi.name = filename_from_path(import_path); @@ -4239,12 +4260,12 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) { return err; } - package->id = p->packages.count+1; - array_add(&p->packages, package); + parser_add_package(p, package); return ParseFile_None; } + Array list = {}; ReadDirectoryError rd_err = read_directory(import_path, &list); defer (array_free(&list)); @@ -4253,6 +4274,7 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) { GB_ASSERT(import_path != list[0].fullpath); } + if (rd_err != ReadDirectory_None) { if (pos.line != 0) { gb_printf_err("%.*s(%td:%td) ", LIT(pos.file), pos.line, pos.column); @@ -4291,13 +4313,13 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) { AstPackage *package = gb_alloc_item(heap_allocator(), AstPackage); package->kind = imported_package.kind; package->fullpath = import_path; - map_init(&package->files, heap_allocator()); + array_init(&package->files, heap_allocator()); // TODO(bill): Fix concurrency - for_array(i, list) { - FileInfo *fi = &list[i]; + for_array(list_index, list) { + FileInfo *fi = &list[list_index]; String name = fi->name; - if (string_ends_with(name, ext)) { + if (string_ends_with(name, file_ext)) { if (is_excluded_target_filename(name)) { continue; } @@ -4308,9 +4330,7 @@ ParseFileError parse_import(Parser *p, ImportedPackage imported_package) { } } - package->id = p->packages.count+1; - array_add(&p->packages, package); - + parser_add_package(p, package); return ParseFile_None; } @@ -4348,8 +4368,8 @@ ParseFileError parse_packages(Parser *p, String init_filename) { isize shared_package_count = 0; if (!build_context.generate_docs) { - String s = get_fullpath_core(heap_allocator(), str_lit("builtin")); - try_add_import_path(p, s, s, init_pos, Package_Builtin); + String s = get_fullpath_core(heap_allocator(), str_lit("runtime")); + try_add_import_path(p, s, s, init_pos, Package_Runtime); shared_package_count++; } diff --git a/src/parser.hpp b/src/parser.hpp index 3f8b13cb4..a2c10c81a 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -27,7 +27,7 @@ struct CommentGroup { enum PackageKind { Package_Normal, - Package_Builtin, + Package_Runtime, Package_Init, }; @@ -85,11 +85,11 @@ struct AstFile { struct AstPackage { - isize id; - PackageKind kind; - String name; - String fullpath; - Map files; // Key: String (names) + isize id; + PackageKind kind; + String name; + String fullpath; + Array files; Scope * scope; // NOTE(bill): Created in checker DeclInfo *decl_info; // NOTE(bill): Created in checker @@ -356,6 +356,12 @@ AST_NODE_KIND(_DeclBegin, "", struct {}) \ bool is_mutable; \ bool been_handled; \ }) \ + AST_NODE_KIND(PackageDecl, "package declaration", struct { \ + Token token; \ + Token name; \ + CommentGroup docs; \ + CommentGroup comment; \ + }) \ AST_NODE_KIND(ImportDecl, "import declaration", struct { \ AstPackage *package; \ Token token; \