mirror of
https://github.com/Ed94/WATL_Exercise.git
synced 2025-11-08 17:49:18 -08:00
Compare commits
21 Commits
2ff49a188d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bd9d2b3a7b | |||
| f5330c686b | |||
| a48681fc00 | |||
| acb5e916c1 | |||
| 5a44788b4a | |||
| dbb1367acb | |||
| aab3a3f689 | |||
| d7790795dd | |||
| ac05262c8d | |||
| 3bb46692e1 | |||
| a7d17a8b70 | |||
| 7aaf617b3c | |||
| 5e3e8970d8 | |||
| 8269ea9cc5 | |||
| d9bce18ccb | |||
| 3554615244 | |||
| aad7b59179 | |||
| 9179f77f05 | |||
| 816ed5debd | |||
| 81328819c6 | |||
| f437be32e2 |
@@ -1,2 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
661
C/watl.v0.msvc.c
661
C/watl.v0.msvc.c
File diff suppressed because it is too large
Load Diff
61
Odin/watl.v0.ideomatic.odin
Normal file
61
Odin/watl.v0.ideomatic.odin
Normal file
@@ -0,0 +1,61 @@
|
||||
package watl
|
||||
|
||||
import "core:os/os2"
|
||||
import "core:mem/virtual"
|
||||
import "core:mem"
|
||||
|
||||
|
||||
main :: proc()
|
||||
{
|
||||
os_init()
|
||||
|
||||
// Note(Ed): Possible compiler bug, cannot resolve proc map with named arguments.
|
||||
|
||||
vm_file: virtual.Arena; virtual.arena_init_static(& vm_file, reserved = mem.Gigabytes * 4)
|
||||
data, err := os2.read_entire_file_from_path("watl.v0.ideomatic.odin", virtual.arena_allocator(& vm_file), )
|
||||
assert(err != .None)
|
||||
|
||||
|
||||
|
||||
a_msgs := arena_make()
|
||||
a_toks := arena_make()
|
||||
// lex_res := watl_lex(transmute(string) file.content,
|
||||
// ainfo_msgs = ainfo(a_msgs),
|
||||
// ainfo_toks = ainfo(a_toks),
|
||||
// )
|
||||
lex_res := watl_lex(transmute(string) file.content,
|
||||
ainfo(a_msgs),
|
||||
ainfo(a_toks),
|
||||
)
|
||||
assert(lex_res.signal & { .MemFail_SliceConstraintFail } == {})
|
||||
|
||||
str8_cache_kt1_ainfo := arena_make()
|
||||
str_cache := str8cache_make(
|
||||
str_reserve = ainfo(arena_make()),
|
||||
cell_reserve = ainfo(str8_cache_kt1_ainfo),
|
||||
tbl_backing = ainfo(str8_cache_kt1_ainfo),
|
||||
cell_pool_size = Kilo * 4,
|
||||
table_size = Kilo * 32,
|
||||
)
|
||||
|
||||
a_lines := arena_make()
|
||||
// parse_res := watl_parse(lex_res.toks,
|
||||
// ainfo_msgs = ainfo(a_msgs),
|
||||
// ainfo_nodes = ainfo(a_toks),
|
||||
// ainfo_lines = ainfo(a_lines),
|
||||
// str_cache = & str_cache
|
||||
// )
|
||||
parse_res := watl_parse(lex_res.toks,
|
||||
ainfo(a_msgs),
|
||||
ainfo(a_toks),
|
||||
ainfo(a_lines),
|
||||
& str_cache
|
||||
)
|
||||
assert(parse_res.signal & { .MemFail_SliceConstraintFail } == {})
|
||||
|
||||
arena_reset(a_msgs)
|
||||
arena_reset(a_toks)
|
||||
listing := watl_dump_listing(ainfo(a_msgs), parse_res.lines)
|
||||
file_write_str8("watl.v0.win32.odin.listing.txt", listing)
|
||||
return
|
||||
}
|
||||
@@ -100,23 +100,14 @@ align_pow2 :: #force_inline proc(x: int, b: int) -> int {
|
||||
assert((b & (b - 1)) == 0) // Check power of 2
|
||||
return ((x + b - 1) & ~(b - 1))
|
||||
}
|
||||
memory_zero :: #force_inline proc "contextless" (data: rawptr, len: int) -> rawptr {
|
||||
intrinsics.mem_zero(data, len)
|
||||
return data
|
||||
}
|
||||
memory_zero :: #force_inline proc "contextless" (data: rawptr, len: int) -> rawptr { intrinsics.mem_zero(data, len); return data }
|
||||
memory_zero_explicit :: #force_inline proc "contextless" (data: rawptr, len: int) -> rawptr {
|
||||
intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero
|
||||
intrinsics.atomic_thread_fence(.Seq_Cst) // Prevent reordering
|
||||
return data
|
||||
}
|
||||
memory_copy_overlapping :: #force_inline proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
intrinsics.mem_copy(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
memory_copy :: #force_inline proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
intrinsics.mem_copy_non_overlapping(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
memory_copy_overlapping :: #force_inline proc "contextless" (dst, src: rawptr, len: int) -> rawptr { intrinsics.mem_copy(dst, src, len); return dst }
|
||||
memory_copy :: #force_inline proc "contextless" (dst, src: rawptr, len: int) -> rawptr { intrinsics.mem_copy_non_overlapping(dst, src, len); return dst }
|
||||
|
||||
sll_stack_push_n :: proc "contextless" (curr, n, n_link: ^^$Type) {
|
||||
(n_link ^) = (curr ^)
|
||||
@@ -136,22 +127,14 @@ sll_queue_push_nz :: proc "contextless" (first: ^$ParentType, last, n: ^^$Type,
|
||||
}
|
||||
sll_queue_push_n :: #force_inline proc "contextless" (first: $ParentType, last, n: ^^$Type) { sll_queue_push_nz(first, last, n, nil) }
|
||||
|
||||
SliceByte :: struct {
|
||||
data: [^]byte,
|
||||
len: int
|
||||
}
|
||||
SliceRaw :: struct ($Type: typeid) {
|
||||
data: [^]Type,
|
||||
len: int,
|
||||
}
|
||||
SliceByte :: struct { data: [^]byte, len: int }
|
||||
SliceRaw :: struct($Type: typeid) { data: [^]Type, len: int, }
|
||||
slice :: #force_inline proc "contextless" (s: [^] $Type, num: $Some_Integer) -> [ ]Type { return transmute([]Type) SliceRaw(Type) { s, cast(int) num } }
|
||||
slice_cursor :: #force_inline proc "contextless" (s: []$Type) -> [^]Type { return transmute([^]Type) raw_data(s) }
|
||||
slice_assert :: #force_inline proc (s: $SliceType / []$Type) {
|
||||
assert(len(s) > 0)
|
||||
assert(s != nil)
|
||||
}
|
||||
slice_end :: #force_inline proc "contextless" (s : $SliceType / []$Type) -> ^Type { return & cursor(s)[len(s)] }
|
||||
|
||||
slice_assert :: #force_inline proc (s: $SliceType / []$Type) { assert(len(s) > 0); assert(s != nil) }
|
||||
|
||||
@(require_results) slice_to_bytes :: proc "contextless" (s: []$Type) -> []byte { return ([^]byte)(raw_data(s))[:len(s) * size_of(Type)] }
|
||||
@(require_results) slice_raw :: proc "contextless" (s: []$Type) -> SliceRaw(Type) { return transmute(SliceRaw(Type)) s }
|
||||
|
||||
@@ -270,8 +253,7 @@ mem_alloc :: proc(ainfo: AllocatorInfo, size: int, alignment: int = MEMORY_ALIGN
|
||||
requested_size = size,
|
||||
alignment = alignment,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
ainfo.procedure(input, & output)
|
||||
output: AllocatorProc_Out; ainfo.procedure(input, & output)
|
||||
return output.allocation
|
||||
}
|
||||
mem_grow :: proc(ainfo: AllocatorInfo, mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, give_actual: b32 = false) -> []byte {
|
||||
@@ -283,8 +265,7 @@ mem_grow :: proc(ainfo: AllocatorInfo, mem: []byte, size: int, alignment: int =
|
||||
alignment = alignment,
|
||||
old_allocation = mem,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
ainfo.procedure(input, & output)
|
||||
output: AllocatorProc_Out; ainfo.procedure(input, & output)
|
||||
return slice(cursor(output.allocation), give_actual ? len(output.allocation) : size)
|
||||
}
|
||||
mem_resize :: proc(ainfo: AllocatorInfo, mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, give_actual: b32 = false) -> []byte {
|
||||
@@ -296,8 +277,7 @@ mem_resize :: proc(ainfo: AllocatorInfo, mem: []byte, size: int, alignment: int
|
||||
alignment = alignment,
|
||||
old_allocation = mem,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
ainfo.procedure(input, & output)
|
||||
output: AllocatorProc_Out; ainfo.procedure(input, & output)
|
||||
return slice(cursor(output.allocation), give_actual ? len(output.allocation) : size)
|
||||
}
|
||||
mem_shrink :: proc(ainfo: AllocatorInfo, mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false) -> []byte {
|
||||
@@ -309,8 +289,7 @@ mem_shrink :: proc(ainfo: AllocatorInfo, mem: []byte, size: int, alignment: int
|
||||
alignment = alignment,
|
||||
old_allocation = mem,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
ainfo.procedure(input, & output)
|
||||
output: AllocatorProc_Out; ainfo.procedure(input, & output)
|
||||
return output.allocation
|
||||
}
|
||||
|
||||
@@ -322,8 +301,7 @@ alloc_type :: proc(ainfo: AllocatorInfo, $Type: typeid, alignment: int = MEMORY
|
||||
requested_size = size_of(Type),
|
||||
alignment = alignment,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
ainfo.procedure(input, & output)
|
||||
output: AllocatorProc_Out; ainfo.procedure(input, & output)
|
||||
return transmute(^Type) raw_data(output.allocation)
|
||||
}
|
||||
alloc_slice :: proc(ainfo: AllocatorInfo, $SliceType: typeid / []$Type, num : int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false) -> []Type {
|
||||
@@ -334,17 +312,13 @@ alloc_slice :: proc(ainfo: AllocatorInfo, $SliceType: typeid / []$Type, num : in
|
||||
requested_size = size_of(Type) * num,
|
||||
alignment = alignment,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
ainfo.procedure(input, & output)
|
||||
output: AllocatorProc_Out; ainfo.procedure(input, & output)
|
||||
return transmute([]Type) slice(raw_data(output.allocation), num)
|
||||
}
|
||||
//endregion Allocator Interface
|
||||
|
||||
//region Strings
|
||||
Raw_String :: struct {
|
||||
data: [^]byte,
|
||||
len: int,
|
||||
}
|
||||
Raw_String :: struct { data: [^]byte, len: int, }
|
||||
string_cursor :: proc(s: string) -> [^]u8 { return slice_cursor(transmute([]byte) s) }
|
||||
string_copy :: proc(dst, src: string) { slice_copy (transmute([]byte) dst, transmute([]byte) src) }
|
||||
string_end :: proc(s: string) -> ^u8 { return slice_end (transmute([]byte) s) }
|
||||
@@ -356,10 +330,7 @@ FArena :: struct {
|
||||
mem: []byte,
|
||||
used: int,
|
||||
}
|
||||
farena_make :: proc(backing: []byte) -> FArena {
|
||||
arena := FArena {mem = backing}
|
||||
return arena
|
||||
}
|
||||
farena_make :: proc(backing: []byte) -> FArena { return {mem = backing} }
|
||||
farena_init :: proc(arena: ^FArena, backing: []byte) {
|
||||
assert(arena != nil)
|
||||
arena.mem = backing
|
||||
@@ -367,20 +338,15 @@ farena_init :: proc(arena: ^FArena, backing: []byte) {
|
||||
}
|
||||
farena_push :: proc(arena: ^FArena, $Type: typeid, amount: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT) -> []Type {
|
||||
assert(arena != nil)
|
||||
if amount == 0 {
|
||||
return {}
|
||||
}
|
||||
if amount == 0 { return {} }
|
||||
desired := size_of(Type) * amount
|
||||
to_commit := align_pow2(desired, alignment)
|
||||
unused := len(arena.mem) - arena.used
|
||||
assert(to_commit <= unused)
|
||||
unused := len(arena.mem) - arena.used; assert(to_commit <= unused)
|
||||
ptr := cursor(arena.mem[arena.used:])
|
||||
arena.used += to_commit
|
||||
return slice(ptr, amount)
|
||||
}
|
||||
farena_reset :: proc(arena: ^FArena) {
|
||||
arena.used = 0
|
||||
}
|
||||
farena_reset :: #force_inline proc(arena: ^FArena) { arena.used = 0 }
|
||||
farena_rewind :: proc(arena: ^FArena, save_point: AllocatorSP) {
|
||||
assert(save_point.type_sig == farena_allocator_proc)
|
||||
assert(save_point.slot >= 0 && save_point.slot <= arena.used)
|
||||
@@ -391,7 +357,6 @@ farena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Ou
|
||||
assert(output != nil)
|
||||
assert(input.data != nil)
|
||||
arena := transmute(^FArena) input.data
|
||||
|
||||
switch input.op
|
||||
{
|
||||
case .Alloc, .Alloc_NoZero:
|
||||
@@ -400,11 +365,8 @@ farena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Ou
|
||||
zero(output.allocation)
|
||||
}
|
||||
|
||||
case .Free:
|
||||
// No-op for arena
|
||||
|
||||
case .Reset:
|
||||
farena_reset(arena)
|
||||
case .Free: // No-op for arena
|
||||
case .Reset: farena_reset(arena)
|
||||
|
||||
case .Grow, .Grow_NoZero:
|
||||
// Check if the allocation is at the end of the arena
|
||||
@@ -453,11 +415,8 @@ farena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Ou
|
||||
arena.used -= (aligned_original - aligned_new)
|
||||
output.allocation = input.old_allocation[:input.requested_size]
|
||||
|
||||
case .Rewind:
|
||||
farena_rewind(arena, input.save_point)
|
||||
|
||||
case .SavePoint:
|
||||
output.save_point = farena_save(arena^)
|
||||
case .Rewind: farena_rewind(arena, input.save_point)
|
||||
case .SavePoint: output.save_point = farena_save(arena^)
|
||||
|
||||
case .Query:
|
||||
output.features = {.Alloc, .Reset, .Grow, .Shrink, .Rewind}
|
||||
@@ -471,14 +430,9 @@ farena_ainfo :: #force_inline proc "contextless" (arena : ^FArena) -> AllocatorI
|
||||
//endregion FArena
|
||||
|
||||
//region OS
|
||||
OS_SystemInfo :: struct {
|
||||
target_page_size: int,
|
||||
}
|
||||
OS_Windows_State :: struct {
|
||||
system_info: OS_SystemInfo,
|
||||
}
|
||||
@(private)
|
||||
os_windows_info: OS_Windows_State
|
||||
OS_SystemInfo :: struct { target_page_size: int }
|
||||
OS_Windows_State :: struct { system_info: OS_SystemInfo }
|
||||
@(private) os_windows_info: OS_Windows_State
|
||||
|
||||
// Windows API constants
|
||||
MS_INVALID_HANDLE_VALUE :: ~uintptr(0)
|
||||
@@ -537,12 +491,7 @@ os_enable_large_pages :: proc() {
|
||||
{
|
||||
priv := MS_TOKEN_PRIVILEGES {
|
||||
privilege_count = 1,
|
||||
privileges = {
|
||||
{
|
||||
luid = luid,
|
||||
attributes = MS_SE_PRIVILEGE_ENABLED,
|
||||
},
|
||||
},
|
||||
privileges = { { luid = luid, attributes = MS_SE_PRIVILEGE_ENABLED, }, },
|
||||
}
|
||||
AdjustTokenPrivileges(token, 0, &priv, size_of(MS_TOKEN_PRIVILEGES), nil, nil)
|
||||
}
|
||||
@@ -554,25 +503,19 @@ os_init :: proc() {
|
||||
info := &os_windows_info.system_info
|
||||
info.target_page_size = int(GetLargePageMinimum())
|
||||
}
|
||||
os_system_info :: proc() -> ^OS_SystemInfo {
|
||||
return &os_windows_info.system_info
|
||||
}
|
||||
os_vmem_commit :: proc(vm: rawptr, size: int, no_large_pages: b32 = false) -> b32 {
|
||||
os_system_info :: #force_inline proc "contextless" () -> ^OS_SystemInfo { return & os_windows_info.system_info }
|
||||
os_vmem_commit :: #force_inline proc "contextless" (vm: rawptr, size: int, no_large_pages: b32 = false) -> b32 {
|
||||
// Large pages disabled for now (not failing gracefully in original C)
|
||||
result := VirtualAlloc(vm, uintptr(size), MS_MEM_COMMIT, MS_PAGE_READWRITE) != nil
|
||||
return b32(result)
|
||||
return cast(b32) VirtualAlloc(vm, uintptr(size), MS_MEM_COMMIT, MS_PAGE_READWRITE) != nil
|
||||
}
|
||||
os_vmem_reserve :: proc(size: int, base_addr: int = 0, no_large_pages: b32 = false) -> rawptr {
|
||||
result := VirtualAlloc(rawptr(uintptr(base_addr)), uintptr(size),
|
||||
os_vmem_reserve :: #force_inline proc "contextless" (size: int, base_addr: int = 0, no_large_pages: b32 = false) -> rawptr {
|
||||
return VirtualAlloc(rawptr(uintptr(base_addr)), uintptr(size),
|
||||
MS_MEM_RESERVE,
|
||||
// MS_MEM_COMMIT
|
||||
// | (no_large_pages ? 0 : MS_MEM_LARGE_PAGES), // Large pages disabled
|
||||
MS_PAGE_READWRITE)
|
||||
return result
|
||||
}
|
||||
os_vmem_release :: proc(vm: rawptr, size: int) {
|
||||
VirtualFree(vm, 0, MS_MEM_RELEASE)
|
||||
}
|
||||
os_vmem_release :: #force_inline proc "contextless" (vm: rawptr, size: int) { VirtualFree(vm, 0, MS_MEM_RELEASE) }
|
||||
//endregion OS
|
||||
|
||||
//region VArena
|
||||
@@ -646,17 +589,6 @@ varena_push :: proc(va: ^VArena, $Type: typeid, amount: int, alignment: int = ME
|
||||
va.commit_used = to_be_used
|
||||
return slice(transmute([^]Type) uintptr(current_offset), amount)
|
||||
}
|
||||
varena_release :: proc(va: ^VArena) {
|
||||
os_vmem_release(va, va.reserve)
|
||||
}
|
||||
varena_rewind :: proc(va: ^VArena, save_point: AllocatorSP) {
|
||||
assert(va != nil)
|
||||
assert(save_point.type_sig == varena_allocator_proc)
|
||||
va.commit_used = max(save_point.slot, size_of(VArena))
|
||||
}
|
||||
varena_reset :: proc(va: ^VArena) {
|
||||
va.commit_used = size_of(VArena)
|
||||
}
|
||||
varena_shrink :: proc(va: ^VArena, old_allocation: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT) -> []byte {
|
||||
assert(va != nil)
|
||||
current_offset := va.reserve_start + va.commit_used
|
||||
@@ -668,6 +600,13 @@ varena_shrink :: proc(va: ^VArena, old_allocation: []byte, requested_size: int,
|
||||
va.commit_used -= shrink_amount
|
||||
return old_allocation[:requested_size]
|
||||
}
|
||||
varena_release :: #force_inline proc(va: ^VArena) { os_vmem_release(va, va.reserve) }
|
||||
varena_reset :: #force_inline proc(va: ^VArena) { va.commit_used = size_of(VArena) }
|
||||
varena_rewind :: #force_inline proc(va: ^VArena, save_point: AllocatorSP) {
|
||||
assert(va != nil)
|
||||
assert(save_point.type_sig == varena_allocator_proc)
|
||||
va.commit_used = max(save_point.slot, size_of(VArena))
|
||||
}
|
||||
varena_save :: #force_inline proc "contextless" (va: ^VArena) -> AllocatorSP { return AllocatorSP { type_sig = varena_allocator_proc, slot = va.commit_used } }
|
||||
varena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Out) {
|
||||
assert(output != nil)
|
||||
@@ -785,7 +724,7 @@ arena_push :: proc(arena: ^Arena, $Type: typeid, amount: int, alignment: int = M
|
||||
active.pos = pos_pst
|
||||
return slice(result_ptr, amount)
|
||||
}
|
||||
arena_release :: proc(arena: ^Arena) {
|
||||
arena_release :: #force_inline proc(arena: ^Arena) {
|
||||
assert(arena != nil)
|
||||
curr := arena.current
|
||||
for curr != nil {
|
||||
@@ -794,9 +733,7 @@ arena_release :: proc(arena: ^Arena) {
|
||||
curr = prev
|
||||
}
|
||||
}
|
||||
arena_reset :: proc(arena: ^Arena) {
|
||||
arena_rewind(arena, AllocatorSP { type_sig = arena_allocator_proc, slot = 0 })
|
||||
}
|
||||
arena_reset :: #force_inline proc(arena: ^Arena) { arena_rewind(arena, AllocatorSP { type_sig = arena_allocator_proc, slot = 0 }) }
|
||||
arena_rewind :: proc(arena: ^Arena, save_point: AllocatorSP) {
|
||||
assert(arena != nil)
|
||||
assert(save_point.type_sig == arena_allocator_proc)
|
||||
@@ -1025,11 +962,7 @@ kt1cx_clear :: proc(kt: KT1CX_Byte, m: KT1CX_ByteMeta) {
|
||||
}
|
||||
}
|
||||
}
|
||||
kt1cx_slot_id :: proc(kt: KT1CX_Byte, key: u64, m: KT1CX_ByteMeta) -> u64 {
|
||||
cell_size := m.cell_size // dummy value
|
||||
hash_index := key % u64(len(kt.table))
|
||||
return hash_index
|
||||
}
|
||||
kt1cx_slot_id :: #force_inline proc(kt: KT1CX_Byte, key: u64, m: KT1CX_ByteMeta) -> u64 { return key % u64(len(kt.table)) }
|
||||
kt1cx_get :: proc(kt: KT1CX_Byte, key: u64, m: KT1CX_ByteMeta) -> ^byte {
|
||||
hash_index := kt1cx_slot_id(kt, key, m)
|
||||
cell_offset := uintptr(hash_index) * uintptr(m.cell_size)
|
||||
@@ -1100,28 +1033,22 @@ kt1cx_set :: proc(kt: KT1CX_Byte, key: u64, value: []byte, backing_cells: Alloca
|
||||
return nil
|
||||
}
|
||||
}
|
||||
kt1cx_assert :: proc(kt: $type / KT1CX) {
|
||||
slice_assert(kt.table)
|
||||
}
|
||||
kt1cx_byte :: proc(kt: $type / KT1CX) -> KT1CX_Byte { return {
|
||||
slice( transmute([^]byte) cursor(kt.table), len(kt.table))
|
||||
} }
|
||||
kt1cx_assert :: #force_inline proc(kt: $type / KT1CX) { slice_assert(kt.table) }
|
||||
kt1cx_byte :: #force_inline proc(kt: $type / KT1CX) -> KT1CX_Byte { return { slice( transmute([^]byte) cursor(kt.table), len(kt.table)) } }
|
||||
//endregion Key Table 1-Layer Chained-Chunked-Cells (KT1CX)
|
||||
|
||||
//region String Operations
|
||||
char_is_upper :: proc(c: u8) -> b32 { return('A' <= c && c <= 'Z') }
|
||||
char_to_lower :: proc(c: u8) -> u8 { c:=c; if (char_is_upper(c)) { c += ('a' - 'A') }; return (c) }
|
||||
char_is_upper :: #force_inline proc(c: u8) -> b32 { return('A' <= c && c <= 'Z') }
|
||||
char_to_lower :: #force_inline proc(c: u8) -> u8 { c:=c; if (char_is_upper(c)) { c += ('a' - 'A') }; return (c) }
|
||||
|
||||
integer_symbols :: proc(value: u8) -> u8 {
|
||||
integer_symbols :: #force_inline proc(value: u8) -> u8 {
|
||||
@static lookup_table: [16]u8 = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', };
|
||||
return lookup_table[value];
|
||||
}
|
||||
|
||||
str8_to_cstr_capped :: proc(content: string, mem: []byte) -> cstring {
|
||||
str8_to_cstr_capped :: #force_inline proc(content: string, mem: []byte) -> cstring {
|
||||
copy_len := min(len(content), len(mem) - 1)
|
||||
if copy_len > 0 {
|
||||
copy(mem[:copy_len], transmute([]byte) content)
|
||||
}
|
||||
if copy_len > 0 { copy(mem[:copy_len], transmute([]byte) content) }
|
||||
mem[copy_len] = 0
|
||||
return transmute(cstring) raw_data(mem)
|
||||
}
|
||||
@@ -1184,7 +1111,6 @@ str8_from_u32 :: proc(ainfo: AllocatorInfo, num: u32, radix: u32 = 10, min_digit
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
str8_fmt_kt1l :: proc(ainfo: AllocatorInfo, _buffer: ^[]byte, table: []KTL_Slot(string), fmt_template: string) -> string {
|
||||
buffer := _buffer^
|
||||
slice_assert(buffer)
|
||||
@@ -1264,15 +1190,14 @@ str8_fmt_kt1l :: proc(ainfo: AllocatorInfo, _buffer: ^[]byte, table: []KTL_Slot(
|
||||
result := transmute(string) slice(cursor(buffer), len(buffer) - buffer_remaining)
|
||||
return result
|
||||
}
|
||||
|
||||
str8_fmt_backed :: proc(tbl_ainfo, buf_ainfo: AllocatorInfo, fmt_template: string, entries: [][2]string) -> string {
|
||||
str8_fmt_backed :: #force_inline proc(tbl_ainfo, buf_ainfo: AllocatorInfo, fmt_template: string, entries: [][2]string) -> string {
|
||||
kt: []KTL_Slot(string); ktl_populate_slice_a2_str(& kt, tbl_ainfo, entries)
|
||||
buf_size := Kilo * 64
|
||||
buffer := mem_alloc(buf_ainfo, buf_size)
|
||||
result := str8_fmt_kt1l(buf_ainfo, & buffer, kt, fmt_template)
|
||||
return result
|
||||
}
|
||||
str8_fmt_tmp :: proc(fmt_template: string, entries: [][2]string) -> string {
|
||||
str8_fmt_tmp :: #force_inline proc(fmt_template: string, entries: [][2]string) -> string {
|
||||
@static tbl_mem: [Kilo * 32]byte; tbl_arena := farena_make(tbl_mem[:])
|
||||
@static buf_mem: [Kilo * 64]byte; buffer := buf_mem[:]
|
||||
kt: []KTL_Slot(string); ktl_populate_slice_a2_str(& kt, ainfo(& tbl_arena), entries)
|
||||
@@ -1317,7 +1242,7 @@ str8cache_init :: proc(cache: ^Str8Cache, str_reserve, cell_reserve, tbl_backing
|
||||
kt1cx_init(info, m, transmute(^KT1CX_Byte) & cache.kt)
|
||||
return
|
||||
}
|
||||
str8cache_make :: proc(str_reserve, cell_reserve, tbl_backing: AllocatorInfo, cell_pool_size, table_size: int) -> Str8Cache {
|
||||
str8cache_make :: #force_inline proc(str_reserve, cell_reserve, tbl_backing: AllocatorInfo, cell_pool_size, table_size: int) -> Str8Cache {
|
||||
cache : Str8Cache; str8cache_init(& cache, str_reserve, cell_reserve, tbl_backing, cell_pool_size, table_size); return cache
|
||||
}
|
||||
str8cache_clear :: proc(kt: KT1CX_Str8) {
|
||||
@@ -1368,11 +1293,10 @@ str8cache_set :: proc(kt: KT1CX_Str8, key: u64, value: string, str_reserve, cell
|
||||
}
|
||||
return result
|
||||
}
|
||||
cache_str8 :: proc(cache: ^Str8Cache, str: string) -> string {
|
||||
cache_str8 :: #force_inline proc(cache: ^Str8Cache, str: string) -> string {
|
||||
assert(cache != nil)
|
||||
key: u64 = 0; hash64_fnv1a(& key, transmute([]byte) str)
|
||||
result := str8cache_set(cache.kt, key, str, cache.str_reserve, cache.cell_reserve)
|
||||
return result ^
|
||||
return str8cache_set(cache.kt, key, str, cache.str_reserve, cache.cell_reserve) ^
|
||||
}
|
||||
|
||||
Str8Gen :: struct {
|
||||
@@ -1389,9 +1313,9 @@ str8gen_init :: proc(gen: ^Str8Gen, ainfo: AllocatorInfo) {
|
||||
gen.len = 0
|
||||
gen.cap = Kilo * 4
|
||||
}
|
||||
str8gen_make :: proc(ainfo: AllocatorInfo) -> Str8Gen { gen: Str8Gen; str8gen_init(& gen, ainfo); return gen }
|
||||
str8gen_to_bytes :: proc(gen: Str8Gen) -> []byte { return transmute([]byte) SliceByte {data = gen.ptr, len = gen.cap} }
|
||||
str8_from_str8gen :: proc(gen: Str8Gen) -> string { return transmute(string) SliceByte {data = gen.ptr, len = gen.len} }
|
||||
str8gen_make :: #force_inline proc(ainfo: AllocatorInfo) -> Str8Gen { gen: Str8Gen; str8gen_init(& gen, ainfo); return gen }
|
||||
str8gen_to_bytes :: #force_inline proc(gen: Str8Gen) -> []byte { return transmute([]byte) SliceByte {data = gen.ptr, len = gen.cap} }
|
||||
str8_from_str8gen :: #force_inline proc(gen: Str8Gen) -> string { return transmute(string) SliceByte {data = gen.ptr, len = gen.len} }
|
||||
|
||||
str8gen_append_str8 :: proc(gen: ^Str8Gen, str: string) {
|
||||
result := mem_grow(gen.backing, str8gen_to_bytes(gen ^), len(str) + gen.len)
|
||||
@@ -1515,9 +1439,8 @@ api_file_read_contents :: proc(result: ^FileOpInfo, path: string, backing: Alloc
|
||||
result.content = slice(cursor(buffer), cast(int) file_size.QuadPart)
|
||||
return
|
||||
}
|
||||
file_read_contents_stack :: proc(path: string, backing: AllocatorInfo, zero_backing: b32 = false) -> FileOpInfo {
|
||||
result : FileOpInfo; api_file_read_contents(& result, path, backing, zero_backing)
|
||||
return result
|
||||
file_read_contents_stack :: #force_inline proc(path: string, backing: AllocatorInfo, zero_backing: b32 = false) -> FileOpInfo {
|
||||
result: FileOpInfo; api_file_read_contents(& result, path, backing, zero_backing) return result
|
||||
}
|
||||
file_write_str8 :: proc(path, content: string) {
|
||||
string_assert(path)
|
||||
@@ -1604,8 +1527,7 @@ api_watl_lex :: proc(info: ^WATL_LexInfo, source: string,
|
||||
alloc_tok :: #force_inline proc(ainfo: AllocatorInfo) -> ^Raw_String {
|
||||
return alloc_type(ainfo, Raw_String, align_of(Raw_String), true)
|
||||
}
|
||||
#partial switch cast(WATL_TokKind) code
|
||||
{
|
||||
#partial switch cast(WATL_TokKind) code {
|
||||
case .Space: fallthrough
|
||||
case .Tab:
|
||||
if prev[0] != src_cursor[0] {
|
||||
@@ -1729,8 +1651,7 @@ api_watl_parse :: proc(info: ^WATL_ParseInfo, tokens: []WATL_Tok,
|
||||
info_lines ^ = { transmute([^]WATL_Node) line, 0 }
|
||||
for & token in tokens
|
||||
{
|
||||
#partial switch cast(WATL_TokKind) token[0]
|
||||
{
|
||||
#partial switch cast(WATL_TokKind) token[0] {
|
||||
case .Carriage_Return: fallthrough
|
||||
case .Line_Feed:
|
||||
new_line := alloc_type(ainfo_lines, WATL_Line); if cursor(new_line)[-1:] != transmute(^[]string)line {
|
||||
@@ -1748,9 +1669,7 @@ api_watl_parse :: proc(info: ^WATL_ParseInfo, tokens: []WATL_Tok,
|
||||
line.data = curr
|
||||
info_lines.len += 1
|
||||
continue
|
||||
|
||||
case:
|
||||
break;
|
||||
case: break;
|
||||
}
|
||||
curr ^ = cache_str8(str_cache, token)
|
||||
new_node := alloc_type(ainfo_nodes, WATL_Node); if cursor(new_node)[-1:] != curr {
|
||||
@@ -1799,8 +1718,7 @@ watl_dump_listing :: proc(buffer: AllocatorInfo, lines: []WATL_Line) -> string {
|
||||
for chunk in line
|
||||
{
|
||||
id : string
|
||||
#partial switch cast(WATL_TokKind) chunk[0]
|
||||
{
|
||||
#partial switch cast(WATL_TokKind) chunk[0] {
|
||||
case .Space: id = "Space"
|
||||
case .Tab: id = "Tab"
|
||||
case: id = "Visible"
|
||||
|
||||
200
scripts/build.c.lottes.ps1
Normal file
200
scripts/build.c.lottes.ps1
Normal file
@@ -0,0 +1,200 @@
|
||||
$misc = Join-Path $PSScriptRoot 'helpers/misc.psm1'
|
||||
import-module $misc
|
||||
|
||||
# This script now uses the LLVM toolchain (clang-cl, lld-link).
|
||||
# Ensure these tools are available in your PATH.
|
||||
# The original call to the MSVC devshell has been removed.
|
||||
# & (join-path $PSScriptRoot 'helpers/devshell.ps1') -arch amd64
|
||||
|
||||
$path_root = Get-ScriptRepoRoot
|
||||
|
||||
$path_root = split-path -Path $PSScriptRoot -Parent
|
||||
$path_toolchain = join-path $path_root 'toolchain'
|
||||
$path_rad = join-path $path_toolchain 'rad'
|
||||
|
||||
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
|
||||
# Most cl.exe flags are compatible with clang-cl.exe
|
||||
$flag_all_c = '/TC'
|
||||
$flag_c11 = '/std:c11'
|
||||
$flag_c23 = '/std:c23'
|
||||
$flag_all_cpp = '/TP'
|
||||
$flag_compile = '/c'
|
||||
$flag_charset_utf8 = '/utf-8'
|
||||
$flag_debug = '/Zi'
|
||||
$flag_define = '/D'
|
||||
$flag_exceptions_disabled = '/EHsc-'
|
||||
$flag_RTTI_disabled = '/GR-'
|
||||
$flag_include = '/I'
|
||||
$flag_full_src_path = '/FC'
|
||||
$flag_asm_listing_file = '/FAs'
|
||||
$flag_nologo = '/nologo'
|
||||
$flag_dll = '/LD'
|
||||
$flag_dll_debug = '/LDd'
|
||||
$flag_linker = '/link'
|
||||
# $flag_link_lib = '/lib'
|
||||
$flag_link_dll = '/DLL'
|
||||
$flag_link_no_incremental = '/INCREMENTAL:NO'
|
||||
$flag_link_mapfile = '/MAP:'
|
||||
$flag_link_optimize_references = '/OPT:REF'
|
||||
$flag_link_win_debug = '/DEBUG'
|
||||
$flag_link_win_pdb = '/PDB:'
|
||||
$flag_link_win_machine_32 = '/MACHINE:X86'
|
||||
$flag_link_win_machine_64 = '/MACHINE:X64'
|
||||
$flag_link_win_path_output = '/OUT:'
|
||||
$flag_link_win_rt_dll = '/MD'
|
||||
$flag_link_win_rt_dll_debug = '/MDd'
|
||||
$flag_link_win_rt_static = '/MT'
|
||||
$flag_link_win_rt_static_debug = '/MTd'
|
||||
$flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
|
||||
$flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
|
||||
$flag_no_optimization = '/Od'
|
||||
$flag_optimize_speed_max = '/Ox'
|
||||
$flag_optimize_fast = '/O2'
|
||||
$flag_optimize_size = '/O1'
|
||||
$flag_optimize_intrinsics = '/Oi'
|
||||
$flag_optimized_debug_forceinline = '/d2Obforceinline'
|
||||
$flag_optimized_debug = '/Zo'
|
||||
$flag_preprocess_to_file = '/P'
|
||||
$flag_preprocess_preserve_comments = '/C'
|
||||
# $flag_out_name = '/OUT:'
|
||||
$flag_path_interm = '/Fo'
|
||||
$flag_path_debug = '/Fd'
|
||||
$flag_path_output = '/Fe'
|
||||
$flag_preprocess_conform = '/Zc:preprocessor'
|
||||
$flag_sanitize_address = '/fsanitize=address'
|
||||
$flag_updated_cpp_macro = "/Zc:__cplusplus"
|
||||
$flag_set_stack_size = '/F'
|
||||
$flag_syntax_only = '/Zs'
|
||||
$flag_wall = '/Wall'
|
||||
$flag_warnings_as_errors = '/WX'
|
||||
$flag_lib_list = '/LIST'
|
||||
|
||||
$archiver = 'llvm-lib'
|
||||
$compiler = 'clang-cl'
|
||||
$linker = 'lld-link'
|
||||
$radbin = join-path $path_rad 'radbin.exe'
|
||||
$radlink = join-path $path_rad 'radlink.exe'
|
||||
|
||||
$path_build = join-path $path_root 'build'
|
||||
if ( -not(test-path -Path $path_build) ) {
|
||||
new-item -ItemType Directory -Path $path_build
|
||||
}
|
||||
|
||||
push-location $path_build
|
||||
|
||||
write-host "Compiling with clang-cl"
|
||||
|
||||
$compiler_args = @()
|
||||
$compiler_args += $flag_nologo
|
||||
|
||||
# Constraints on interpeting all files as C code
|
||||
$compiler_args += $flag_all_c
|
||||
$compiler_args += $flag_c11
|
||||
# Constraints on C program code-gen
|
||||
$compiler_args += $flag_exceptions_disabled
|
||||
$compiler_args += $flag_RTTI_disabled
|
||||
# $compiler_args += $flag_preprocess_conform
|
||||
# $compiler_args += $flag_sanitize_address
|
||||
|
||||
$compiler_args += $flag_wall
|
||||
|
||||
# Set charset encoding for both execution and source to UTF-8
|
||||
$compiler_args += $flag_charset_utf8
|
||||
|
||||
# Specifing output pathing
|
||||
$compiler_args += ( $flag_path_interm + $path_build + '\' )
|
||||
# $compiler_args += ( $flag_path_output + $path_build + '\' )
|
||||
|
||||
# Dump preprocess file
|
||||
if ($false) {
|
||||
$compiler_args += $flag_preprocess_to_file
|
||||
$compiler_args += $flag_preprocess_preserve_comments
|
||||
}
|
||||
|
||||
# Diagnostic logging
|
||||
$compiler_args += $flag_full_src_path
|
||||
# $compiler_args += $flag_asm_listing_file
|
||||
|
||||
# $compiler_args += $flag_optimize_speed_max
|
||||
# $compiler_args += $flag_optimize_fast
|
||||
# $compiler_args += $flag_optimize_size
|
||||
$compiler_args += $flag_optimize_intrinsics
|
||||
# $compiler_args += $flag_no_optimization
|
||||
|
||||
# Debug setup
|
||||
$compiler_args += ($flag_define + 'BUILD_DEBUG')
|
||||
$compiler_args += $flag_debug
|
||||
$compiler_args += ( $flag_path_debug + $path_build + '\' )
|
||||
# Use the static, multithreaded, debug runtime library
|
||||
# $compiler_args += $flag_link_win_rt_static_debug
|
||||
|
||||
# Include setup
|
||||
$compiler_args += ($flag_include + $path_root)
|
||||
|
||||
$unit_name = "watl.v0.llvm.lottes"
|
||||
|
||||
# Specify unit to compile
|
||||
$unit = join-path $path_root "C\$unit_name.c"
|
||||
$compiler_args += $flag_compile, $unit
|
||||
|
||||
# Diagnoistc print for the args
|
||||
$compiler_args | ForEach-Object { Write-Host $_ }
|
||||
|
||||
# Compile the unit
|
||||
$compilation_time = Measure-Command {
|
||||
& $compiler $compiler_args
|
||||
}
|
||||
write-host "Compilation took $($compilation_time.TotalMilliseconds)ms"
|
||||
write-host
|
||||
|
||||
$binary = join-path $path_build "$unit_name.exe"
|
||||
$object = join-path $path_build "$unit_name.obj"
|
||||
|
||||
$pdb = join-path $path_build "$unit_name.pdb"
|
||||
$map = join-path $path_build "$unit_name.map"
|
||||
$rdi = join-path $path_build "$unit_name.rdi"
|
||||
$rdi_listing = join-path $path_build "$unit_name.rdi.list"
|
||||
|
||||
if ($true) {
|
||||
write-host "Linking with lld-link"
|
||||
|
||||
$linker_args = @()
|
||||
$linker_args += $flag_nologo
|
||||
$linker_args += $flag_link_win_machine_64
|
||||
$linker_args += $flag_link_no_incremental
|
||||
$linker_args += ($flag_link_win_path_output + $binary)
|
||||
|
||||
$linker_args += "$flag_link_win_debug"
|
||||
$linker_args += $flag_link_win_pdb + $pdb
|
||||
$linker_args += $flag_link_mapfile + $map
|
||||
$linker_args += $flag_link_win_subsystem_console
|
||||
|
||||
$linker_args += $object
|
||||
|
||||
# Add necessary libraries for a basic Windows application
|
||||
$linker_args += "kernel32.lib", "user32.lib", "gdi32.lib"
|
||||
|
||||
# Diagnoistc print for the args
|
||||
$linker_args | ForEach-Object { Write-Host $_ }
|
||||
|
||||
$linking_time = Measure-Command { & $linker $linker_args }
|
||||
# & $radlink $linker_args
|
||||
write-host "Linking took $($linking_time.TotalMilliseconds)ms"
|
||||
write-host
|
||||
}
|
||||
|
||||
if ($false) {
|
||||
write-host "Dumping Debug Info"
|
||||
|
||||
$rbin_out = '--out:'
|
||||
$rbin_dump = '--dump'
|
||||
|
||||
$nargs = @($pdb, ($rbin_out + $rdi))
|
||||
& $radbin $nargs
|
||||
|
||||
$nargs = @($rbin_dump, $rdi)
|
||||
$dump = & $radbin $nargs
|
||||
$dump > $rdi_listing
|
||||
}
|
||||
|
||||
Pop-Location
|
||||
@@ -118,8 +118,8 @@ $compiler_args += $flag_full_src_path
|
||||
# $compiler_args += $flag_optimize_speed_max
|
||||
# $compiler_args += $flag_optimize_fast
|
||||
# $compiler_args += $flag_optimize_size
|
||||
# $compiler_args += $flag_optimize_intrinsics
|
||||
$compiler_args += $flag_no_optimization
|
||||
$compiler_args += $flag_optimize_intrinsics
|
||||
# $compiler_args += $flag_no_optimization
|
||||
|
||||
# Debug setup
|
||||
$compiler_args += ($flag_define + 'BUILD_DEBUG')
|
||||
@@ -117,8 +117,8 @@ $compiler_args += $flag_full_src_path
|
||||
# $compiler_args += $flag_optimize_speed_max
|
||||
# $compiler_args += $flag_optimize_fast
|
||||
# $compiler_args += $flag_optimize_size
|
||||
# $compiler_args += $flag_optimize_intrinsics
|
||||
$compiler_args += $flag_no_optimization
|
||||
$compiler_args += $flag_optimize_intrinsics
|
||||
# $compiler_args += $flag_no_optimization
|
||||
|
||||
# Debug setup
|
||||
$compiler_args += ($flag_define + 'BUILD_DEBUG')
|
||||
@@ -139,7 +139,10 @@ $compiler_args += $flag_compile, $unit
|
||||
$compiler_args | ForEach-Object { Write-Host $_ }
|
||||
|
||||
# Compile the unit
|
||||
& $compiler $compiler_args
|
||||
$compilation_time = Measure-Command {
|
||||
& $compiler $compiler_args
|
||||
}
|
||||
write-host "Compilation took $($compilation_time.TotalMilliseconds)ms"
|
||||
write-host
|
||||
|
||||
$binary = join-path $path_build "$unit_name.exe"
|
||||
@@ -168,8 +171,9 @@ if ($true) {
|
||||
# Diagnoistc print for the args
|
||||
$linker_args | ForEach-Object { Write-Host $_ }
|
||||
|
||||
& $linker $linker_args
|
||||
$linking_time = Measure-Command { & $linker $linker_args }
|
||||
# & $radlink $linker_args
|
||||
write-host "Linking took $($linking_time.TotalMilliseconds)ms"
|
||||
write-host
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user