mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 11:11:37 -07:00
Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 14eeee40b2 | |||
| 038dea9202 | |||
| 0ae3484171 | |||
| 54976c3249 | |||
| 8f913c656c | |||
| 001b48a5c6 | |||
| 54929a1b92 | |||
| 92780e2683 | |||
| 2891988d3b | |||
| c1728914c6 | |||
| ed2f49e8d2 | |||
| 8a76a370a9 | |||
| 1160fd4331 | |||
| 0134c38759 | |||
| d079095517 | |||
| 028d628e9f | |||
| 5e4b62acfe | |||
| 9366fa8e95 | |||
| 369db3a8e3 | |||
| 8c360b2a3c | |||
| b66e7bed45 | |||
| e919482aa8 | |||
| dce45e7d58 | |||
| 1a0877e965 | |||
| 0361a18551 | |||
| 83d90f1463 | |||
| f661ae9d09 | |||
| bee4cb57f2 | |||
| 53b670b889 | |||
| e2600a3e44 | |||
| 25101b2ae0 | |||
| 4e7867fcc1 | |||
| 101ee64165 | |||
| 4c3e65791e | |||
| a9c8031b61 | |||
| afb3033913 | |||
| 2ad26640a2 | |||
| 2c0b08145f | |||
| aa9c9eda9e | |||
| 1353d61894 | |||
| 88ba6d8015 | |||
| 8b288a2072 | |||
| 4e90644527 | |||
| 6651b65373 | |||
| 705352099f | |||
| 2e28c9d793 | |||
| 2fe660a1d7 | |||
| b03ce0e9b4 | |||
| 386f5f596d | |||
| add53228b2 | |||
| d90008cc52 | |||
| dbf8f9ab38 | |||
| 81a99cf67b | |||
| 876af6fb02 | |||
| b3734a5f77 | |||
| 419ab6f00c | |||
| 5558b55e9f | |||
| 4b14d608f4 | |||
| 9428d86f2b | |||
| ddebf0daf2 | |||
| 3a44c62ecf | |||
| 184efd4f49 | |||
| 6b3c4cc379 | |||
| 0b137e087c | |||
| 37790c13a0 | |||
| 82057f08ce | |||
| 1553421e1a | |||
| f3ea109e6f | |||
| 90dbfe7660 | |||
| 125bad3154 | |||
| 30c83d6c81 | |||
| 4f12c118a5 | |||
| 423775d50e | |||
| 860a5c3e86 | |||
| 649e02f209 | |||
| b449305cc1 | |||
| 49bee6bad0 | |||
| ac277a1cce | |||
| a17310a83c | |||
| b509946b13 | |||
| a69ea58388 | |||
| 30530d058c | |||
| 436928d06a | |||
| 32a502d14e | |||
| 0d665c637f | |||
| 1b6a14ac39 | |||
| 367013f589 | |||
| c980a30bad | |||
| 78b459590c | |||
| 054e241033 | |||
| f7e9649be4 | |||
| fd1f6ec75c | |||
| 6b0d7cb26c | |||
| 3aea08df78 | |||
| 3c6f90e552 | |||
| 3703ca4df4 | |||
| 41b8281c73 | |||
| acd1f83bd0 | |||
| ba8371104d | |||
| 991682e9fd | |||
| f0de994059 | |||
| ebb2a9812c | |||
| 265c05927f | |||
| 05ad38ae2d | |||
| 596a2c8355 | |||
| 9f52b2c283 | |||
| 8035a407a6 | |||
| 97760c3fa4 | |||
| d75291097e | |||
| db632b7e22 | |||
| 1a75dfe075 | |||
| e00d88d82e | |||
| 04cce1826b | |||
| cc28cda053 | |||
| cfabc0e61f | |||
| 91b534d128 | |||
| 3268f43340 | |||
| 05e374934d | |||
| 3e1ff0ec67 | |||
| 65945dac09 | |||
| 1608da2dc8 | |||
| c340827381 | |||
| 74fa7ca25d | |||
| 5a9223afda | |||
| febcd73323 | |||
| df06236076 | |||
| b0d3fbba47 | |||
| adb6c7637e | |||
| 425f83b17d | |||
| 976415ff9d | |||
| 4d7fb3e8d6 | |||
| bcca3bf322 | |||
| 74aaa3408f | |||
| 2a5beee88c | |||
| cec9f7abfe |
@@ -11,6 +11,30 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
|
||||
|
||||
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
|
||||
|
||||
```go
|
||||
import "core:fmt.odin"
|
||||
|
||||
main :: proc() {
|
||||
program := "+ + * 😃 - /";
|
||||
accumulator := 0;
|
||||
|
||||
for token in program {
|
||||
switch token {
|
||||
case '+': accumulator += 1;
|
||||
case '-': accumulator -= 1;
|
||||
case '*': accumulator *= 2;
|
||||
case '/': accumulator /= 2;
|
||||
case '😃': accumulator *= accumulator;
|
||||
case: // Ignore everything else
|
||||
}
|
||||
}
|
||||
|
||||
fmt.printf("The program \"%s\" calculates the value %d\n",
|
||||
program, accumulator);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Demonstrations:
|
||||
* First Talk & Demo
|
||||
- [Talk](https://youtu.be/TMCkT-uASaE?t=338)
|
||||
|
||||
@@ -41,9 +41,10 @@ set linker_settings=%libs% %linker_flags%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
|
||||
cl %compiler_settings% "src\main.cpp" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run examples/demo.odin -opt=0
|
||||
&& odin run examples/demo.odin
|
||||
rem && odin docs core/fmt.odin
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
+431
-186
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
#shared_global_scope
|
||||
|
||||
/*
|
||||
@(link_name="__multi3")
|
||||
__multi3 :: proc "c" (a, b: u128) -> u128 {
|
||||
bits_in_dword_2 :: size_of(i64) * 4;
|
||||
@@ -108,3 +109,4 @@ __u128_quo_mod :: proc "c" (a, b: u128, rem: ^u128) -> (quo: u128) {
|
||||
if rem != nil do rem^ = r;
|
||||
return q;
|
||||
}
|
||||
*/
|
||||
|
||||
+28
-28
@@ -13,90 +13,90 @@ sfence :: proc() { win32.write_barrier(); }
|
||||
lfence :: proc() { win32.read_barrier(); }
|
||||
|
||||
|
||||
load :: proc(a: ^i32) -> i32 {
|
||||
load_i32 :: proc(a: ^i32) -> i32 {
|
||||
return a^;
|
||||
}
|
||||
store :: proc(a: ^i32, value: i32) {
|
||||
store_i32 :: proc(a: ^i32, value: i32) {
|
||||
a^ = value;
|
||||
}
|
||||
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||
compare_exchange_i32 :: proc(a: ^i32, expected, desired: i32) -> i32 {
|
||||
return win32.interlocked_compare_exchange(a, desired, expected);
|
||||
}
|
||||
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
|
||||
exchanged_i32 :: proc(a: ^i32, desired: i32) -> i32 {
|
||||
return win32.interlocked_exchange(a, desired);
|
||||
}
|
||||
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_add_i32 :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.interlocked_exchange_add(a, operand);
|
||||
|
||||
}
|
||||
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_and_i32 :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.interlocked_and(a, operand);
|
||||
}
|
||||
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
fetch_or_i32 :: proc(a: ^i32, operand: i32) -> i32 {
|
||||
return win32.interlocked_or(a, operand);
|
||||
}
|
||||
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
spin_lock_i32 :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange_i32(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
old_value = compare_exchange_i32(a, 1, 0);
|
||||
mfence();
|
||||
}
|
||||
return old_value == 0;
|
||||
}
|
||||
spin_unlock :: proc(a: ^i32) {
|
||||
store(a, 0);
|
||||
spin_unlock_i32 :: proc(a: ^i32) {
|
||||
store_i32(a, 0);
|
||||
mfence();
|
||||
}
|
||||
try_acquire_lock :: proc(a: ^i32) -> bool {
|
||||
try_acquire_lock_i32 :: proc(a: ^i32) -> bool {
|
||||
yield_thread();
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
old_value := compare_exchange_i32(a, 1, 0);
|
||||
mfence();
|
||||
return old_value == 0;
|
||||
}
|
||||
|
||||
|
||||
load :: proc(a: ^i64) -> i64 {
|
||||
load_i64 :: proc(a: ^i64) -> i64 {
|
||||
return a^;
|
||||
}
|
||||
store :: proc(a: ^i64, value: i64) {
|
||||
store_i64 :: proc(a: ^i64, value: i64) {
|
||||
a^ = value;
|
||||
}
|
||||
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||
compare_exchange_i64 :: proc(a: ^i64, expected, desired: i64) -> i64 {
|
||||
return win32.interlocked_compare_exchange64(a, desired, expected);
|
||||
}
|
||||
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
|
||||
exchanged_i64 :: proc(a: ^i64, desired: i64) -> i64 {
|
||||
return win32.interlocked_exchange64(a, desired);
|
||||
}
|
||||
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_add_i64 :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.interlocked_exchange_add64(a, operand);
|
||||
}
|
||||
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_and_i64 :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.interlocked_and64(a, operand);
|
||||
}
|
||||
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
fetch_or_i64 :: proc(a: ^i64, operand: i64) -> i64 {
|
||||
return win32.interlocked_or64(a, operand);
|
||||
}
|
||||
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
spin_lock_i64 :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
|
||||
old_value := compare_exchange_i64(a, 1, 0);
|
||||
counter := 0;
|
||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||
counter += 1;
|
||||
yield_thread();
|
||||
old_value = compare_exchange(a, 1, 0);
|
||||
old_value = compare_exchange_i64(a, 1, 0);
|
||||
mfence();
|
||||
}
|
||||
return old_value == 0;
|
||||
}
|
||||
spin_unlock :: proc(a: ^i64) {
|
||||
store(a, 0);
|
||||
spin_unlock_i64 :: proc(a: ^i64) {
|
||||
store_i64(a, 0);
|
||||
mfence();
|
||||
}
|
||||
try_acquire_lock :: proc(a: ^i64) -> bool {
|
||||
try_acquire_lock_i64 :: proc(a: ^i64) -> bool {
|
||||
yield_thread();
|
||||
old_value := compare_exchange(a, 1, 0);
|
||||
old_value := compare_exchange_i64(a, 1, 0);
|
||||
mfence();
|
||||
return old_value == 0;
|
||||
}
|
||||
|
||||
+186
-270
@@ -2,327 +2,243 @@ U8_MIN :: u8(0);
|
||||
U16_MIN :: u16(0);
|
||||
U32_MIN :: u32(0);
|
||||
U64_MIN :: u64(0);
|
||||
U128_MIN :: u128(0);
|
||||
|
||||
U8_MAX :: ~u8(0);
|
||||
U16_MAX :: ~u16(0);
|
||||
U32_MAX :: ~u32(0);
|
||||
U64_MAX :: ~u64(0);
|
||||
U128_MAX :: ~u128(0);
|
||||
|
||||
I8_MIN :: i8( ~u8(0) >> 1);
|
||||
I16_MIN :: i16( ~u16(0) >> 1);
|
||||
I32_MIN :: i32( ~u32(0) >> 1);
|
||||
I64_MIN :: i64( ~u64(0) >> 1);
|
||||
I128_MIN :: i128(~u128(0) >> 1);
|
||||
|
||||
I8_MAX :: -I8_MIN - 1;
|
||||
I16_MAX :: -I16_MIN - 1;
|
||||
I32_MAX :: -I32_MIN - 1;
|
||||
I64_MAX :: -I64_MIN - 1;
|
||||
I128_MAX :: -I128_MIN - 1;
|
||||
|
||||
foreign __llvm_core {
|
||||
@(link_name="llvm.ctpop.i8") __llvm_ctpop :: proc(u8) -> u8 ---;
|
||||
@(link_name="llvm.ctpop.i8") __llvm_ctpop :: proc(i8) -> i8 ---;
|
||||
@(link_name="llvm.ctpop.i16") __llvm_ctpop :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.ctpop.i16") __llvm_ctpop :: proc(i16) -> i16 ---;
|
||||
@(link_name="llvm.ctpop.i32") __llvm_ctpop :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.ctpop.i32") __llvm_ctpop :: proc(i32) -> i32 ---;
|
||||
@(link_name="llvm.ctpop.i64") __llvm_ctpop :: proc(u64) -> u64 ---;
|
||||
@(link_name="llvm.ctpop.i64") __llvm_ctpop :: proc(i64) -> i64 ---;
|
||||
@(link_name="llvm.ctpop.i128") __llvm_ctpop :: proc(u128) -> u128 ---;
|
||||
@(link_name="llvm.ctpop.i128") __llvm_ctpop :: proc(i128) -> i128 ---;
|
||||
@(link_name="llvm.ctpop.i8") __llvm_ctpop8 :: proc(u8) -> u8 ---;
|
||||
@(link_name="llvm.ctpop.i16") __llvm_ctpop16 :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.ctpop.i32") __llvm_ctpop32 :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.ctpop.i64") __llvm_ctpop64 :: proc(u64) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.ctlz.i8") __llvm_ctlz :: proc(u8, bool) -> u8 ---;
|
||||
@(link_name="llvm.ctlz.i8") __llvm_ctlz :: proc(i8, bool) -> i8 ---;
|
||||
@(link_name="llvm.ctlz.i16") __llvm_ctlz :: proc(u16, bool) -> u16 ---;
|
||||
@(link_name="llvm.ctlz.i16") __llvm_ctlz :: proc(i16, bool) -> i16 ---;
|
||||
@(link_name="llvm.ctlz.i32") __llvm_ctlz :: proc(u32, bool) -> u32 ---;
|
||||
@(link_name="llvm.ctlz.i32") __llvm_ctlz :: proc(i32, bool) -> i32 ---;
|
||||
@(link_name="llvm.ctlz.i64") __llvm_ctlz :: proc(u64, bool) -> u64 ---;
|
||||
@(link_name="llvm.ctlz.i64") __llvm_ctlz :: proc(i64, bool) -> i64 ---;
|
||||
@(link_name="llvm.ctlz.i128") __llvm_ctlz :: proc(u128, bool) -> u128 ---;
|
||||
@(link_name="llvm.ctlz.i128") __llvm_ctlz :: proc(i128, bool) -> i128 ---;
|
||||
@(link_name="llvm.ctlz.i8") __llvm_ctlz8 :: proc(u8, bool) -> u8 ---;
|
||||
@(link_name="llvm.ctlz.i16") __llvm_ctlz16 :: proc(u16, bool) -> u16 ---;
|
||||
@(link_name="llvm.ctlz.i32") __llvm_ctlz32 :: proc(u32, bool) -> u32 ---;
|
||||
@(link_name="llvm.ctlz.i64") __llvm_ctlz64 :: proc(u64, bool) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.cttz.i8") __llvm_cttz :: proc(u8, bool) -> u8 ---;
|
||||
@(link_name="llvm.cttz.i8") __llvm_cttz :: proc(i8, bool) -> i8 ---;
|
||||
@(link_name="llvm.cttz.i16") __llvm_cttz :: proc(u16, bool) -> u16 ---;
|
||||
@(link_name="llvm.cttz.i16") __llvm_cttz :: proc(i16, bool) -> i16 ---;
|
||||
@(link_name="llvm.cttz.i32") __llvm_cttz :: proc(u32, bool) -> u32 ---;
|
||||
@(link_name="llvm.cttz.i32") __llvm_cttz :: proc(i32, bool) -> i32 ---;
|
||||
@(link_name="llvm.cttz.i64") __llvm_cttz :: proc(u64, bool) -> u64 ---;
|
||||
@(link_name="llvm.cttz.i64") __llvm_cttz :: proc(i64, bool) -> i64 ---;
|
||||
@(link_name="llvm.cttz.i128") __llvm_cttz :: proc(u128, bool) -> u128 ---;
|
||||
@(link_name="llvm.cttz.i128") __llvm_cttz :: proc(i128, bool) -> i128 ---;
|
||||
@(link_name="llvm.cttz.i8") __llvm_cttz8 :: proc(u8, bool) -> u8 ---;
|
||||
@(link_name="llvm.cttz.i16") __llvm_cttz16 :: proc(u16, bool) -> u16 ---;
|
||||
@(link_name="llvm.cttz.i32") __llvm_cttz32 :: proc(u32, bool) -> u32 ---;
|
||||
@(link_name="llvm.cttz.i64") __llvm_cttz64 :: proc(u64, bool) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse :: proc(u8) -> u8 ---;
|
||||
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse :: proc(i8) -> i8 ---;
|
||||
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse :: proc(i16) -> i16 ---;
|
||||
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse :: proc(i32) -> i32 ---;
|
||||
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse :: proc(u64) -> u64 ---;
|
||||
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse :: proc(i64) -> i64 ---;
|
||||
@(link_name="llvm.bitreverse.i128") __llvm_bitreverse :: proc(u128) -> u128 ---;
|
||||
@(link_name="llvm.bitreverse.i128") __llvm_bitreverse :: proc(i128) -> i128 ---;
|
||||
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse8 :: proc(u8) -> u8 ---;
|
||||
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse16 :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse32 :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse64 :: proc(u64) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.bswap.i16") byte_swap :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.bswap.i16") byte_swap :: proc(i16) -> i16 ---;
|
||||
@(link_name="llvm.bswap.i32") byte_swap :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.bswap.i32") byte_swap :: proc(i32) -> i32 ---;
|
||||
@(link_name="llvm.bswap.i64") byte_swap :: proc(u64) -> u64 ---;
|
||||
@(link_name="llvm.bswap.i64") byte_swap :: proc(i64) -> i64 ---;
|
||||
@(link_name="llvm.bswap.i128") byte_swap :: proc(u128) -> u128 ---;
|
||||
@(link_name="llvm.bswap.i128") byte_swap :: proc(i128) -> i128 ---;
|
||||
@(link_name="llvm.bswap.i16") byte_swap16 :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.bswap.i32") byte_swap32 :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.bswap.i64") byte_swap64 :: proc(u64) -> u64 ---;
|
||||
}
|
||||
byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
|
||||
byte_swap :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(byte_swap(i32(i))); } else { return int(byte_swap(i64(i))); } }
|
||||
|
||||
count_ones :: proc(i: u8) -> u8 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i8) -> i8 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u16) -> u16 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i16) -> i16 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u32) -> u32 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i32) -> i32 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u64) -> u64 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i64) -> i64 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: u128) -> u128 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: i128) -> i128 { return __llvm_ctpop(i); }
|
||||
count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
|
||||
count_ones :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
|
||||
|
||||
count_zeros :: proc(i: u8) -> u8 { return 8 - count_ones(i); }
|
||||
count_zeros :: proc(i: i8) -> i8 { return 8 - count_ones(i); }
|
||||
count_zeros :: proc(i: u16) -> u16 { return 16 - count_ones(i); }
|
||||
count_zeros :: proc(i: i16) -> i16 { return 16 - count_ones(i); }
|
||||
count_zeros :: proc(i: u32) -> u32 { return 32 - count_ones(i); }
|
||||
count_zeros :: proc(i: i32) -> i32 { return 32 - count_ones(i); }
|
||||
count_zeros :: proc(i: u64) -> u64 { return 64 - count_ones(i); }
|
||||
count_zeros :: proc(i: i64) -> i64 { return 64 - count_ones(i); }
|
||||
count_zeros :: proc(i: u128) -> u128 { return 128 - count_ones(i); }
|
||||
count_zeros :: proc(i: i128) -> i128 { return 128 - count_ones(i); }
|
||||
count_zeros :: proc(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
|
||||
count_zeros :: proc(i: int) -> int { return 8*size_of(int) - count_ones(i); }
|
||||
|
||||
|
||||
rotate_left :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
|
||||
rotate_left :: proc(i: i8, s: uint) -> i8 { return (i << s)|(i >> (8*size_of(i8) - s)); }
|
||||
rotate_left :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
|
||||
rotate_left :: proc(i: i16, s: uint) -> i16 { return (i << s)|(i >> (8*size_of(i16) - s)); }
|
||||
rotate_left :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
|
||||
rotate_left :: proc(i: i32, s: uint) -> i32 { return (i << s)|(i >> (8*size_of(i32) - s)); }
|
||||
rotate_left :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
|
||||
rotate_left :: proc(i: i64, s: uint) -> i64 { return (i << s)|(i >> (8*size_of(i64) - s)); }
|
||||
rotate_left :: proc(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
|
||||
rotate_left :: proc(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
|
||||
rotate_left :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
|
||||
rotate_left :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_left(i32(i), s)); } else { return int(rotate_left(i64(i), s)); } }
|
||||
|
||||
|
||||
rotate_right :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
|
||||
rotate_right :: proc(i: i8, s: uint) -> i8 { return (i >> s)|(i << (8*size_of(i8) - s)); }
|
||||
rotate_right :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
|
||||
rotate_right :: proc(i: i16, s: uint) -> i16 { return (i >> s)|(i << (8*size_of(i16) - s)); }
|
||||
rotate_right :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
|
||||
rotate_right :: proc(i: i32, s: uint) -> i32 { return (i >> s)|(i << (8*size_of(i32) - s)); }
|
||||
rotate_right :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
|
||||
rotate_right :: proc(i: i64, s: uint) -> i64 { return (i >> s)|(i << (8*size_of(i64) - s)); }
|
||||
rotate_right :: proc(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
|
||||
rotate_right :: proc(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
|
||||
rotate_right :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
|
||||
rotate_right :: proc(i: int, s: uint) -> int { when size_of(int) == size_of(i32) { return int(rotate_right(i32(i), s)); } else { return int(rotate_right(i64(i), s)); } }
|
||||
|
||||
leading_zeros :: proc(i: u8) -> u8 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i8) -> i8 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u16) -> u16 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i16) -> i16 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u32) -> u32 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i32) -> i32 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u64) -> u64 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i64) -> i64 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: u128) -> u128 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: i128) -> i128 { return __llvm_ctlz(i, false); }
|
||||
leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
|
||||
leading_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(leading_zeros(i32(i))); } else { return int(leading_zeros(i64(i))); } }
|
||||
|
||||
trailing_zeros :: proc(i: u8) -> u8 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i8) -> i8 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u16) -> u16 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i16) -> i16 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u32) -> u32 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i32) -> i32 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u64) -> u64 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i64) -> i64 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: u128) -> u128 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: i128) -> i128 { return __llvm_cttz(i, false); }
|
||||
trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
|
||||
trailing_zeros :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(trailing_zeros(i32(i))); } else { return int(trailing_zeros(i64(i))); } }
|
||||
|
||||
|
||||
reverse_bits :: proc(i: u8) -> u8 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i8) -> i8 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u16) -> u16 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i16) -> i16 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u32) -> u32 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i32) -> i32 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u64) -> u64 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i64) -> i64 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: u128) -> u128 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: i128) -> i128 { return __llvm_bitreverse(i); }
|
||||
reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
|
||||
reverse_bits :: proc(i: int) -> int { when size_of(int) == size_of(i32) { return int(reverse_bits(i32(i))); } else { return int(reverse_bits(i64(i))); } }
|
||||
|
||||
from_be :: proc(i: u8) -> u8 { return i; }
|
||||
from_be :: proc(i: i8) -> i8 { return i; }
|
||||
from_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
from_le :: proc(i: u8) -> u8 { return i; }
|
||||
from_le :: proc(i: i8) -> i8 { return i; }
|
||||
from_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
to_be :: proc(i: u8) -> u8 { return i; }
|
||||
to_be :: proc(i: i8) -> i8 { return i; }
|
||||
to_be :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be :: proc(i: int) -> int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
to_le :: proc(i: u8) -> u8 { return i; }
|
||||
to_le :: proc(i: i8) -> i8 { return i; }
|
||||
to_le :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i16) -> i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i32) -> i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i64) -> i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le :: proc(i: int) -> int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
overflowing_add :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
byte_swap_uint :: proc(i: uint) -> uint {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_add(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
return uint(byte_swap32(u32(i)));
|
||||
} else {
|
||||
x, ok := overflowing_add(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_add :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_add(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_add(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
return uint(byte_swap64(u64(i)));
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_sub :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
byte_swap :: proc[byte_swap16, byte_swap32, byte_swap64, byte_swap_uint];
|
||||
|
||||
count_ones8 :: proc(i: u8) -> u8 { return __llvm_ctpop8(i); }
|
||||
count_ones16 :: proc(i: u16) -> u16 { return __llvm_ctpop16(i); }
|
||||
count_ones32 :: proc(i: u32) -> u32 { return __llvm_ctpop32(i); }
|
||||
count_ones64 :: proc(i: u64) -> u64 { return __llvm_ctpop64(i); }
|
||||
|
||||
count_zeros8 :: proc(i: u8) -> u8 { return 8 - count_ones8(i); }
|
||||
count_zeros16 :: proc(i: u16) -> u16 { return 16 - count_ones16(i); }
|
||||
count_zeros32 :: proc(i: u32) -> u32 { return 32 - count_ones32(i); }
|
||||
count_zeros64 :: proc(i: u64) -> u64 { return 64 - count_ones64(i); }
|
||||
|
||||
|
||||
rotate_left8 :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
|
||||
rotate_left16 :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
|
||||
rotate_left32 :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
|
||||
rotate_left64 :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
|
||||
|
||||
|
||||
rotate_right8 :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
|
||||
rotate_right16 :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
|
||||
rotate_right32 :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
|
||||
rotate_right64 :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
|
||||
|
||||
leading_zeros8 :: proc(i: u8) -> u8 { return __llvm_ctlz8(i, false); }
|
||||
leading_zeros16 :: proc(i: u16) -> u16 { return __llvm_ctlz16(i, false); }
|
||||
leading_zeros32 :: proc(i: u32) -> u32 { return __llvm_ctlz32(i, false); }
|
||||
leading_zeros64 :: proc(i: u64) -> u64 { return __llvm_ctlz64(i, false); }
|
||||
|
||||
trailing_zeros8 :: proc(i: u8) -> u8 { return __llvm_cttz8(i, false); }
|
||||
trailing_zeros16 :: proc(i: u16) -> u16 { return __llvm_cttz16(i, false); }
|
||||
trailing_zeros32 :: proc(i: u32) -> u32 { return __llvm_cttz32(i, false); }
|
||||
trailing_zeros64 :: proc(i: u64) -> u64 { return __llvm_cttz64(i, false); }
|
||||
|
||||
|
||||
reverse_bits8 :: proc(i: u8) -> u8 { return __llvm_bitreverse8(i); }
|
||||
reverse_bits16 :: proc(i: u16) -> u16 { return __llvm_bitreverse16(i); }
|
||||
reverse_bits32 :: proc(i: u32) -> u32 { return __llvm_bitreverse32(i); }
|
||||
reverse_bits64 :: proc(i: u64) -> u64 { return __llvm_bitreverse64(i); }
|
||||
|
||||
from_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
from_le_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
to_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
to_le_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
overflowing_add_u8 :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i8 :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_u16 :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i16 :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_u32 :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i32 :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_u64 :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i64 :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_sub(u32(lhs), u32(rhs));
|
||||
x, ok := overflowing_add_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_sub(u64(lhs), u64(rhs));
|
||||
x, ok := overflowing_add_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_sub :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
overflowing_add_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_sub(i32(lhs), i32(rhs));
|
||||
x, ok := overflowing_add_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_sub(i64(lhs), i64(rhs));
|
||||
x, ok := overflowing_add_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_mul :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i128") op :: proc(u128, u128) -> (u128, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i128") op :: proc(i128, i128) -> (i128, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
overflowing_add :: proc[
|
||||
overflowing_add_u8, overflowing_add_i8,
|
||||
overflowing_add_u16, overflowing_add_i16,
|
||||
overflowing_add_u32, overflowing_add_i32,
|
||||
overflowing_add_u64, overflowing_add_i64,
|
||||
overflowing_add_uint, overflowing_add_int,
|
||||
];
|
||||
|
||||
overflowing_sub_u8 :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i8 :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_u16 :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i16 :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_u32 :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i32 :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_u64 :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i64 :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_mul(u32(lhs), u32(rhs));
|
||||
x, ok := overflowing_sub_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul(u64(lhs), u64(rhs));
|
||||
x, ok := overflowing_sub_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_mul :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
overflowing_sub_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_mul(i32(lhs), i32(rhs));
|
||||
x, ok := overflowing_sub_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul(i64(lhs), i64(rhs));
|
||||
x, ok := overflowing_sub_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
is_power_of_two :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
overflowing_sub :: proc[
|
||||
overflowing_sub_u8, overflowing_sub_i8,
|
||||
overflowing_sub_u16, overflowing_sub_i16,
|
||||
overflowing_sub_u32, overflowing_sub_i32,
|
||||
overflowing_sub_u64, overflowing_sub_i64,
|
||||
overflowing_sub_uint, overflowing_sub_int,
|
||||
];
|
||||
|
||||
|
||||
overflowing_mul_u8 :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i8 :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_u16 :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i16 :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_u32 :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i32 :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_u64 :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i64 :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_mul_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_mul_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_mul_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_mul :: proc[
|
||||
overflowing_mul_u8, overflowing_mul_i8,
|
||||
overflowing_mul_u16, overflowing_mul_i16,
|
||||
overflowing_mul_u32, overflowing_mul_i32,
|
||||
overflowing_mul_u64, overflowing_mul_i64,
|
||||
overflowing_mul_uint, overflowing_mul_int,
|
||||
];
|
||||
|
||||
is_power_of_two_u8 :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i8 :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u16 :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i16 :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u32 :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i32 :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u64 :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i64 :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_uint :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_int :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
|
||||
is_power_of_two :: proc[
|
||||
is_power_of_two_u8, is_power_of_two_i8,
|
||||
is_power_of_two_u16, is_power_of_two_i16,
|
||||
is_power_of_two_u32, is_power_of_two_i32,
|
||||
is_power_of_two_u64, is_power_of_two_i64,
|
||||
is_power_of_two_uint, is_power_of_two_int,
|
||||
]
|
||||
|
||||
+24
-24
@@ -1,38 +1,38 @@
|
||||
CHAR_BIT :: 8;
|
||||
|
||||
c_bool :: #alias bool;
|
||||
c_char :: #alias u8;
|
||||
c_byte :: #alias u8;
|
||||
c_schar :: #alias i8;
|
||||
c_uchar :: #alias u8;
|
||||
c_short :: #alias i16;
|
||||
c_ushort :: #alias u16;
|
||||
c_int :: #alias i32;
|
||||
c_uint :: #alias u32;
|
||||
c_bool :: bool;
|
||||
c_char :: u8;
|
||||
c_byte :: u8;
|
||||
c_schar :: i8;
|
||||
c_uchar :: u8;
|
||||
c_short :: i16;
|
||||
c_ushort :: u16;
|
||||
c_int :: i32;
|
||||
c_uint :: u32;
|
||||
|
||||
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
|
||||
c_long :: #alias i32;
|
||||
c_long :: i32;
|
||||
} else {
|
||||
c_long :: #alias i64;
|
||||
c_long :: i64;
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
|
||||
c_ulong :: #alias u32;
|
||||
c_ulong :: u32;
|
||||
} else {
|
||||
c_ulong :: #alias u64;
|
||||
c_ulong :: u64;
|
||||
}
|
||||
|
||||
c_longlong :: #alias i64;
|
||||
c_ulonglong :: #alias u64;
|
||||
c_float :: #alias f32;
|
||||
c_double :: #alias f64;
|
||||
c_complex_float :: #alias complex64;
|
||||
c_complex_double :: #alias complex128;
|
||||
c_longlong :: i64;
|
||||
c_ulonglong :: u64;
|
||||
c_float :: f32;
|
||||
c_double :: f64;
|
||||
c_complex_float :: complex64;
|
||||
c_complex_double :: complex128;
|
||||
|
||||
_ :: compile_assert(size_of(uintptr) == size_of(int));
|
||||
|
||||
c_size_t :: #alias uint;
|
||||
c_ssize_t :: #alias int;
|
||||
c_ptrdiff_t :: #alias int;
|
||||
c_uintptr_t :: #alias uintptr;
|
||||
c_intptr_t :: #alias int;
|
||||
c_size_t :: uint;
|
||||
c_ssize_t :: int;
|
||||
c_ptrdiff_t :: int;
|
||||
c_uintptr_t :: uintptr;
|
||||
c_intptr_t :: int;
|
||||
|
||||
+9
-9
@@ -2,14 +2,14 @@
|
||||
// NOTE: This is only for floating point printing and nothing else
|
||||
|
||||
Decimal :: struct {
|
||||
digits: [384]u8, // big-endian digits
|
||||
digits: [384]byte, // big-endian digits
|
||||
count: int,
|
||||
decimal_point: int,
|
||||
neg, trunc: bool,
|
||||
}
|
||||
|
||||
decimal_to_string :: proc(buf: []u8, a: ^Decimal) -> string {
|
||||
digit_zero :: proc(buf: []u8) -> int {
|
||||
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||
digit_zero :: proc(buf: []byte) -> int {
|
||||
for _, i in buf do buf[i] = '0';
|
||||
return len(buf);
|
||||
}
|
||||
@@ -56,12 +56,12 @@ trim :: proc(a: ^Decimal) {
|
||||
|
||||
|
||||
assign :: proc(a: ^Decimal, i: u64) {
|
||||
buf: [64]u8;
|
||||
buf: [64]byte;
|
||||
n := 0;
|
||||
for i > 0 {
|
||||
j := i/10;
|
||||
i -= 10*j;
|
||||
buf[n] = u8('0'+i);
|
||||
buf[n] = byte('0'+i);
|
||||
n += 1;
|
||||
i = j;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
c := uint(a.digits[r]);
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
a.digits[w] = u8('0' + dig);
|
||||
a.digits[w] = byte('0' + dig);
|
||||
w += 1;
|
||||
n = n*10 + c - '0';
|
||||
}
|
||||
@@ -115,7 +115,7 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
dig := n>>k;
|
||||
n &= mask;
|
||||
if w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + dig);
|
||||
a.digits[w] = byte('0' + dig);
|
||||
w += 1;
|
||||
} else if dig > 0 {
|
||||
a.trunc = true;
|
||||
@@ -141,7 +141,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
rem := n - 10*quo;
|
||||
w -= 1;
|
||||
if w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + rem);
|
||||
a.digits[w] = byte('0' + rem);
|
||||
} else if rem != 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
@@ -153,7 +153,7 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
rem := n - 10*quo;
|
||||
w -= 1;
|
||||
if 0 <= w && w < len(a.digits) {
|
||||
a.digits[w] = u8('0' + rem);
|
||||
a.digits[w] = byte('0' + rem);
|
||||
} else if rem != 0 {
|
||||
a.trunc = true;
|
||||
}
|
||||
|
||||
+181
-233
@@ -8,10 +8,7 @@ import "core:raw.odin"
|
||||
|
||||
_BUFFER_SIZE :: 1<<12;
|
||||
|
||||
String_Buffer :: union {
|
||||
[]u8,
|
||||
[dynamic]u8,
|
||||
}
|
||||
String_Buffer :: distinct [dynamic]byte;
|
||||
|
||||
Fmt_Info :: struct {
|
||||
minus: bool,
|
||||
@@ -33,45 +30,35 @@ Fmt_Info :: struct {
|
||||
arg: any, // Temporary
|
||||
}
|
||||
|
||||
string_buffer_from_slice :: proc(backing: []byte) -> String_Buffer {
|
||||
s := transmute(raw.Slice)backing;
|
||||
d := raw.Dynamic_Array{
|
||||
data = s.data,
|
||||
len = 0,
|
||||
cap = s.len,
|
||||
allocator = nil_allocator(),
|
||||
};
|
||||
return transmute(String_Buffer)d;
|
||||
}
|
||||
|
||||
|
||||
string_buffer_data :: proc(buf: ^String_Buffer) -> []u8 {
|
||||
switch b in buf {
|
||||
case []u8: return b[..];
|
||||
case [dynamic]u8: return b[..];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
string_buffer_data :: proc(buf: String_Buffer) -> []u8 {
|
||||
switch b in buf {
|
||||
case []u8: return b[..];
|
||||
case [dynamic]u8: return b[..];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
to_string :: proc(buf: String_Buffer) -> string {
|
||||
return string(string_buffer_data(buf));
|
||||
return string(buf[..]);
|
||||
}
|
||||
|
||||
|
||||
write_string :: proc(buf: ^String_Buffer, s: string) {
|
||||
write_bytes(buf, cast([]u8)s);
|
||||
append_string(buf, s);
|
||||
}
|
||||
write_bytes :: proc(buf: ^String_Buffer, data: []u8) {
|
||||
switch b in buf {
|
||||
case []u8: append(b, ...data);
|
||||
case [dynamic]u8: append(b, ...data);
|
||||
}
|
||||
write_bytes :: proc(buf: ^String_Buffer, data: []byte) {
|
||||
append(buf, ...data);
|
||||
}
|
||||
write_byte :: proc(buf: ^String_Buffer, data: u8) {
|
||||
switch b in buf {
|
||||
case []u8: append(b, data);
|
||||
case [dynamic]u8: append(b, data);
|
||||
}
|
||||
write_byte :: proc(buf: ^String_Buffer, data: byte) {
|
||||
append(buf, data);
|
||||
}
|
||||
write_rune :: proc(buf: ^String_Buffer, r: rune) {
|
||||
if r < utf8.RUNE_SELF {
|
||||
write_byte(buf, u8(r));
|
||||
write_byte(buf, byte(r));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,42 +66,32 @@ write_rune :: proc(buf: ^String_Buffer, r: rune) {
|
||||
write_bytes(buf, b[..n]);
|
||||
}
|
||||
|
||||
write_int :: proc(buf: ^String_Buffer, i: i128, base: int) {
|
||||
b: [129]u8;
|
||||
s := strconv.append_bits(b[..0], u128(i), base, true, 128, strconv.digits, 0);
|
||||
write_i64 :: proc(buf: ^String_Buffer, i: i64, base: int) {
|
||||
b: [129]byte;
|
||||
s := strconv.append_bits(b[..], u64(i), base, true, 64, strconv.digits, 0);
|
||||
write_string(buf, s);
|
||||
}
|
||||
write_int :: proc(buf: ^String_Buffer, i: i64, base: int) {
|
||||
b: [129]u8;
|
||||
s := strconv.append_bits(b[..0], u128(i), base, true, 64, strconv.digits, 0);
|
||||
write_string(buf, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
fprint :: proc(fd: os.Handle, args: ...any) -> int {
|
||||
data: [_BUFFER_SIZE]u8;
|
||||
buf := String_Buffer(data[..0]);
|
||||
sbprint(&buf, ...args);
|
||||
res := string_buffer_data(buf);
|
||||
os.write(fd, res);
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
res := sbprint(&buf, ...args);
|
||||
os.write_string(fd, res);
|
||||
return len(res);
|
||||
}
|
||||
|
||||
fprintln :: proc(fd: os.Handle, args: ...any) -> int {
|
||||
data: [_BUFFER_SIZE]u8;
|
||||
buf := String_Buffer(data[..0]);
|
||||
sbprintln(&buf, ...args);
|
||||
res := string_buffer_data(buf);
|
||||
os.write(fd, res);
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
res := sbprintln(&buf, ...args);
|
||||
os.write_string(fd, res);
|
||||
return len(res);
|
||||
}
|
||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
|
||||
data: [_BUFFER_SIZE]u8;
|
||||
buf := String_Buffer(data[..0]);
|
||||
sbprintf(&buf, fmt, ...args);
|
||||
res := string_buffer_data(buf);
|
||||
os.write(fd, res);
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
res := sbprintf(&buf, fmt, ...args);
|
||||
os.write_string(fd, res);
|
||||
return len(res);
|
||||
}
|
||||
|
||||
@@ -131,33 +108,33 @@ printf_err :: proc(fmt: string, args: ...any) -> int { return fprintf(os.stderr
|
||||
// aprint* procedures return a string that was allocated with the current context
|
||||
// They must be freed accordingly
|
||||
aprint :: proc(args: ...any) -> string {
|
||||
buf := String_Buffer(make([dynamic]u8));
|
||||
buf := String_Buffer(make([dynamic]byte));
|
||||
sbprint(&buf, ...args);
|
||||
return to_string(buf);
|
||||
}
|
||||
aprintln :: proc(args: ...any) -> string {
|
||||
buf := String_Buffer(make([dynamic]u8));
|
||||
buf := String_Buffer(make([dynamic]byte));
|
||||
sbprintln(&buf, ...args);
|
||||
return to_string(buf);
|
||||
}
|
||||
aprintf :: proc(fmt: string, args: ...any) -> string {
|
||||
buf := String_Buffer(make([dynamic]u8));
|
||||
buf := String_Buffer(make([dynamic]byte));
|
||||
sbprintf(&buf, fmt, ...args);
|
||||
return to_string(buf);
|
||||
}
|
||||
|
||||
|
||||
// bprint* procedures return a string using a buffer from an array
|
||||
bprint :: proc(buf: []u8, args: ...any) -> string {
|
||||
sb := String_Buffer(buf[..0..len(buf)]);
|
||||
bprint :: proc(buf: []byte, args: ...any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0..len(buf)]);
|
||||
return sbprint(&sb, ...args);
|
||||
}
|
||||
bprintln :: proc(buf: []u8, args: ...any) -> string {
|
||||
sb := String_Buffer(buf[..0..len(buf)]);
|
||||
bprintln :: proc(buf: []byte, args: ...any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0..len(buf)]);
|
||||
return sbprintln(&sb, ...args);
|
||||
}
|
||||
bprintf :: proc(buf: []u8, fmt: string, args: ...any) -> string {
|
||||
sb := String_Buffer(buf[..0..len(buf)]);
|
||||
bprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0..len(buf)]);
|
||||
return sbprintf(&sb, fmt, ...args);
|
||||
}
|
||||
|
||||
@@ -167,10 +144,10 @@ bprintf :: proc(buf: []u8, fmt: string, args: ...any) -> string {
|
||||
|
||||
|
||||
fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
|
||||
data: [_BUFFER_SIZE]u8;
|
||||
buf := String_Buffer(data[..0]);
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
write_type(&buf, info);
|
||||
os.write(fd, string_buffer_data(buf));
|
||||
os.write(fd, buf[..]);
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
@@ -183,31 +160,33 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
case Type_Info_Named:
|
||||
write_string(buf, info.name);
|
||||
case Type_Info_Integer:
|
||||
switch {
|
||||
case ti == type_info_of(int): write_string(buf, "int");
|
||||
case ti == type_info_of(uint): write_string(buf, "uint");
|
||||
case ti == type_info_of(uintptr): write_string(buf, "uintptr");
|
||||
a := any{type_info = ti};
|
||||
switch _ in a {
|
||||
case int: write_string(buf, "int");
|
||||
case uint: write_string(buf, "uint");
|
||||
case uintptr: write_string(buf, "uintptr");
|
||||
case:
|
||||
if info.signed do write_byte(buf, 'i');
|
||||
else do write_byte(buf, 'u');
|
||||
write_int(buf, i64(8*ti.size), 10);
|
||||
write_byte(buf, info.signed ? 'i' : 'u');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
write_string(buf, "rune");
|
||||
case Type_Info_Float:
|
||||
switch ti.size {
|
||||
case 2: write_string(buf, "f16");
|
||||
case 4: write_string(buf, "f32");
|
||||
case 8: write_string(buf, "f64");
|
||||
}
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case Type_Info_Complex:
|
||||
switch ti.size {
|
||||
case 4: write_string(buf, "complex32");
|
||||
case 8: write_string(buf, "complex64");
|
||||
case 16: write_string(buf, "complex128");
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case Type_Info_String:
|
||||
write_string(buf, "string");
|
||||
case Type_Info_Boolean:
|
||||
a := any{type_info = ti};
|
||||
switch _ in a {
|
||||
case bool: write_string(buf, "bool");
|
||||
case:
|
||||
write_byte(buf, 'b');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case Type_Info_String: write_string(buf, "string");
|
||||
case Type_Info_Boolean: write_string(buf, "bool");
|
||||
case Type_Info_Any:
|
||||
write_string(buf, "any");
|
||||
|
||||
@@ -253,8 +232,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
|
||||
case Type_Info_Array:
|
||||
write_string(buf, "[");
|
||||
fi := Fmt_Info{buf = buf};
|
||||
write_int(buf, i64(info.count), 10);
|
||||
write_i64(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
case Type_Info_Dynamic_Array:
|
||||
@@ -263,11 +241,6 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
case Type_Info_Slice:
|
||||
write_string(buf, "[]");
|
||||
write_type(buf, info.elem);
|
||||
case Type_Info_Vector:
|
||||
write_string(buf, "[vector ");
|
||||
write_int(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case Type_Info_Map:
|
||||
write_string(buf, "map[");
|
||||
@@ -278,11 +251,10 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
case Type_Info_Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.is_packed do write_string(buf, "#packed ");
|
||||
if info.is_ordered do write_string(buf, "#ordered ");
|
||||
if info.is_raw_union do write_string(buf, "#raw_union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_int(buf, i64(ti.align), 10);
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
@@ -305,6 +277,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
case Type_Info_Enum:
|
||||
write_string(buf, "enum ");
|
||||
write_type(buf, info.base);
|
||||
if info.is_export do write_string(buf, " #export");
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
@@ -316,7 +289,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
write_string(buf, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
write_string(buf, "#align ");
|
||||
write_int(buf, i64(ti.align), 10);
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_rune(buf, ' ');
|
||||
}
|
||||
write_string(buf, " {");
|
||||
@@ -324,35 +297,30 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_int(buf, i64(info.bits[i]), 10);
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_string(buf, "}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
|
||||
is_digit :: inline proc(r: rune) -> bool{
|
||||
return '0' <= r && r <= '9';
|
||||
}
|
||||
_parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok: bool) {
|
||||
is_digit :: inline proc(r: byte) -> bool { return '0' <= r && r <= '9' }
|
||||
|
||||
result := 0;
|
||||
ok := true;
|
||||
|
||||
i := 0;
|
||||
for i < len(s[offset..]) {
|
||||
c := rune(s[offset+i]);
|
||||
new_offset = offset;
|
||||
for new_offset <= len(s) {
|
||||
c := s[new_offset];
|
||||
if !is_digit(c) do break;
|
||||
i += 1;
|
||||
new_offset += 1;
|
||||
|
||||
result *= 10;
|
||||
result += int(c)-'0';
|
||||
}
|
||||
|
||||
return result, offset+i, i != 0;
|
||||
ok = new_offset > offset;
|
||||
return;
|
||||
}
|
||||
|
||||
_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_count: int) -> (index, offset: int, ok: bool) {
|
||||
_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_count: int) -> (index, new_offset: int, ok: bool) {
|
||||
parse_arg_number :: proc(format: string) -> (int, int, bool) {
|
||||
if len(format) < 3 do return 0, 1, false;
|
||||
|
||||
@@ -374,7 +342,9 @@ _arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_c
|
||||
return arg_index, offset, false;
|
||||
}
|
||||
fi.reordered = true;
|
||||
index, width, ok := parse_arg_number(format[offset..]);
|
||||
|
||||
width: int;
|
||||
index, width, ok = parse_arg_number(format[offset..]);
|
||||
if ok && 0 <= index && index < arg_count {
|
||||
return index, offset+width, true;
|
||||
}
|
||||
@@ -426,9 +396,7 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
|
||||
fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
|
||||
switch verb {
|
||||
case 't', 'v':
|
||||
s := "false";
|
||||
if b do s = "true";
|
||||
write_string(buf, s);
|
||||
write_string(buf, b ? "true" : "false");
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
}
|
||||
@@ -438,7 +406,7 @@ fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) {
|
||||
fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
|
||||
if width <= 0 do return;
|
||||
|
||||
pad_byte: u8 = '0';
|
||||
pad_byte: byte = '0';
|
||||
if fi.space do pad_byte = ' ';
|
||||
|
||||
for _ in 0..width {
|
||||
@@ -446,8 +414,8 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
|
||||
}
|
||||
}
|
||||
|
||||
_fmt_int :: proc(fi: ^Fmt_Info, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
|
||||
_, neg := strconv.is_integer_negative(u128(u), is_signed, bit_size);
|
||||
_fmt_int :: proc(fi: ^Fmt_Info, u: u64, base: int, is_signed: bool, bit_size: int, digits: string) {
|
||||
_, neg := strconv.is_integer_negative(u, is_signed, bit_size);
|
||||
|
||||
BUF_SIZE :: 256;
|
||||
if fi.width_set || fi.prec_set {
|
||||
@@ -483,21 +451,20 @@ _fmt_int :: proc(fi: ^Fmt_Info, u: u128, base: int, is_signed: bool, bit_size: i
|
||||
panic("_fmt_int: unknown base, whoops");
|
||||
}
|
||||
|
||||
buf: [256]u8;
|
||||
buf: [256]byte;
|
||||
start := 0;
|
||||
|
||||
flags: strconv.Int_Flag;
|
||||
if fi.hash && !fi.zero do flags |= strconv.Int_Flag.Prefix;
|
||||
if fi.plus do flags |= strconv.Int_Flag.Plus;
|
||||
if fi.space do flags |= strconv.Int_Flag.Space;
|
||||
s := strconv.append_bits(buf[start..start], u128(u), base, is_signed, bit_size, digits, flags);
|
||||
s := strconv.append_bits(buf[start..], u, base, is_signed, bit_size, digits, flags);
|
||||
|
||||
if fi.hash && fi.zero {
|
||||
c: u8;
|
||||
c: byte = 0;
|
||||
switch base {
|
||||
case 2: c = 'b';
|
||||
case 8: c = 'o';
|
||||
// case 10: c = 'd';
|
||||
case 12: c = 'z';
|
||||
case 16: c = 'x';
|
||||
}
|
||||
@@ -522,11 +489,11 @@ fmt_rune :: proc(fi: ^Fmt_Info, r: rune, verb: rune) {
|
||||
case 'c', 'r', 'v':
|
||||
write_rune(fi.buf, r);
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
fmt_int(fi, u64(r), false, 32, verb);
|
||||
}
|
||||
}
|
||||
|
||||
fmt_int :: proc(fi: ^Fmt_Info, u: u128, is_signed: bool, bit_size: int, verb: rune) {
|
||||
fmt_int :: proc(fi: ^Fmt_Info, u: u64, is_signed: bool, bit_size: int, verb: rune) {
|
||||
switch verb {
|
||||
case 'v': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
|
||||
case 'b': _fmt_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER);
|
||||
@@ -558,7 +525,7 @@ _pad :: proc(fi: ^Fmt_Info, s: string) {
|
||||
}
|
||||
|
||||
|
||||
width := fi.width - utf8.rune_count(s);
|
||||
width := fi.width - utf8.rune_count_from_string(s);
|
||||
if fi.minus { // right pad
|
||||
write_string(fi.buf, s);
|
||||
fmt_write_padding(fi, width);
|
||||
@@ -576,9 +543,9 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
||||
case 'f', 'F', 'v':
|
||||
prec: int = 3;
|
||||
if fi.prec_set do prec = fi.prec;
|
||||
buf: [386]u8;
|
||||
buf: [386]byte;
|
||||
|
||||
str := strconv.append_float(buf[1..1], v, 'f', prec, bit_size);
|
||||
str := strconv.append_float(buf[1..], v, 'f', prec, bit_size);
|
||||
str = string(buf[...len(str)]);
|
||||
if str[1] == '+' || str[1] == '-' {
|
||||
str = str[1..];
|
||||
@@ -625,7 +592,7 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
||||
if i > 0 && space do write_byte(fi.buf, ' ');
|
||||
char_set := __DIGITS_UPPER;
|
||||
if verb == 'x' do char_set = __DIGITS_LOWER;
|
||||
_fmt_int(fi, u128(s[i]), 16, false, 8, char_set);
|
||||
_fmt_int(fi, u64(s[i]), 16, false, 8, char_set);
|
||||
}
|
||||
|
||||
case:
|
||||
@@ -636,16 +603,14 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
||||
fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
||||
switch verb {
|
||||
case 'p', 'v':
|
||||
// Okay
|
||||
u := u64(uintptr(p));
|
||||
if !fi.hash || verb == 'v' {
|
||||
write_string(fi.buf, "0x");
|
||||
}
|
||||
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
}
|
||||
u := u128(uintptr(p));
|
||||
if !fi.hash || verb == 'v' {
|
||||
write_string(fi.buf, "0x");
|
||||
}
|
||||
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
|
||||
}
|
||||
|
||||
enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
@@ -680,13 +645,11 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
case i16: return get_str(v, e);
|
||||
case i32: return get_str(v, e);
|
||||
case i64: return get_str(v, e);
|
||||
case i128: return get_str(v, e);
|
||||
case int: return get_str(v, e);
|
||||
case u8: return get_str(v, e);
|
||||
case u16: return get_str(v, e);
|
||||
case u32: return get_str(v, e);
|
||||
case u64: return get_str(v, e);
|
||||
case u128: return get_str(v, e);
|
||||
case uint: return get_str(v, e);
|
||||
case uintptr: return get_str(v, e);
|
||||
|
||||
@@ -752,7 +715,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
write_string(fi.buf, info.name);
|
||||
write_string(fi.buf, "{}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
write_string(fi.buf, info.name);
|
||||
write_byte(fi.buf, '{');
|
||||
|
||||
@@ -774,7 +737,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if t := b.types[i]; types.is_any(t) {
|
||||
write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := cast(^u8)v.data + b.offsets[i];
|
||||
data := uintptr(v.data) + b.offsets[i];
|
||||
fmt_arg(fi, any{rawptr(data), t}, 'v');
|
||||
}
|
||||
|
||||
@@ -797,9 +760,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
|
||||
case Type_Info_Pointer:
|
||||
if v.type_info == type_info_of(^Type_Info) {
|
||||
write_type(fi.buf, (cast(^^Type_Info)v.data)^);
|
||||
write_type(fi.buf, (^^Type_Info)(v.data)^);
|
||||
} else {
|
||||
fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
|
||||
fmt_pointer(fi, (^rawptr)(v.data)^, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Array:
|
||||
@@ -808,7 +771,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
for i in 0..info.count {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := cast(^u8)v.data + i*info.elem_size;
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
|
||||
@@ -819,32 +782,21 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
for i in 0..array.len {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := cast(^u8)array.data + i*info.elem_size;
|
||||
data := uintptr(array.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Slice:
|
||||
write_byte(fi.buf, '[');
|
||||
defer write_byte(fi.buf, ']');
|
||||
slice := cast(^[]u8)v.data;
|
||||
for _, i in slice {
|
||||
slice := cast(^raw.Slice)v.data;
|
||||
for i in 0..slice.len {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := &slice[0] + i*info.elem_size;
|
||||
data := uintptr(slice.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Vector:
|
||||
write_byte(fi.buf, '<');
|
||||
defer write_byte(fi.buf, '>');
|
||||
|
||||
for i in 0..info.count {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := cast(^u8)v.data + i*info.elem_size;
|
||||
fmt_value(fi, any{rawptr(data), info.elem}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Map:
|
||||
if verb != 'v' {
|
||||
fmt_bad_verb(fi, verb);
|
||||
@@ -854,33 +806,35 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
write_string(fi.buf, "map[");
|
||||
defer write_byte(fi.buf, ']');
|
||||
|
||||
entries := &((cast(^raw.Map)v.data).entries);
|
||||
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
|
||||
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
|
||||
entry_type := ed.elem.variant.(Type_Info_Struct);
|
||||
entry_size := ed.elem_size;
|
||||
m := (^raw.Map)(v.data);
|
||||
if m != nil {
|
||||
assert(info.generated_struct != nil);
|
||||
entries := &m.entries;
|
||||
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
|
||||
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
|
||||
entry_type := ed.elem.variant.(Type_Info_Struct);
|
||||
entry_size := ed.elem_size;
|
||||
|
||||
for i in 0..entries.len {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
for i in 0..entries.len {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := cast(^u8)entries.data + i*entry_size;
|
||||
header := cast(^__Map_Entry_Header)data;
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||
header := cast(^__Map_Entry_Header)data;
|
||||
|
||||
if types.is_string(info.key) {
|
||||
write_string(fi.buf, header.key.str);
|
||||
} else {
|
||||
fi := Fmt_Info{buf = fi.buf};
|
||||
fmt_arg(&fi, any{rawptr(&header.key.hash), info.key}, 'v');
|
||||
if types.is_string(info.key) {
|
||||
write_string(fi.buf, header.key.str);
|
||||
} else {
|
||||
fi := Fmt_Info{buf = fi.buf};
|
||||
fmt_arg(&fi, any{rawptr(&header.key.hash), info.key}, 'v');
|
||||
}
|
||||
|
||||
write_string(fi.buf, "=");
|
||||
|
||||
value := data + entry_type.offsets[2];
|
||||
fmt_arg(fi, any{rawptr(value), info.value}, 'v');
|
||||
}
|
||||
|
||||
write_string(fi.buf, "=");
|
||||
|
||||
value := data + entry_type.offsets[2];
|
||||
fmt_arg(fi, any{rawptr(value), info.value}, 'v');
|
||||
}
|
||||
|
||||
|
||||
|
||||
case Type_Info_Struct:
|
||||
if info.is_raw_union {
|
||||
write_string(fi.buf, "(raw_union)");
|
||||
@@ -890,11 +844,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
write_byte(fi.buf, '{');
|
||||
defer write_byte(fi.buf, '}');
|
||||
|
||||
hash := fi.hash; defer fi.hash = hash;
|
||||
indent := fi.indent; defer fi.indent -= 1;
|
||||
|
||||
fi.indent += 1; defer fi.indent -= 1;
|
||||
hash := fi.hash; defer fi.hash = hash;
|
||||
fi.hash = false;
|
||||
fi.indent += 1;
|
||||
|
||||
|
||||
if hash do write_byte(fi.buf, '\n');
|
||||
|
||||
@@ -912,16 +865,15 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if t := info.types[i]; types.is_any(t) {
|
||||
write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := cast(^u8)v.data + info.offsets[i];
|
||||
data := uintptr(v.data) + info.offsets[i];
|
||||
fmt_arg(fi, any{rawptr(data), t}, 'v');
|
||||
}
|
||||
if hash do write_string(fi.buf, ",\n");
|
||||
}
|
||||
|
||||
case Type_Info_Union:
|
||||
data := cast(^u8)v.data;
|
||||
tag_ptr := rawptr(data + info.tag_offset);
|
||||
tag_any := any{tag_ptr, info.tag_type};
|
||||
tag_ptr := uintptr(v.data) + info.tag_offset;
|
||||
tag_any := any{rawptr(tag_ptr), info.tag_type};
|
||||
|
||||
tag: i64 = -1;
|
||||
switch i in tag_any {
|
||||
@@ -933,25 +885,28 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
case i32: tag = i64(i);
|
||||
case u64: tag = i64(i);
|
||||
case i64: tag = i64(i);
|
||||
case u128: tag = i64(i);
|
||||
case i128: tag = i64(i);
|
||||
case: panic("Invalid union tag type");
|
||||
}
|
||||
|
||||
if data == nil || tag <= 0 {
|
||||
write_string(fi.buf, "(union)");
|
||||
if v.data == nil || tag == 0 {
|
||||
write_string(fi.buf, "nil");
|
||||
} else {
|
||||
ti := info.variants[tag-1];
|
||||
fmt_arg(fi, any{data, ti}, verb);
|
||||
fmt_arg(fi, any{v.data, ti}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Enum:
|
||||
fmt_enum(fi, v, verb);
|
||||
|
||||
case Type_Info_Procedure:
|
||||
write_type(fi.buf, v.type_info);
|
||||
write_string(fi.buf, " @ ");
|
||||
fmt_pointer(fi, (cast(^rawptr)v.data)^, 'p');
|
||||
ptr := (^rawptr)(v.data)^;
|
||||
if ptr == nil {
|
||||
write_string(fi.buf, "nil");
|
||||
} else {
|
||||
write_type(fi.buf, v.type_info);
|
||||
write_string(fi.buf, " @ ");
|
||||
fmt_pointer(fi, ptr, 'p');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,14 +927,6 @@ fmt_complex :: proc(fi: ^Fmt_Info, c: complex128, bits: int, verb: rune) {
|
||||
}
|
||||
}
|
||||
|
||||
_u128_to_lo_hi :: proc(a: u128) -> (lo, hi: u64) { return u64(a), u64(a>>64); }
|
||||
_i128_to_lo_hi :: proc(a: u128) -> (lo: u64 hi: i64) { return u64(a), i64(a>>64); }
|
||||
|
||||
|
||||
do_foo :: proc(fi: ^Fmt_Info, f: f64) {
|
||||
fmt_string(fi, "Hellope$%!", 'v');
|
||||
}
|
||||
|
||||
fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
if arg == nil {
|
||||
write_string(fi.buf, "<nil>");
|
||||
@@ -996,35 +943,35 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
base_arg := arg;
|
||||
base_arg.type_info = type_info_base(base_arg.type_info);
|
||||
switch a in base_arg {
|
||||
case any: fmt_arg(fi, a, verb);
|
||||
case bool: fmt_bool(fi, a, verb);
|
||||
case rune: fmt_rune(fi, a, verb);
|
||||
case bool: fmt_bool(fi, bool(a), verb);
|
||||
case b8: fmt_bool(fi, bool(a), verb);
|
||||
case b16: fmt_bool(fi, bool(a), verb);
|
||||
case b32: fmt_bool(fi, bool(a), verb);
|
||||
case b64: fmt_bool(fi, bool(a), verb);
|
||||
|
||||
case f32: fmt_float(fi, f64(a), 32, verb);
|
||||
case f64: fmt_float(fi, a, 64, verb);
|
||||
case any: fmt_arg(fi, a, verb);
|
||||
case rune: fmt_rune(fi, a, verb);
|
||||
|
||||
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
case f32: fmt_float(fi, f64(a), 32, verb);
|
||||
case f64: fmt_float(fi, a, 64, verb);
|
||||
|
||||
case int: fmt_int(fi, u128(a), true, 8*size_of(int), verb);
|
||||
case i8: fmt_int(fi, u128(a), true, 8, verb);
|
||||
case i16: fmt_int(fi, u128(a), true, 16, verb);
|
||||
case i32: fmt_int(fi, u128(a), true, 32, verb);
|
||||
case i64: fmt_int(fi, u128(a), true, 64, verb);
|
||||
case i128: fmt_int(fi, u128(a), true, 128, verb);
|
||||
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
|
||||
case uintptr: fmt_int(fi, u128(a), false, 8*size_of(uintptr), verb);
|
||||
|
||||
case uint: fmt_int(fi, u128(a), false, 8*size_of(uint), verb);
|
||||
case u8: fmt_int(fi, u128(a), false, 8, verb);
|
||||
case u16: fmt_int(fi, u128(a), false, 16, verb);
|
||||
case u32: fmt_int(fi, u128(a), false, 32, verb);
|
||||
case u64: fmt_int(fi, u128(a), false, 64, verb);
|
||||
case u128: fmt_int(fi, u128(a), false, 128, verb);
|
||||
case i8: fmt_int(fi, u64(a), true, 8, verb);
|
||||
case u8: fmt_int(fi, u64(a), false, 8, verb);
|
||||
case i16: fmt_int(fi, u64(a), true, 16, verb);
|
||||
case u16: fmt_int(fi, u64(a), false, 16, verb);
|
||||
case i32: fmt_int(fi, u64(a), true, 32, verb);
|
||||
case u32: fmt_int(fi, u64(a), false, 32, verb);
|
||||
case i64: fmt_int(fi, u64(a), true, 64, verb);
|
||||
case u64: fmt_int(fi, u64(a), false, 64, verb);
|
||||
case int: fmt_int(fi, u64(a), true, 8*size_of(int), verb);
|
||||
case uint: fmt_int(fi, u64(a), false, 8*size_of(uint), verb);
|
||||
case uintptr: fmt_int(fi, u64(a), false, 8*size_of(uintptr), verb);
|
||||
|
||||
case string: fmt_string(fi, a, verb);
|
||||
|
||||
@@ -1056,7 +1003,7 @@ sbprintln :: proc(buf: ^String_Buffer, args: ...any) -> string {
|
||||
fi: Fmt_Info;
|
||||
fi.buf = buf;
|
||||
|
||||
for arg, i in args {
|
||||
for _, i in args {
|
||||
if i > 0 do write_byte(buf, ' ');
|
||||
|
||||
fmt_value(&fi, args[i], 'v');
|
||||
@@ -1072,7 +1019,7 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
was_prev_index := false;
|
||||
|
||||
|
||||
for i := 0; i < end; /**/ {
|
||||
loop: for i := 0; i < end; /**/ {
|
||||
fi = Fmt_Info{buf = b, good_arg_index = true};
|
||||
|
||||
prev_i := i;
|
||||
@@ -1083,7 +1030,7 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
write_string(b, fmt[prev_i..i]);
|
||||
}
|
||||
if i >= end {
|
||||
break;
|
||||
break loop;
|
||||
}
|
||||
|
||||
// Process a "verb"
|
||||
@@ -1163,19 +1110,20 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
|
||||
if i >= end {
|
||||
write_string(b, "%!(NO VERB)");
|
||||
break;
|
||||
break loop;
|
||||
}
|
||||
|
||||
verb, w := utf8.decode_rune(fmt[i..]);
|
||||
verb, w := utf8.decode_rune_from_string(fmt[i..]);
|
||||
i += w;
|
||||
|
||||
if verb == '%' {
|
||||
switch {
|
||||
case verb == '%':
|
||||
write_byte(b, '%');
|
||||
} else if !fi.good_arg_index {
|
||||
case !fi.good_arg_index:
|
||||
write_string(b, "%!(BAD ARGUMENT NUMBER)");
|
||||
} else if arg_index >= len(args) {
|
||||
case arg_index >= len(args):
|
||||
write_string(b, "%!(MISSING ARGUMENT)");
|
||||
} else {
|
||||
case:
|
||||
fmt_arg(&fi, args[arg_index], verb);
|
||||
arg_index += 1;
|
||||
}
|
||||
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
import "core:mem.odin"
|
||||
|
||||
adler32 :: proc(data: []u8) -> u32 {
|
||||
adler32 :: proc(data: []byte) -> u32 {
|
||||
ADLER_CONST :: 65521;
|
||||
a, b: u32 = 1, 0;
|
||||
for x in data {
|
||||
@@ -10,14 +10,14 @@ adler32 :: proc(data: []u8) -> u32 {
|
||||
return (b << 16) | a;
|
||||
}
|
||||
|
||||
crc32 :: proc(data: []u8) -> u32 {
|
||||
crc32 :: proc(data: []byte) -> u32 {
|
||||
result := ~u32(0);
|
||||
for b in data {
|
||||
result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff];
|
||||
}
|
||||
return ~result;
|
||||
}
|
||||
crc64 :: proc(data: []u8) -> u64 {
|
||||
crc64 :: proc(data: []byte) -> u64 {
|
||||
result := ~u64(0);
|
||||
for b in data {
|
||||
result = result>>8 ~ _crc64_table[(result ~ u64(b)) & 0xff];
|
||||
@@ -25,7 +25,7 @@ crc64 :: proc(data: []u8) -> u64 {
|
||||
return ~result;
|
||||
}
|
||||
|
||||
fnv32 :: proc(data: []u8) -> u32 {
|
||||
fnv32 :: proc(data: []byte) -> u32 {
|
||||
h: u32 = 0x811c9dc5;
|
||||
for b in data {
|
||||
h = (h * 0x01000193) ~ u32(b);
|
||||
@@ -33,7 +33,7 @@ fnv32 :: proc(data: []u8) -> u32 {
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv64 :: proc(data: []u8) -> u64 {
|
||||
fnv64 :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h * 0x100000001b3) ~ u64(b);
|
||||
@@ -41,7 +41,7 @@ fnv64 :: proc(data: []u8) -> u64 {
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv32a :: proc(data: []u8) -> u32 {
|
||||
fnv32a :: proc(data: []byte) -> u32 {
|
||||
h: u32 = 0x811c9dc5;
|
||||
for b in data {
|
||||
h = (h ~ u32(b)) * 0x01000193;
|
||||
@@ -49,7 +49,7 @@ fnv32a :: proc(data: []u8) -> u32 {
|
||||
return h;
|
||||
}
|
||||
|
||||
fnv64a :: proc(data: []u8) -> u64 {
|
||||
fnv64a :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
@@ -57,7 +57,7 @@ fnv64a :: proc(data: []u8) -> u64 {
|
||||
return h;
|
||||
}
|
||||
|
||||
murmur32 :: proc(data: []u8) -> u32 {
|
||||
murmur32 :: proc(data: []byte) -> u32 {
|
||||
c1_32: u32 : 0xcc9e2d51;
|
||||
c2_32: u32 : 0x1b873593;
|
||||
|
||||
@@ -106,7 +106,7 @@ murmur32 :: proc(data: []u8) -> u32 {
|
||||
return h1;
|
||||
}
|
||||
|
||||
murmur64 :: proc(data: []u8) -> u64 {
|
||||
murmur64 :: proc(data: []byte) -> u64 {
|
||||
SEED :: 0x9747b28c;
|
||||
|
||||
when size_of(int) == 8 {
|
||||
|
||||
+168
-72
@@ -1,7 +1,5 @@
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
|
||||
ONE_OVER_PI :: 0.159154943091895335768883763372514362;
|
||||
|
||||
E :: 2.71828182845904523536;
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||
@@ -16,60 +14,58 @@ EPSILON :: 1.19209290e-7;
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
|
||||
Vec2 :: [2]f32;
|
||||
Vec3 :: [3]f32;
|
||||
Vec4 :: [4]f32;
|
||||
Vec2 :: distinct [2]f32;
|
||||
Vec3 :: distinct [3]f32;
|
||||
Vec4 :: distinct [4]f32;
|
||||
|
||||
// Column major
|
||||
Mat2 :: [2][2]f32;
|
||||
Mat3 :: [3][3]f32;
|
||||
Mat4 :: [4][4]f32;
|
||||
Mat2 :: distinct [2][2]f32;
|
||||
Mat3 :: distinct [3][3]f32;
|
||||
Mat4 :: distinct [4][4]f32;
|
||||
|
||||
Complex :: complex64;
|
||||
Quat :: struct {x, y, z: f32, w: f32 = 1};
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign __llvm_core {
|
||||
@(link_name="llvm.sqrt.f32")
|
||||
sqrt :: proc(x: f32) -> f32 ---;
|
||||
sqrt_f32 :: proc(x: f32) -> f32 ---;
|
||||
@(link_name="llvm.sqrt.f64")
|
||||
sqrt :: proc(x: f64) -> f64 ---;
|
||||
sqrt_f64 :: proc(x: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.sin.f32")
|
||||
sin :: proc(θ: f32) -> f32 ---;
|
||||
sin_f32 :: proc(θ: f32) -> f32 ---;
|
||||
@(link_name="llvm.sin.f64")
|
||||
sin :: proc(θ: f64) -> f64 ---;
|
||||
sin_f64 :: proc(θ: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.cos.f32")
|
||||
cos :: proc(θ: f32) -> f32 ---;
|
||||
cos_f32 :: proc(θ: f32) -> f32 ---;
|
||||
@(link_name="llvm.cos.f64")
|
||||
cos :: proc(θ: f64) -> f64 ---;
|
||||
cos_f64 :: proc(θ: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.pow.f32")
|
||||
pow :: proc(x, power: f32) -> f32 ---;
|
||||
pow_f32 :: proc(x, power: f32) -> f32 ---;
|
||||
@(link_name="llvm.pow.f64")
|
||||
pow :: proc(x, power: f64) -> f64 ---;
|
||||
pow_f64 :: proc(x, power: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.fmuladd.f32")
|
||||
fmuladd :: proc(a, b, c: f32) -> f32 ---;
|
||||
fmuladd_f32 :: proc(a, b, c: f32) -> f32 ---;
|
||||
@(link_name="llvm.fmuladd.f64")
|
||||
fmuladd :: proc(a, b, c: f64) -> f64 ---;
|
||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
|
||||
}
|
||||
|
||||
tan :: proc "c" (θ: f32) -> f32 do return sin(θ)/cos(θ);
|
||||
tan :: proc "c" (θ: f64) -> f64 do return sin(θ)/cos(θ);
|
||||
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
|
||||
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
|
||||
|
||||
lerp :: proc(a, b: $T, t: $E) -> (x: T) do return a*(1-t) + b*t;
|
||||
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
|
||||
|
||||
unlerp :: proc(a, b, x: f32) -> (t: f32) do return (x-a)/(b-a);
|
||||
unlerp :: proc(a, b, x: f64) -> (t: f64) do return (x-a)/(b-a);
|
||||
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
|
||||
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
|
||||
|
||||
|
||||
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||
sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||
sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||
sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||
|
||||
|
||||
|
||||
copy_sign :: proc(x, y: f32) -> f32 {
|
||||
copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
||||
ix := transmute(u32)x;
|
||||
iy := transmute(u32)y;
|
||||
ix &= 0x7fff_ffff;
|
||||
@@ -77,7 +73,7 @@ copy_sign :: proc(x, y: f32) -> f32 {
|
||||
return transmute(f32)ix;
|
||||
}
|
||||
|
||||
copy_sign :: proc(x, y: f64) -> f64 {
|
||||
copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
||||
ix := transmute(u64)x;
|
||||
iy := transmute(u64)y;
|
||||
ix &= 0x7fff_ffff_ffff_ff;
|
||||
@@ -85,19 +81,34 @@ copy_sign :: proc(x, y: f64) -> f64 {
|
||||
return transmute(f64)ix;
|
||||
}
|
||||
|
||||
round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
|
||||
floor :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
floor :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
sqrt :: proc[sqrt_f32, sqrt_f64];
|
||||
sin :: proc[sin_f32, sin_f64];
|
||||
cos :: proc[cos_f32, cos_f64];
|
||||
tan :: proc[tan_f32, tan_f64];
|
||||
pow :: proc[pow_f32, pow_f64];
|
||||
fmuladd :: proc[fmuladd_f32, fmuladd_f64];
|
||||
sign :: proc[sign_f32, sign_f64];
|
||||
copy_sign :: proc[copy_sign_f32, copy_sign_f64];
|
||||
|
||||
ceil :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); }// TODO: Get accurate versions
|
||||
ceil :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); }// TODO: Get accurate versions
|
||||
|
||||
remainder :: proc(x, y: f32) -> f32 do return x - round(x/y) * y;
|
||||
remainder :: proc(x, y: f64) -> f64 do return x - round(x/y) * y;
|
||||
round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round :: proc[round_f32, round_f64];
|
||||
|
||||
mod :: proc(x, y: f32) -> f32 {
|
||||
floor_f32 :: proc(x: f32) -> f32 { return x >= 0 ? f32(i64(x)) : f32(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
floor_f64 :: proc(x: f64) -> f64 { return x >= 0 ? f64(i64(x)) : f64(i64(x-0.5)); } // TODO: Get accurate versions
|
||||
floor :: proc[floor_f32, floor_f64];
|
||||
|
||||
ceil_f32 :: proc(x: f32) -> f32 { return x < 0 ? f32(i64(x)) : f32(i64(x+1)); }// TODO: Get accurate versions
|
||||
ceil_f64 :: proc(x: f64) -> f64 { return x < 0 ? f64(i64(x)) : f64(i64(x+1)); }// TODO: Get accurate versions
|
||||
ceil :: proc[ceil_f32, ceil_f64];
|
||||
|
||||
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
remainder :: proc[remainder_f32, remainder_f64];
|
||||
|
||||
mod_f32 :: proc(x, y: f32) -> f32 {
|
||||
result: f32;
|
||||
y = abs(y);
|
||||
result = remainder(abs(x), y);
|
||||
@@ -106,7 +117,7 @@ mod :: proc(x, y: f32) -> f32 {
|
||||
}
|
||||
return copy_sign(result, x);
|
||||
}
|
||||
mod :: proc(x, y: f64) -> f64 {
|
||||
mod_f64 :: proc(x, y: f64) -> f64 {
|
||||
result: f64;
|
||||
y = abs(y);
|
||||
result = remainder(abs(x), y);
|
||||
@@ -115,47 +126,66 @@ mod :: proc(x, y: f64) -> f64 {
|
||||
}
|
||||
return copy_sign(result, x);
|
||||
}
|
||||
|
||||
|
||||
to_radians :: proc(degrees: f32) -> f32 do return degrees * TAU / 360;
|
||||
to_degrees :: proc(radians: f32) -> f32 do return radians * 360 / TAU;
|
||||
mod :: proc[mod_f32, mod_f64];
|
||||
|
||||
|
||||
|
||||
dot :: proc(a, b: $T/[$N]$E) -> E {
|
||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||
|
||||
|
||||
|
||||
|
||||
mul :: proc[
|
||||
mat4_mul, mat4_mul_vec4,
|
||||
quat_mul, quat_mulf,
|
||||
];
|
||||
|
||||
div :: proc[
|
||||
quat_div, quat_divf,
|
||||
];
|
||||
|
||||
inverse :: proc[mat4_inverse, quat_inverse];
|
||||
dot :: proc[vec_dot, quat_dot];
|
||||
cross :: proc[cross2, cross3];
|
||||
|
||||
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
|
||||
res: E;
|
||||
for i in 0..N do res += a[i] * b[i];
|
||||
for i in 0..N {
|
||||
res += a[i] * b[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
cross :: proc(x, y: $T/[3]$E) -> T {
|
||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
||||
return T(a - b);
|
||||
cross2 :: proc(a, b: $T/[2]$E) -> E {
|
||||
return a[0]*b[1] - a[1]*b[0];
|
||||
}
|
||||
|
||||
cross3 :: proc(a, b: $T/[3]$E) -> T {
|
||||
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
|
||||
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
|
||||
return T(i - j);
|
||||
}
|
||||
|
||||
|
||||
mag :: proc(v: $T/[$N]$E) -> E do return sqrt(dot(v, v));
|
||||
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }
|
||||
|
||||
norm :: proc(v: $T/[$N]$E) -> T do return v / mag(v);
|
||||
norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); }
|
||||
|
||||
norm0 :: proc(v: $T/[$N]$E) -> T {
|
||||
m := mag(v);
|
||||
m := length(v);
|
||||
return m == 0 ? 0 : v/m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mat4_identity :: proc() -> Mat4 {
|
||||
return Mat4{
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
};
|
||||
identity :: proc(T: type/[$N][N]$E) -> T {
|
||||
m: T;
|
||||
for i in 0..N do m[i][i] = E(1);
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
transpose :: proc(m: Mat4) -> Mat4 {
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
@@ -164,7 +194,7 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||
return m;
|
||||
}
|
||||
|
||||
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
@@ -177,7 +207,7 @@ mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
return c;
|
||||
}
|
||||
|
||||
mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
return Vec4{
|
||||
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
|
||||
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
|
||||
@@ -186,7 +216,8 @@ mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
};
|
||||
}
|
||||
|
||||
inverse :: proc(m: Mat4) -> Mat4 {
|
||||
|
||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4;
|
||||
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
@@ -257,7 +288,7 @@ inverse :: proc(m: Mat4) -> Mat4 {
|
||||
|
||||
|
||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||
m := mat4_identity();
|
||||
m := identity(Mat4);
|
||||
m[3][0] = v[0];
|
||||
m[3][1] = v[1];
|
||||
m[3][2] = v[2];
|
||||
@@ -272,7 +303,7 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
a := norm(v);
|
||||
t := a * (1-c);
|
||||
|
||||
rot := mat4_identity();
|
||||
rot := identity(Mat4);
|
||||
|
||||
rot[0][0] = c + t[0]*a[0];
|
||||
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
|
||||
@@ -292,20 +323,22 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
return rot;
|
||||
}
|
||||
|
||||
scale :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
m[0][0] *= v[0];
|
||||
m[1][1] *= v[1];
|
||||
m[2][2] *= v[2];
|
||||
return m;
|
||||
}
|
||||
|
||||
scale :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
m[0][0] *= s;
|
||||
m[1][1] *= s;
|
||||
m[2][2] *= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
scale :: proc[scale_vec3, scale_f32];
|
||||
|
||||
|
||||
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := norm(centre - eye);
|
||||
@@ -313,9 +346,9 @@ look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
u := cross(s, f);
|
||||
|
||||
return Mat4{
|
||||
{+s[0], +u[0], -f[0], 0},
|
||||
{+s[1], +u[1], -f[1], 0},
|
||||
{+s[2], +u[2], -f[2], 0},
|
||||
{+s.x, +u.x, -f.x, 0},
|
||||
{+s.y, +u.y, -f.y, 0},
|
||||
{+s.z, +u.z, -f.z, 0},
|
||||
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
|
||||
};
|
||||
}
|
||||
@@ -334,7 +367,7 @@ perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
|
||||
|
||||
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
m := mat4_identity();
|
||||
m := identity(Mat4);
|
||||
m[0][0] = +2.0 / (right - left);
|
||||
m[1][1] = +2.0 / (top - bottom);
|
||||
m[2][2] = -2.0 / (far - near);
|
||||
@@ -345,6 +378,69 @@ ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
}
|
||||
|
||||
|
||||
// Quaternion operations
|
||||
|
||||
conj :: proc(q: Quat) -> Quat {
|
||||
return Quat{-q.x, -q.y, -q.z, q.w};
|
||||
}
|
||||
|
||||
quat_mul :: proc(q0, q1: Quat) -> Quat {
|
||||
d: Quat;
|
||||
d.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
|
||||
d.y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x;
|
||||
d.z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w;
|
||||
d.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
|
||||
return d;
|
||||
}
|
||||
|
||||
quat_mulf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x*f, q.y*f, q.z*f, q.w*f}; }
|
||||
quat_divf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x/f, q.y/f, q.z/f, q.w/f}; }
|
||||
|
||||
quat_div :: proc(q0, q1: Quat) -> Quat { return mul(q0, quat_inverse(q1)); }
|
||||
quat_inverse :: proc(q: Quat) -> Quat { return div(conj(q), dot(q, q)); }
|
||||
quat_dot :: proc(q0, q1: Quat) -> f32 { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; }
|
||||
|
||||
quat_norm :: proc(q: Quat) -> Quat {
|
||||
m := sqrt(dot(q, q));
|
||||
return div(q, m);
|
||||
}
|
||||
|
||||
axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat {
|
||||
v := norm(axis) * sin(0.5*angle_radians);
|
||||
w := cos(0.5*angle_radians);
|
||||
return Quat{v.x, v.y, v.z, w};
|
||||
}
|
||||
|
||||
euler_angles :: proc(pitch, yaw, roll: f32) -> Quat {
|
||||
p := axis_angle(Vec3{1, 0, 0}, pitch);
|
||||
y := axis_angle(Vec3{0, 1, 0}, pitch);
|
||||
r := axis_angle(Vec3{0, 0, 1}, pitch);
|
||||
return mul(mul(y, p), r);
|
||||
}
|
||||
|
||||
quat_to_mat4 :: proc(q: Quat) -> Mat4 {
|
||||
a := quat_norm(q);
|
||||
xx := a.x*a.x; yy := a.y*a.y; zz := a.z*a.z;
|
||||
xy := a.x*a.y; xz := a.x*a.z; yz := a.y*a.z;
|
||||
wx := a.w*a.x; wy := a.w*a.y; wz := a.w*a.z;
|
||||
|
||||
m := identity(Mat4);
|
||||
|
||||
m[0][0] = 1 - 2*(yy + zz);
|
||||
m[0][1] = 2*(xy + wz);
|
||||
m[0][2] = 2*(xz - wy);
|
||||
|
||||
m[1][0] = 2*(xy - wz);
|
||||
m[1][1] = 1 - 2*(xx + zz);
|
||||
m[1][2] = 2*(yz + wx);
|
||||
|
||||
m[2][0] = 2*(xz + wy);
|
||||
m[2][1] = 2*(yz - wx);
|
||||
m[2][2] = 1 - 2*(xx + yy);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
F32_DIG :: 6;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
Rand :: struct {
|
||||
state: u64,
|
||||
inc: u64,
|
||||
}
|
||||
|
||||
init :: proc(r: ^Rand, seed: u64 = 8675309) {
|
||||
r.state = 0;
|
||||
r.inc = (seed << 1) | 1;
|
||||
_random(r);
|
||||
r.state += seed;
|
||||
_random(r);
|
||||
}
|
||||
|
||||
_random :: proc(r: ^Rand) -> u32 {
|
||||
old_state := r.state;
|
||||
r.state = old_state * 6364136223846793005 + (r.inc|1);
|
||||
xor_shifted := u32(((old_state>>18) ~ old_state) >> 27);
|
||||
rot := u32(old_state >> 59);
|
||||
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 31));
|
||||
}
|
||||
|
||||
uint32 :: proc(r: ^Rand) -> u32 { return _random(r); }
|
||||
|
||||
uint64 :: proc(r: ^Rand) -> u64 {
|
||||
a := u64(_random(r));
|
||||
b := u64(_random(r));
|
||||
return (a<<32) | b;
|
||||
}
|
||||
|
||||
int31 :: proc(r: ^Rand) -> i32 { return i32(uint32(r) << 1 >> 1); }
|
||||
int63 :: proc(r: ^Rand) -> i64 { return i64(uint64(r) << 1 >> 1); }
|
||||
|
||||
int31_max :: proc(r: ^Rand, n: i32) -> i32 {
|
||||
if n <= 0 do panic("Invalid argument to int31_max");
|
||||
if n&(n-1) == 0 {
|
||||
return int31(r) & (n-1);
|
||||
}
|
||||
max := i32((1<<31) - 1 - (1<<31)&u32(n));
|
||||
v := int31(r);
|
||||
for v > max {
|
||||
v = int31(r);
|
||||
}
|
||||
return v % n;
|
||||
}
|
||||
|
||||
int63_max :: proc(r: ^Rand, n: i64) -> i64 {
|
||||
if n <= 0 do panic("Invalid argument to int63_max");
|
||||
if n&(n-1) == 0 {
|
||||
return int63(r) & (n-1);
|
||||
}
|
||||
max := i64((1<<63) - 1 - (1<<63)&u64(n));
|
||||
v := int63(r);
|
||||
for v > max {
|
||||
v = int63(r);
|
||||
}
|
||||
return v % n;
|
||||
}
|
||||
|
||||
float64 :: proc(r: ^Rand) -> f64 { return f64(int63_max(r, 1<<53)) / (1 << 53); }
|
||||
float32 :: proc(r: ^Rand) -> f32 { return f32(float64(r)); }
|
||||
+31
-39
@@ -1,10 +1,12 @@
|
||||
import "core:raw.odin"
|
||||
|
||||
foreign __llvm_core {
|
||||
@(link_name = "llvm.bswap.i16") swap :: proc(b: u16) -> u16 ---;
|
||||
@(link_name = "llvm.bswap.i32") swap :: proc(b: u32) -> u32 ---;
|
||||
@(link_name = "llvm.bswap.i64") swap :: proc(b: u64) -> u64 ---;
|
||||
@(link_name = "llvm.bswap.i16") swap16 :: proc(b: u16) -> u16 ---;
|
||||
@(link_name = "llvm.bswap.i32") swap32 :: proc(b: u32) -> u32 ---;
|
||||
@(link_name = "llvm.bswap.i64") swap64 :: proc(b: u64) -> u64 ---;
|
||||
}
|
||||
swap :: proc[swap16, swap32, swap64];
|
||||
|
||||
|
||||
set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr {
|
||||
return __mem_set(data, value, len);
|
||||
@@ -18,37 +20,26 @@ copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
return __mem_copy_non_overlapping(dst, src, len);
|
||||
}
|
||||
compare :: proc "contextless" (a, b: []u8) -> int {
|
||||
compare :: proc "contextless" (a, b: []byte) -> int {
|
||||
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
|
||||
|
||||
slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
|
||||
assert(len >= 0);
|
||||
slice := raw.Slice{data = ptr, len = len, cap = len};
|
||||
return transmute([]T)slice;
|
||||
}
|
||||
slice_ptr :: proc "contextless" (ptr: ^$T, len, cap: int) -> []T {
|
||||
assert(0 <= len && len <= cap);
|
||||
slice := raw.Slice{data = ptr, len = len, cap = cap};
|
||||
slice := raw.Slice{data = ptr, len = len};
|
||||
return transmute([]T)slice;
|
||||
}
|
||||
|
||||
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []u8 {
|
||||
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
|
||||
s := transmute(raw.Slice)slice;
|
||||
s.len *= size_of(T);
|
||||
s.cap *= size_of(T);
|
||||
return transmute([]u8)s;
|
||||
return transmute([]byte)s;
|
||||
}
|
||||
|
||||
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []u8 {
|
||||
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
|
||||
assert(len >= 0);
|
||||
return transmute([]u8)raw.Slice{ptr, len*size_of(T), len*size_of(T)};
|
||||
}
|
||||
|
||||
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len, cap: int) -> []u8 {
|
||||
assert(0 <= len && len <= cap);
|
||||
return transmute([]u8)raw.Slice{ptr, len*size_of(T), cap*size_of(T)};
|
||||
return transmute([]byte)raw.Slice{ptr, len*size_of(T)};
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +84,17 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
}
|
||||
|
||||
|
||||
Fixed_Byte_Buffer :: distinct [dynamic]byte;
|
||||
|
||||
make_fixed_byte_buffer :: proc(backing: []byte) -> Fixed_Byte_Buffer {
|
||||
s := transmute(raw.Slice)backing;
|
||||
d: raw.Dynamic_Array;
|
||||
d.data = s.data;
|
||||
d.len = 0;
|
||||
d.cap = s.len;
|
||||
d.allocator = nil_allocator();
|
||||
return transmute(Fixed_Byte_Buffer)d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -100,7 +102,7 @@ allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
|
||||
Arena :: struct {
|
||||
backing: Allocator,
|
||||
memory: []u8,
|
||||
memory: Fixed_Byte_Buffer,
|
||||
temp_count: int,
|
||||
}
|
||||
|
||||
@@ -113,15 +115,15 @@ ArenaTempMemory :: struct {
|
||||
|
||||
|
||||
|
||||
init_arena_from_memory :: proc(using a: ^Arena, data: []u8) {
|
||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||
backing = Allocator{};
|
||||
memory = data[..0];
|
||||
memory = make_fixed_byte_buffer(data);
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
backing = context.allocator;
|
||||
memory = make([]u8, 0, size);
|
||||
memory = make_fixed_byte_buffer(make([]byte, size));
|
||||
temp_count = 0;
|
||||
}
|
||||
|
||||
@@ -135,7 +137,9 @@ context_from_allocator :: proc(a: Allocator) -> Context {
|
||||
destroy_arena :: proc(using a: ^Arena) {
|
||||
if backing.procedure != nil {
|
||||
context <- context_from_allocator(backing) {
|
||||
free(memory);
|
||||
if memory != nil {
|
||||
free(&memory[0]);
|
||||
}
|
||||
memory = nil;
|
||||
}
|
||||
}
|
||||
@@ -194,7 +198,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
|
||||
end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
|
||||
assert(len(arena.memory) >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
arena.memory = arena.memory[..original_count];
|
||||
(^raw.Dynamic_Array)(&arena.memory).len = original_count;
|
||||
arena.temp_count -= 1;
|
||||
}
|
||||
|
||||
@@ -217,7 +221,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
}
|
||||
|
||||
WORD_SIZE :: size_of(int);
|
||||
MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
|
||||
MAX_ALIGN :: 2*align_of(rawptr); // TODO(bill): Should these constants be builtin constants?
|
||||
switch info in type_info.variant {
|
||||
case Type_Info_Named:
|
||||
return align_of_type_info(info.base);
|
||||
@@ -243,11 +247,6 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Slice:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Vector:
|
||||
size := size_of_type_info(info.elem);
|
||||
count := int(max(prev_pow2(i64(info.count)), 1));
|
||||
total := size * count;
|
||||
return clamp(total, 1, MAX_ALIGN);
|
||||
case Type_Info_Tuple:
|
||||
return type_info.align;
|
||||
case Type_Info_Struct:
|
||||
@@ -300,13 +299,6 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
||||
case Type_Info_Slice:
|
||||
return 2*WORD_SIZE;
|
||||
case Type_Info_Vector:
|
||||
count := info.count;
|
||||
if count == 0 do return 0;
|
||||
size := size_of_type_info(info.elem);
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case Type_Info_Struct:
|
||||
return type_info.size;
|
||||
case Type_Info_Union:
|
||||
|
||||
+3
-3
@@ -44,13 +44,13 @@ _string_data :: inline proc(s: string) -> ^u8 do return &s[0];
|
||||
|
||||
_libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
|
||||
|
||||
get_proc_address :: proc(name: string) -> rawptr {
|
||||
get_gl_proc_address :: proc(name: string) -> rawptr {
|
||||
if name[len(name)-1] == 0 {
|
||||
name = name[..len(name)-1];
|
||||
}
|
||||
// NOTE(bill): null terminated
|
||||
assert((&name[0] + len(name))^ == 0);
|
||||
res := wgl.get_proc_address(&name[0]);
|
||||
res := wgl.get_gl_proc_address(&name[0]);
|
||||
if res == nil {
|
||||
res = win32.get_proc_address(_libgl, &name[0]);
|
||||
}
|
||||
@@ -122,7 +122,7 @@ get_proc_address :: proc(name: string) -> rawptr {
|
||||
init :: proc() {
|
||||
set_proc_address :: proc(p: rawptr, name: string) {
|
||||
x := cast(^rawptr)p;
|
||||
x^ = get_proc_address(name);
|
||||
x^ = get_gl_proc_address(name);
|
||||
}
|
||||
|
||||
set_proc_address(&GenBuffers, "glGenBuffers\x00");
|
||||
|
||||
+16
-10
@@ -1,14 +1,20 @@
|
||||
when ODIN_OS == "windows" do export "core:os_windows.odin";
|
||||
when ODIN_OS == "osx" do export "core:os_x.odin";
|
||||
when ODIN_OS == "linux" do export "core:os_linux.odin";
|
||||
when ODIN_OS == "essence" do export "core:os_essence.odin";
|
||||
|
||||
import "mem.odin";
|
||||
|
||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, cast([]u8)str);
|
||||
return write(fd, cast([]byte)str);
|
||||
}
|
||||
|
||||
read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
|
||||
write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) {
|
||||
return write(fd, []byte{b});
|
||||
}
|
||||
|
||||
|
||||
read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
|
||||
fd, err := open(name, O_RDONLY, 0);
|
||||
if err != 0 {
|
||||
return nil, false;
|
||||
@@ -24,7 +30,7 @@ read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
|
||||
return nil, true;
|
||||
}
|
||||
|
||||
data := make([]u8, int(length));
|
||||
data = make([]byte, int(length));
|
||||
if data == nil {
|
||||
return nil, false;
|
||||
}
|
||||
@@ -37,7 +43,7 @@ read_entire_file :: proc(name: string) -> (data: []u8, success: bool) {
|
||||
return data[0..bytes_read], true;
|
||||
}
|
||||
|
||||
write_entire_file :: proc(name: string, data: []u8, truncate := true) -> (success: bool) {
|
||||
write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) {
|
||||
flags: int = O_WRONLY|O_CREATE;
|
||||
if truncate {
|
||||
flags |= O_TRUNC;
|
||||
@@ -48,14 +54,14 @@ write_entire_file :: proc(name: string, data: []u8, truncate := true) -> (succes
|
||||
}
|
||||
defer close(fd);
|
||||
|
||||
bytes_written, write_err := write(fd, data);
|
||||
return write_err != 0;
|
||||
_, write_err := write(fd, data);
|
||||
return write_err == 0;
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||
return write(fd, mem.slice_ptr(cast(^u8)data, len));
|
||||
write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||
return write(fd, mem.slice_ptr(cast(^byte)data, len));
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||
return read(fd, mem.slice_ptr(cast(^u8)data, len));
|
||||
read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||
return read(fd, mem.slice_ptr(cast(^byte)data, len));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
foreign import api "system:api"
|
||||
|
||||
Handle :: distinct int;
|
||||
Errno :: distinct int;
|
||||
|
||||
O_RDONLY :: 1;
|
||||
O_WRONLY :: 2;
|
||||
O_CREATE :: 4;
|
||||
O_TRUNC :: 4;
|
||||
|
||||
OS_Node_Type :: enum i32 {
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
}
|
||||
|
||||
OS_Node_Information :: struct {
|
||||
handle: Handle,
|
||||
id: [16]byte,
|
||||
ntype: OS_Node_Type,
|
||||
size: i64,
|
||||
position: i64,
|
||||
}
|
||||
|
||||
foreign api {
|
||||
@(link_name="OSHelloWorld") os_hello_world :: proc() ---;
|
||||
@(link_name="OSPrintDirect") os_print_direct :: proc(string: ^byte, length: int) ---;
|
||||
@(link_name="OSHeapAllocate") os_heap_allocate :: proc(bytes: int, zero: bool) -> rawptr ---;
|
||||
@(link_name="OSHeapFree") os_heap_free :: proc(address: rawptr) ---;
|
||||
@(link_name="OSOpenNode") os_open_node :: proc(path: ^byte, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
|
||||
@(link_name="OSResizeFile") os_resize_file :: proc(handle: Handle, new_size: u64) -> Errno ---;
|
||||
@(link_name="OSCloseHandle") os_close_handle :: proc(handle: Handle) ---;
|
||||
@(link_name="OSWriteFileSync") os_write_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
|
||||
@(link_name="OSReadFileSync") os_read_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
|
||||
@(link_name="OSInitialiseAPI") os_initialise_api :: proc() -> int ---;
|
||||
@(link_name="OSTerminateProcess") os_terminate_process :: proc(handle: Handle) ---;
|
||||
@(link_name="realloc") os_heap_reallocate :: proc(address: rawptr, size: int) -> rawptr ---;
|
||||
}
|
||||
|
||||
stdin := Handle(-1); // Not implemented
|
||||
stdout := Handle(0);
|
||||
stderr := Handle(0);
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
// Not implemented
|
||||
return -1;
|
||||
}
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return os_heap_allocate(size, true);
|
||||
}
|
||||
|
||||
heap_free :: proc(address: rawptr) {
|
||||
os_heap_free(address);
|
||||
}
|
||||
|
||||
heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
|
||||
return os_heap_reallocate(address, new_size);
|
||||
}
|
||||
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
information := new(OS_Node_Information);
|
||||
error := os_open_node(&path[0], len(path), u64(mode), information);
|
||||
if error < -1 do return 0, 1;
|
||||
information.position = 0;
|
||||
if mode&O_TRUNC==O_TRUNC {
|
||||
error := os_resize_file(information.handle, 0);
|
||||
if error < -1 do return 0, 1;
|
||||
}
|
||||
return Handle(uintptr(information)), 0;
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) {
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
os_close_handle(information.handle);
|
||||
free(information);
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
// Not (properly) implemented
|
||||
information := cast(^OS_Node_Information)uintptr(fd);
|
||||
return information.size,0;
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if fd == 0 {
|
||||
os_print_direct(&data[0], len(data));
|
||||
return len(data), 0;
|
||||
} else if fd == 1 {
|
||||
assert(false);
|
||||
return 0, 1;
|
||||
}
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
count := os_write_file_sync(information.handle, information.position, i64(len(data)), &data[0]);
|
||||
if count < 0 do return 0, 1;
|
||||
information.position += count;
|
||||
return int(count), 0;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if (fd == 0 || fd == 1) {
|
||||
assert(false);
|
||||
return 0, 1;
|
||||
}
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
count := os_read_file_sync(information.handle, information.position, i64(len(data)), &data[0]);
|
||||
if count < 0 do return 0, 1;
|
||||
information.position += count;
|
||||
return int(count), 0;
|
||||
}
|
||||
|
||||
os_terminate_this_process :: proc() {
|
||||
os_terminate_process(0x1001);
|
||||
}
|
||||
+21
-20
@@ -4,9 +4,9 @@ foreign import libc "system:c"
|
||||
import "core:strings.odin"
|
||||
import "core:mem.odin"
|
||||
|
||||
Handle :: i32;
|
||||
File_Time :: u64;
|
||||
Errno :: i32;
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
Errno :: distinct i32;
|
||||
|
||||
|
||||
O_RDONLY :: 0x00000;
|
||||
@@ -40,7 +40,7 @@ RTLD_GLOBAL :: 0x100;
|
||||
// "Argv" arguments converted to Odin strings
|
||||
args := _alloc_command_line_arguments();
|
||||
|
||||
_File_Time :: struct #ordered {
|
||||
_File_Time :: struct {
|
||||
seconds: i64,
|
||||
nanoseconds: i32,
|
||||
reserved: i32,
|
||||
@@ -50,7 +50,7 @@ _File_Time :: struct #ordered {
|
||||
// https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
|
||||
// Validity is not guaranteed.
|
||||
|
||||
Stat :: struct #ordered {
|
||||
Stat :: struct {
|
||||
device_id: u64, // ID of device containing file
|
||||
serial: u64, // File serial number
|
||||
nlink: u32, // Number of hard links
|
||||
@@ -122,28 +122,28 @@ W_OK :: 2; // Test for write permission
|
||||
R_OK :: 4; // Test for read permission
|
||||
|
||||
foreign libc {
|
||||
@(link_name="open") _unix_open :: proc(path: ^u8, mode: int) -> Handle ---;
|
||||
@(link_name="open") _unix_open :: proc(path: ^byte, mode: int) -> Handle ---;
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> i32 ---;
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
|
||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 ---;
|
||||
@(link_name="access") _unix_access :: proc(path: ^u8, mask: int) -> i32 ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: ^byte, stat: ^Stat) -> i32 ---;
|
||||
@(link_name="access") _unix_access :: proc(path: ^byte, mask: int) -> i32 ---;
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(^u8) -> ^u8 ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(^byte) -> ^byte ---;
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: int) ---;
|
||||
}
|
||||
foreign dl {
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> rawptr ---;
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^byte, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^byte) -> rawptr ---;
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> ^u8 ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> ^byte ---;
|
||||
}
|
||||
|
||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||
@@ -166,12 +166,12 @@ close :: proc(fd: Handle) {
|
||||
_unix_close(fd);
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
sz := _unix_read(fd, &data[0], len(data));
|
||||
return sz, 0;
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
sz := _unix_write(fd, &data[0], len(data));
|
||||
return sz, 0;
|
||||
}
|
||||
@@ -201,9 +201,10 @@ last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||
*/
|
||||
|
||||
stat :: inline proc(path: string) -> (Stat, int) {
|
||||
s: Stat;
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
|
||||
s: Stat;
|
||||
ret_int := _unix_stat(cstr, &s);
|
||||
return s, int(ret_int);
|
||||
}
|
||||
@@ -229,9 +230,9 @@ heap_free :: proc(ptr: rawptr) {
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_c_string(name);
|
||||
cstr: ^u8 = _unix_getenv(path_str);
|
||||
free(path_str);
|
||||
if(cstr == nil) {
|
||||
defer free(path_str);
|
||||
cstr := _unix_getenv(path_str);
|
||||
if cstr == nil {
|
||||
return "", false;
|
||||
}
|
||||
return strings.to_odin_string(cstr), true;
|
||||
@@ -248,15 +249,15 @@ current_thread_id :: proc() -> int {
|
||||
|
||||
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.new_c_string(filename);
|
||||
defer free(cstr);
|
||||
handle := _unix_dlopen(cstr, flags);
|
||||
free(cstr);
|
||||
return handle;
|
||||
}
|
||||
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil);
|
||||
cstr := strings.new_c_string(symbol);
|
||||
defer free(cstr);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
free(cstr);
|
||||
return proc_handle;
|
||||
}
|
||||
dlclose :: inline proc(handle: rawptr) -> bool {
|
||||
|
||||
+25
-25
@@ -1,8 +1,9 @@
|
||||
import win32 "core:sys/windows.odin"
|
||||
import "core:mem.odin"
|
||||
|
||||
Handle :: uintptr;
|
||||
File_Time :: u64;
|
||||
Handle :: distinct uintptr;
|
||||
File_Time :: distinct u64;
|
||||
Errno :: distinct int;
|
||||
|
||||
|
||||
INVALID_HANDLE :: ~Handle(0);
|
||||
@@ -22,7 +23,6 @@ O_SYNC :: 0x01000;
|
||||
O_ASYNC :: 0x02000;
|
||||
O_CLOEXEC :: 0x80000;
|
||||
|
||||
Errno :: int;
|
||||
|
||||
ERROR_NONE: Errno : 0;
|
||||
ERROR_FILE_NOT_FOUND: Errno : 2;
|
||||
@@ -76,7 +76,7 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn
|
||||
|
||||
share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
|
||||
sa: ^win32.Security_Attributes = nil;
|
||||
sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = 1};
|
||||
sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = true};
|
||||
if mode&O_CLOEXEC == 0 {
|
||||
sa = &sa_inherit;
|
||||
}
|
||||
@@ -95,8 +95,8 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn
|
||||
create_mode = win32.OPEN_EXISTING;
|
||||
}
|
||||
|
||||
buf: [300]u8;
|
||||
copy(buf[..], cast([]u8)path);
|
||||
buf: [300]byte;
|
||||
copy(buf[..], cast([]byte)path);
|
||||
|
||||
handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
|
||||
if handle != INVALID_HANDLE do return handle, ERROR_NONE;
|
||||
@@ -110,7 +110,7 @@ close :: proc(fd: Handle) {
|
||||
}
|
||||
|
||||
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 do return 0, ERROR_NONE;
|
||||
|
||||
single_write_length: i32;
|
||||
@@ -123,7 +123,7 @@ write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
to_write: i32 = min(i32(remaining), MAX);
|
||||
|
||||
e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
|
||||
if single_write_length <= 0 || e == win32.FALSE {
|
||||
if single_write_length <= 0 || !e {
|
||||
err := Errno(win32.get_last_error());
|
||||
return int(total_write), err;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
return int(total_write), ERROR_NONE;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 do return 0, ERROR_NONE;
|
||||
|
||||
single_read_length: i32;
|
||||
@@ -145,7 +145,7 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
to_read: u32 = min(u32(remaining), MAX);
|
||||
|
||||
e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
|
||||
if single_read_length <= 0 || e == win32.FALSE {
|
||||
if single_read_length <= 0 || !e {
|
||||
err := Errno(win32.get_last_error());
|
||||
return int(total_read), err;
|
||||
}
|
||||
@@ -177,7 +177,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
length: i64;
|
||||
err: Errno;
|
||||
if win32.get_file_size_ex(win32.Handle(fd), &length) == 0 {
|
||||
if !win32.get_file_size_ex(win32.Handle(fd), &length) {
|
||||
err = Errno(win32.get_last_error());
|
||||
}
|
||||
return length, err;
|
||||
@@ -213,13 +213,13 @@ last_write_time :: proc(fd: Handle) -> File_Time {
|
||||
last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
last_write_time: win32.Filetime;
|
||||
data: win32.File_Attribute_Data;
|
||||
buf: [1024]u8;
|
||||
buf: [1024]byte;
|
||||
|
||||
assert(len(buf) > len(name));
|
||||
|
||||
copy(buf[..], cast([]u8)name);
|
||||
copy(buf[..], cast([]byte)name);
|
||||
|
||||
if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) != 0 {
|
||||
if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) {
|
||||
last_write_time = data.last_write_time;
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
for (wstr+wstr_len)^ != 0 do wstr_len += 1;
|
||||
|
||||
len := 2*wstr_len-1;
|
||||
buf := make([]u8, len+1);
|
||||
buf := make([]byte, len+1);
|
||||
str := mem.slice_ptr(wstr, wstr_len+1);
|
||||
|
||||
i, j := 0, 0;
|
||||
@@ -275,28 +275,28 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
switch {
|
||||
case str[j] < 0x80:
|
||||
if i+1 > len do return "";
|
||||
buf[i] = u8(str[j]); i += 1;
|
||||
buf[i] = byte(str[j]); i += 1;
|
||||
j += 1;
|
||||
case str[j] < 0x800:
|
||||
if i+2 > len do return "";
|
||||
buf[i] = u8(0xc0 + (str[j]>>6)); i += 1;
|
||||
buf[i] = u8(0x80 + (str[j]&0x3f)); i += 1;
|
||||
buf[i] = byte(0xc0 + (str[j]>>6)); i += 1;
|
||||
buf[i] = byte(0x80 + (str[j]&0x3f)); i += 1;
|
||||
j += 1;
|
||||
case 0xd800 <= str[j] && str[j] < 0xdc00:
|
||||
if i+4 > len do return "";
|
||||
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
|
||||
buf[i] = u8(0xf0 + (c >> 18)); i += 1;
|
||||
buf[i] = u8(0x80 + ((c >> 12) & 0x3f)); i += 1;
|
||||
buf[i] = u8(0x80 + ((c >> 6) & 0x3f)); i += 1;
|
||||
buf[i] = u8(0x80 + ((c ) & 0x3f)); i += 1;
|
||||
buf[i] = byte(0xf0 + (c >> 18)); i += 1;
|
||||
buf[i] = byte(0x80 + ((c >> 12) & 0x3f)); i += 1;
|
||||
buf[i] = byte(0x80 + ((c >> 6) & 0x3f)); i += 1;
|
||||
buf[i] = byte(0x80 + ((c ) & 0x3f)); i += 1;
|
||||
j += 2;
|
||||
case 0xdc00 <= str[j] && str[j] < 0xe000:
|
||||
return "";
|
||||
case:
|
||||
if i+3 > len do return "";
|
||||
buf[i] = 0xe0 + u8 (str[j] >> 12); i += 1;
|
||||
buf[i] = 0x80 + u8((str[j] >> 6) & 0x3f); i += 1;
|
||||
buf[i] = 0x80 + u8((str[j] ) & 0x3f); i += 1;
|
||||
buf[i] = 0xe0 + byte (str[j] >> 12); i += 1;
|
||||
buf[i] = 0x80 + byte((str[j] >> 6) & 0x3f); i += 1;
|
||||
buf[i] = 0x80 + byte((str[j] ) & 0x3f); i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-23
@@ -4,9 +4,9 @@ foreign import libc "system:c"
|
||||
import "core:strings.odin"
|
||||
import "core:mem.odin"
|
||||
|
||||
Handle :: i32;
|
||||
File_Time :: u64;
|
||||
Errno :: int;
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
Errno :: distinct int;
|
||||
|
||||
|
||||
O_RDONLY :: 0x00000;
|
||||
@@ -46,12 +46,12 @@ RTLD_FIRST :: 0x100;
|
||||
// "Argv" arguments converted to Odin strings
|
||||
args := _alloc_command_line_arguments();
|
||||
|
||||
_File_Time :: struct #ordered {
|
||||
_File_Time :: struct {
|
||||
seconds: i64,
|
||||
nanoseconds: i64,
|
||||
}
|
||||
|
||||
Stat :: struct #ordered {
|
||||
Stat :: struct {
|
||||
device_id: i32, // ID of device containing file
|
||||
mode: u16, // Mode of the file
|
||||
nlink: u16, // Number of hard links
|
||||
@@ -122,38 +122,37 @@ X_OK :: 1; // Test for execute permission
|
||||
F_OK :: 0; // Test for file existance
|
||||
|
||||
foreign libc {
|
||||
@(link_name="open") _unix_open :: proc(path: ^u8, mode: int) -> Handle ---;
|
||||
@(link_name="open") _unix_open :: proc(path: ^byte, mode: int) -> Handle ---;
|
||||
@(link_name="close") _unix_close :: proc(handle: Handle) ---;
|
||||
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
|
||||
@(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
|
||||
@(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---;
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: ^u8, stat: ^Stat) -> int ---;
|
||||
@(link_name="access") _unix_access :: proc(path: ^u8, mask: int) -> int ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: ^byte, stat: ^Stat) -> int ---;
|
||||
@(link_name="access") _unix_access :: proc(path: ^byte, mask: int) -> int ---;
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(^u8) -> ^u8 ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(^byte) -> ^byte ---;
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: int) ---;
|
||||
}
|
||||
|
||||
foreign dl {
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> rawptr ---;
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^byte, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^byte) -> rawptr ---;
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> ^u8 ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> ^byte ---;
|
||||
}
|
||||
|
||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
||||
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
handle := _unix_open(cstr, mode);
|
||||
free(cstr);
|
||||
if(handle == -1) {
|
||||
if handle == -1 {
|
||||
return 0, 1;
|
||||
}
|
||||
return handle, 0;
|
||||
@@ -182,7 +181,7 @@ read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
bytes_read := _unix_read(fd, &data[0], len(data));
|
||||
if(bytes_read == -1) {
|
||||
if bytes_read == -1 {
|
||||
return 0, 1;
|
||||
}
|
||||
return bytes_read, 0;
|
||||
@@ -192,7 +191,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
assert(fd != -1);
|
||||
|
||||
final_offset := i64(_unix_lseek(fd, int(offset), whence));
|
||||
if(final_offset == -1) {
|
||||
if final_offset == -1 {
|
||||
return 0, 1;
|
||||
}
|
||||
return final_offset, 0;
|
||||
@@ -244,9 +243,9 @@ heap_free :: inline proc(ptr: rawptr) {
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_c_string(name);
|
||||
cstr: ^u8 = _unix_getenv(path_str);
|
||||
free(path_str);
|
||||
if(cstr == nil) {
|
||||
defer free(path_str);
|
||||
cstr := _unix_getenv(path_str);
|
||||
if cstr == nil {
|
||||
return "", false;
|
||||
}
|
||||
return strings.to_odin_string(cstr), true;
|
||||
@@ -258,21 +257,21 @@ exit :: inline proc(code: int) {
|
||||
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
// return cast(int) _unix_gettid();
|
||||
// return int(_unix_gettid());
|
||||
return 0;
|
||||
}
|
||||
|
||||
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.new_c_string(filename);
|
||||
defer free(cstr);
|
||||
handle := _unix_dlopen(cstr, flags);
|
||||
free(cstr);
|
||||
return handle;
|
||||
}
|
||||
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil);
|
||||
cstr := strings.new_c_string(symbol);
|
||||
defer free(cstr);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
free(cstr);
|
||||
return proc_handle;
|
||||
}
|
||||
dlclose :: inline proc(handle: rawptr) -> bool {
|
||||
|
||||
+24
-7
@@ -1,28 +1,45 @@
|
||||
Any :: struct #ordered {
|
||||
Any :: struct {
|
||||
data: rawptr,
|
||||
type_info: ^Type_Info,
|
||||
}
|
||||
|
||||
String :: struct #ordered {
|
||||
data: ^u8,
|
||||
String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Slice :: struct #ordered {
|
||||
Slice :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
}
|
||||
|
||||
Dynamic_Array :: struct #ordered {
|
||||
Dynamic_Array :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: Allocator,
|
||||
}
|
||||
|
||||
Map :: struct #ordered {
|
||||
Map :: struct {
|
||||
hashes: [dynamic]int,
|
||||
entries: Dynamic_Array,
|
||||
}
|
||||
|
||||
|
||||
make_any :: inline proc(data: rawptr, type_info: ^Type_Info) -> any {
|
||||
return transmute(any)Any{data, type_info};
|
||||
}
|
||||
|
||||
string_data :: inline proc(s: $T/string) -> ^byte {
|
||||
return (^String)(&s).data;
|
||||
}
|
||||
slice_data :: inline proc(a: $T/[]$E) -> ^E {
|
||||
return cast(^E)(^Slice)(&a).data;
|
||||
}
|
||||
dynamic_array_data :: inline proc(a: $T/[dynamic]$E) -> ^E {
|
||||
return cast(^E)(^Dynamic_Array)(&a).data;
|
||||
}
|
||||
|
||||
data :: proc[string_data, slice_data, dynamic_array_data];
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
bubble_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
count := len(array);
|
||||
|
||||
@@ -45,7 +45,7 @@ bubble_sort :: proc(array: $A/[]$T) {
|
||||
}
|
||||
}
|
||||
|
||||
quick_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
a := array;
|
||||
n := len(a);
|
||||
@@ -98,7 +98,7 @@ _log2 :: proc(n: int) -> int {
|
||||
return res;
|
||||
}
|
||||
|
||||
merge_sort :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
|
||||
+82
-62
@@ -14,7 +14,7 @@ parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
|
||||
case "0", "f", "F", "false", "FALSE", "False":
|
||||
return false, true;
|
||||
}
|
||||
return ok = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_digit_value :: proc(r: rune) -> int {
|
||||
@@ -28,7 +28,7 @@ _digit_value :: proc(r: rune) -> int {
|
||||
return v;
|
||||
}
|
||||
|
||||
parse_i128 :: proc(s: string) -> i128 {
|
||||
parse_i64 :: proc(s: string) -> i64 {
|
||||
neg := false;
|
||||
if len(s) > 1 {
|
||||
switch s[0] {
|
||||
@@ -41,7 +41,7 @@ parse_i128 :: proc(s: string) -> i128 {
|
||||
}
|
||||
|
||||
|
||||
base: i128 = 10;
|
||||
base: i64 = 10;
|
||||
if len(s) > 2 && s[0] == '0' {
|
||||
switch s[1] {
|
||||
case 'b': base = 2; s = s[2..];
|
||||
@@ -53,13 +53,13 @@ parse_i128 :: proc(s: string) -> i128 {
|
||||
}
|
||||
|
||||
|
||||
value: i128;
|
||||
value: i64;
|
||||
for r in s {
|
||||
if r == '_' {
|
||||
continue;
|
||||
}
|
||||
|
||||
v := i128(_digit_value(r));
|
||||
v := i64(_digit_value(r));
|
||||
if v >= base {
|
||||
break;
|
||||
}
|
||||
@@ -71,14 +71,14 @@ parse_i128 :: proc(s: string) -> i128 {
|
||||
return value;
|
||||
}
|
||||
|
||||
parse_u128 :: proc(s: string) -> u128 {
|
||||
parse_u64 :: proc(s: string) -> u64 {
|
||||
neg := false;
|
||||
if len(s) > 1 && s[0] == '+' {
|
||||
s = s[1..];
|
||||
}
|
||||
|
||||
|
||||
base := u128(10);
|
||||
base := u64(10);
|
||||
if len(s) > 2 && s[0] == '0' {
|
||||
switch s[1] {
|
||||
case 'b': base = 2; s = s[2..];
|
||||
@@ -90,13 +90,13 @@ parse_u128 :: proc(s: string) -> u128 {
|
||||
}
|
||||
|
||||
|
||||
value: u128;
|
||||
value: u64;
|
||||
for r in s {
|
||||
if r == '_' do continue;
|
||||
v := u128(_digit_value(r));
|
||||
v := u64(_digit_value(r));
|
||||
if v >= base do break;
|
||||
value *= base;
|
||||
value += u128(v);
|
||||
value += u64(v);
|
||||
}
|
||||
|
||||
if neg do return -value;
|
||||
@@ -105,13 +105,21 @@ parse_u128 :: proc(s: string) -> u128 {
|
||||
|
||||
|
||||
parse_int :: proc(s: string) -> int {
|
||||
return int(parse_i128(s));
|
||||
return int(parse_i64(s));
|
||||
}
|
||||
parse_uint :: proc(s: string, base: int) -> uint {
|
||||
return uint(parse_u128(s));
|
||||
return uint(parse_u64(s));
|
||||
}
|
||||
|
||||
parse_f32 :: proc(s: string) -> f32 {
|
||||
return f32(parse_f64(s));
|
||||
}
|
||||
|
||||
|
||||
parse_f64 :: proc(s: string) -> f64 {
|
||||
if s == "" {
|
||||
return 0;
|
||||
}
|
||||
i := 0;
|
||||
|
||||
sign: f64 = 1;
|
||||
@@ -180,21 +188,22 @@ parse_f64 :: proc(s: string) -> f64 {
|
||||
}
|
||||
|
||||
|
||||
append_bool :: proc(buf: []u8, b: bool) -> string {
|
||||
if b do append(&buf, "true");
|
||||
else do append(&buf, "false");
|
||||
return string(buf);
|
||||
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
n := 0;
|
||||
if b do n = copy(buf, cast([]byte)"true");
|
||||
else do n = copy(buf, cast([]byte)"false");
|
||||
return string(buf[..n]);
|
||||
}
|
||||
|
||||
append_uint :: proc(buf: []u8, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
|
||||
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, 0);
|
||||
}
|
||||
append_int :: proc(buf: []u8, i: i64, base: int) -> string {
|
||||
return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
|
||||
}
|
||||
itoa :: proc(buf: []u8, i: int) -> string do return append_int(buf, i64(i), 10);
|
||||
itoa :: proc(buf: []byte, i: int) -> string do return append_int(buf, i64(i), 10);
|
||||
|
||||
append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string {
|
||||
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
||||
}
|
||||
|
||||
@@ -202,7 +211,7 @@ append_float :: proc(buf: []u8, f: f64, fmt: u8, prec, bit_size: int) -> string
|
||||
|
||||
|
||||
DecimalSlice :: struct {
|
||||
digits: []u8,
|
||||
digits: []byte,
|
||||
count: int,
|
||||
decimal_point: int,
|
||||
neg: bool,
|
||||
@@ -220,7 +229,7 @@ _f32_info := FloatInfo{23, 8, -127};
|
||||
_f64_info := FloatInfo{52, 11, -1023};
|
||||
|
||||
|
||||
generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8 {
|
||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||
bits: u64;
|
||||
flt: ^FloatInfo;
|
||||
switch bit_size {
|
||||
@@ -248,8 +257,8 @@ generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8
|
||||
} else {
|
||||
s = "+Inf";
|
||||
}
|
||||
append(&buf, ...cast([]u8)s);
|
||||
return buf;
|
||||
n := copy(buf, cast([]byte)s);
|
||||
return buf[..n];
|
||||
|
||||
case 0: // denormalized
|
||||
exp += 1;
|
||||
@@ -292,48 +301,62 @@ generic_ftoa :: proc(buf: []u8, val: f64, fmt: u8, prec, bit_size: int) -> []u8
|
||||
|
||||
|
||||
|
||||
format_digits :: proc(buf: []u8, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: u8) -> []u8 {
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice, prec: int, fmt: byte) -> []byte {
|
||||
Buffer :: struct {
|
||||
b: []byte,
|
||||
n: int,
|
||||
}
|
||||
|
||||
to_bytes :: proc(b: Buffer) -> []byte do return b.b[..b.n];
|
||||
add_bytes :: proc(buf: ^Buffer, bytes: ...byte) {
|
||||
buf.n += copy(buf.b[buf.n..], bytes);
|
||||
}
|
||||
|
||||
b := Buffer{b = buf};
|
||||
|
||||
switch fmt {
|
||||
case 'f', 'F':
|
||||
append(&buf, neg ? '-' : '+');
|
||||
add_bytes(&b, neg ? '-' : '+');
|
||||
|
||||
// integer, padded with zeros when needed
|
||||
if digs.decimal_point > 0 {
|
||||
m := min(digs.count, digs.decimal_point);
|
||||
append(&buf, ...digs.digits[0..m]);
|
||||
add_bytes(&b, ...digs.digits[0..m]);
|
||||
for ; m < digs.decimal_point; m += 1 {
|
||||
append(&buf, '0');
|
||||
add_bytes(&b, '0');
|
||||
}
|
||||
} else {
|
||||
append(&buf, '0');
|
||||
add_bytes(&b, '0');
|
||||
}
|
||||
|
||||
|
||||
// fractional part
|
||||
if prec > 0 {
|
||||
append(&buf, '.');
|
||||
add_bytes(&b, '.');
|
||||
for i in 0..prec {
|
||||
c: u8 = '0';
|
||||
c: byte = '0';
|
||||
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||
c = digs.digits[j];
|
||||
}
|
||||
append(&buf, c);
|
||||
add_bytes(&b, c);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
return to_bytes(b);
|
||||
|
||||
case 'e', 'E':
|
||||
panic("strconv: e/E float printing is not yet supported");
|
||||
return buf; // TODO
|
||||
return to_bytes(b); // TODO
|
||||
|
||||
case 'g', 'G':
|
||||
panic("strconv: g/G float printing is not yet supported");
|
||||
return buf; // TODO
|
||||
return to_bytes(b); // TODO
|
||||
|
||||
case:
|
||||
add_bytes(&b, '%', fmt);
|
||||
return to_bytes(b);
|
||||
}
|
||||
|
||||
c := [2]u8{'%', fmt};
|
||||
append(&buf, ...c[..]);
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
||||
@@ -374,12 +397,12 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
||||
inclusive := mant%2 == 0;
|
||||
|
||||
for i in 0..d.count {
|
||||
l: u8 = '0'; // lower digit
|
||||
l: byte = '0'; // lower digit
|
||||
if i < lower.count {
|
||||
l = lower.digits[i];
|
||||
}
|
||||
m := d.digits[i]; // middle digit
|
||||
u: u8 = '0'; // upper digit
|
||||
u: byte = '0'; // upper digit
|
||||
if i < upper.count {
|
||||
u = upper.digits[i];
|
||||
}
|
||||
@@ -407,30 +430,25 @@ MAX_BASE :: 32;
|
||||
digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
|
||||
is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
|
||||
neg := false;
|
||||
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
|
||||
if is_signed {
|
||||
switch bit_size {
|
||||
case 8:
|
||||
i := i8(u);
|
||||
neg = i < 0;
|
||||
u = u128(abs(i));
|
||||
u = u64(abs(i));
|
||||
case 16:
|
||||
i := i16(u);
|
||||
neg = i < 0;
|
||||
u = u128(abs(i));
|
||||
u = u64(abs(i));
|
||||
case 32:
|
||||
i := i32(u);
|
||||
neg = i < 0;
|
||||
u = u128(abs(i));
|
||||
u = u64(abs(i));
|
||||
case 64:
|
||||
i := i64(u);
|
||||
neg = i < 0;
|
||||
u = u128(abs(i));
|
||||
case 128:
|
||||
i := i128(u);
|
||||
neg = i < 0;
|
||||
u = u128(abs(i));
|
||||
u = u64(abs(i));
|
||||
case:
|
||||
panic("is_integer_negative: Unknown integer size");
|
||||
}
|
||||
@@ -438,21 +456,21 @@ is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigne
|
||||
return u, neg;
|
||||
}
|
||||
|
||||
append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
|
||||
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits");
|
||||
}
|
||||
|
||||
neg: bool;
|
||||
a: [129]u8;
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
u, neg = is_integer_negative(u, is_signed, bit_size);
|
||||
b := u128(base);
|
||||
b := u64(base);
|
||||
for u >= b {
|
||||
i-=1; a[i] = digits[uint(u % b)];
|
||||
i-=1; a[i] = digits[u % b];
|
||||
u /= b;
|
||||
}
|
||||
i-=1; a[i] = digits[uint(u % b)];
|
||||
i-=1; a[i] = digits[u % b];
|
||||
|
||||
if flags&Int_Flag.Prefix != 0 {
|
||||
ok := true;
|
||||
@@ -469,15 +487,17 @@ append_bits :: proc(buf: []u8, u: u128, base: int, is_signed: bool, bit_size: in
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
switch {
|
||||
case neg:
|
||||
i-=1; a[i] = '-';
|
||||
} else if flags&Int_Flag.Plus != 0 {
|
||||
case flags&Int_Flag.Plus != 0:
|
||||
i-=1; a[i] = '+';
|
||||
} else if flags&Int_Flag.Space != 0 {
|
||||
case flags&Int_Flag.Space != 0:
|
||||
i-=1; a[i] = ' ';
|
||||
}
|
||||
|
||||
append(&buf, ...a[i..]);
|
||||
return string(buf);
|
||||
out := a[i..];
|
||||
copy(buf, out);
|
||||
return string(buf[0..len(out)]);
|
||||
}
|
||||
|
||||
|
||||
+13
-6
@@ -1,22 +1,29 @@
|
||||
import "core:mem.odin"
|
||||
|
||||
new_string :: proc(s: string) -> string {
|
||||
c := make([]u8, len(s)+1);
|
||||
copy(c, cast([]u8)s);
|
||||
c := make([]byte, len(s)+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return string(c[..len(s)]);
|
||||
}
|
||||
|
||||
new_c_string :: proc(s: string) -> ^u8 {
|
||||
c := make([]u8, len(s)+1);
|
||||
copy(c, cast([]u8)s);
|
||||
new_c_string :: proc(s: string) -> ^byte {
|
||||
c := make([]byte, len(s)+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return &c[0];
|
||||
}
|
||||
|
||||
to_odin_string :: proc(str: ^u8) -> string {
|
||||
to_odin_string :: proc(str: ^byte) -> string {
|
||||
if str == nil do return "";
|
||||
end := str;
|
||||
for end^ != 0 do end+=1;
|
||||
return string(mem.slice_ptr(str, end-str));
|
||||
}
|
||||
|
||||
contains_rune :: proc(s: string, r: rune) -> int {
|
||||
for c, offset in s {
|
||||
if c == r do return offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ mutex_lock :: proc(m: ^Mutex) {
|
||||
}
|
||||
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return win32.try_enter_critical_section(&m._critical_section) != 0;
|
||||
return bool(win32.try_enter_critical_section(&m._critical_section));
|
||||
}
|
||||
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -12,8 +12,8 @@ CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
|
||||
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
||||
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
|
||||
|
||||
Hglrc :: Handle;
|
||||
Color_Ref :: u32;
|
||||
Hglrc :: distinct Handle;
|
||||
Color_Ref :: distinct u32;
|
||||
|
||||
Layer_Plane_Descriptor :: struct {
|
||||
size: u16,
|
||||
@@ -55,7 +55,7 @@ Glyph_Metrics_Float :: struct {
|
||||
Create_Context_Attribs_ARB_Type :: #type proc "c" (hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
|
||||
Choose_Pixel_Format_ARB_Type :: #type proc "c" (hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool;
|
||||
Swap_Interval_EXT_Type :: #type proc "c" (interval: i32) -> bool;
|
||||
Get_Extensions_String_ARB_Type :: #type proc "c" (Hdc) -> ^u8;
|
||||
Get_Extensions_String_ARB_Type :: #type proc "c" (Hdc) -> ^byte;
|
||||
|
||||
// Procedures
|
||||
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
|
||||
@@ -72,7 +72,7 @@ foreign opengl32 {
|
||||
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool ---;
|
||||
|
||||
@(link_name="wglGetProcAddress")
|
||||
get_proc_address :: proc(c_str: ^u8) -> rawptr ---;
|
||||
get_gl_proc_address :: proc(c_str: ^byte) -> rawptr ---;
|
||||
|
||||
@(link_name="wglDeleteContext")
|
||||
delete_context :: proc(hglrc: Hglrc) -> Bool ---;
|
||||
|
||||
+206
-74
@@ -6,35 +6,33 @@ when ODIN_OS == "windows" {
|
||||
foreign import "system:shell32.lib"
|
||||
}
|
||||
|
||||
Handle :: rawptr;
|
||||
Hwnd :: Handle;
|
||||
Hdc :: Handle;
|
||||
Hinstance :: Handle;
|
||||
Hicon :: Handle;
|
||||
Hcursor :: Handle;
|
||||
Hmenu :: Handle;
|
||||
Hbrush :: Handle;
|
||||
Hgdiobj :: Handle;
|
||||
Hmodule :: Handle;
|
||||
Hmonitor :: Handle;
|
||||
Hrawinput :: Handle;
|
||||
HKL :: Handle;
|
||||
Wparam :: uint;
|
||||
Lparam :: int;
|
||||
Lresult :: int;
|
||||
Wnd_Proc :: #type proc "c" (Hwnd, u32, Wparam, Lparam) -> Lresult;
|
||||
Handle :: distinct rawptr;
|
||||
Hwnd :: distinct Handle;
|
||||
Hdc :: distinct Handle;
|
||||
Hinstance :: distinct Handle;
|
||||
Hicon :: distinct Handle;
|
||||
Hcursor :: distinct Handle;
|
||||
Hmenu :: distinct Handle;
|
||||
Hbrush :: distinct Handle;
|
||||
Hgdiobj :: distinct Handle;
|
||||
Hmodule :: distinct Handle;
|
||||
Hmonitor :: distinct Handle;
|
||||
Hrawinput :: distinct Handle;
|
||||
HKL :: distinct Handle;
|
||||
Wparam :: distinct uint;
|
||||
Lparam :: distinct int;
|
||||
Lresult :: distinct int;
|
||||
Wnd_Proc :: distinct #type proc "c" (Hwnd, u32, Wparam, Lparam) -> Lresult;
|
||||
|
||||
Long_Ptr :: int;
|
||||
Long_Ptr :: distinct int;
|
||||
|
||||
Bool :: i32;
|
||||
FALSE: Bool : 0;
|
||||
TRUE: Bool : 1;
|
||||
Bool :: distinct b32;
|
||||
|
||||
Point :: struct #ordered {
|
||||
Point :: struct {
|
||||
x, y: i32,
|
||||
}
|
||||
|
||||
Wnd_Class_Ex_A :: struct #ordered {
|
||||
Wnd_Class_Ex_A :: struct {
|
||||
size, style: u32,
|
||||
wnd_proc: Wnd_Proc,
|
||||
cls_extra, wnd_extra: i32,
|
||||
@@ -42,11 +40,11 @@ Wnd_Class_Ex_A :: struct #ordered {
|
||||
icon: Hicon,
|
||||
cursor: Hcursor,
|
||||
background: Hbrush,
|
||||
menu_name, class_name: ^u8,
|
||||
menu_name, class_name: ^byte,
|
||||
sm: Hicon,
|
||||
}
|
||||
|
||||
Wnd_Class_Ex_W :: struct #ordered {
|
||||
Wnd_Class_Ex_W :: struct {
|
||||
size, style: u32,
|
||||
wnd_proc: Wnd_Proc,
|
||||
cls_extra, wnd_extra: i32,
|
||||
@@ -59,7 +57,7 @@ Wnd_Class_Ex_W :: struct #ordered {
|
||||
}
|
||||
|
||||
|
||||
Msg :: struct #ordered {
|
||||
Msg :: struct {
|
||||
hwnd: Hwnd,
|
||||
message: u32,
|
||||
wparam: Wparam,
|
||||
@@ -68,24 +66,24 @@ Msg :: struct #ordered {
|
||||
pt: Point,
|
||||
}
|
||||
|
||||
Rect :: struct #ordered {
|
||||
Rect :: struct {
|
||||
left: i32,
|
||||
top: i32,
|
||||
right: i32,
|
||||
bottom: i32,
|
||||
}
|
||||
|
||||
Filetime :: struct #ordered {
|
||||
Filetime :: struct {
|
||||
lo, hi: u32,
|
||||
}
|
||||
|
||||
Systemtime :: struct #ordered {
|
||||
Systemtime :: struct {
|
||||
year, month: u16,
|
||||
day_of_week, day: u16,
|
||||
hour, minute, second, millisecond: u16,
|
||||
}
|
||||
|
||||
By_Handle_File_Information :: struct #ordered {
|
||||
By_Handle_File_Information :: struct {
|
||||
file_attributes: u32,
|
||||
creation_time,
|
||||
last_access_time,
|
||||
@@ -98,7 +96,7 @@ By_Handle_File_Information :: struct #ordered {
|
||||
file_index_low: u32,
|
||||
}
|
||||
|
||||
File_Attribute_Data :: struct #ordered {
|
||||
File_Attribute_Data :: struct {
|
||||
file_attributes: u32,
|
||||
creation_time,
|
||||
last_access_time,
|
||||
@@ -107,7 +105,7 @@ File_Attribute_Data :: struct #ordered {
|
||||
file_size_low: u32,
|
||||
}
|
||||
|
||||
Find_Data :: struct #ordered{
|
||||
Find_Data :: struct{
|
||||
file_attributes: u32,
|
||||
creation_time: Filetime,
|
||||
last_access_time: Filetime,
|
||||
@@ -116,19 +114,45 @@ Find_Data :: struct #ordered{
|
||||
file_size_low: u32,
|
||||
reserved0: u32,
|
||||
reserved1: u32,
|
||||
file_name: [MAX_PATH]u8,
|
||||
alternate_file_name: [14]u8,
|
||||
file_name: [MAX_PATH]byte,
|
||||
alternate_file_name: [14]byte,
|
||||
}
|
||||
|
||||
Security_Attributes :: struct #ordered {
|
||||
Security_Attributes :: struct {
|
||||
length: u32,
|
||||
security_descriptor: rawptr,
|
||||
inherit_handle: Bool,
|
||||
}
|
||||
|
||||
Process_Information :: struct {
|
||||
process: Handle,
|
||||
thread: Handle,
|
||||
process_id: u32,
|
||||
thread_id: u32
|
||||
}
|
||||
|
||||
Startup_Info :: struct {
|
||||
cb : u32,
|
||||
reserved : ^u16,
|
||||
desktop : ^u16,
|
||||
title : ^u16,
|
||||
x : u32,
|
||||
y : u32,
|
||||
x_size : u32,
|
||||
y_size : u32,
|
||||
x_count_chars : u32,
|
||||
y_count_chars : u32,
|
||||
fill_attribute : u32,
|
||||
flags : u32,
|
||||
show_window : u16,
|
||||
_ : u16,
|
||||
_ : ^byte,
|
||||
stdin : Handle,
|
||||
stdout : Handle,
|
||||
stderr : Handle,
|
||||
}
|
||||
|
||||
Pixel_Format_Descriptor :: struct #ordered {
|
||||
Pixel_Format_Descriptor :: struct {
|
||||
size,
|
||||
version,
|
||||
flags: u32,
|
||||
@@ -152,14 +176,14 @@ Pixel_Format_Descriptor :: struct #ordered {
|
||||
stencil_bits,
|
||||
aux_buffers,
|
||||
layer_type,
|
||||
reserved: u8,
|
||||
reserved: byte,
|
||||
|
||||
layer_mask,
|
||||
visible_mask,
|
||||
damage_mask: u32,
|
||||
}
|
||||
|
||||
Critical_Section :: struct #ordered {
|
||||
Critical_Section :: struct {
|
||||
debug_info: ^Critical_Section_Debug,
|
||||
|
||||
lock_count: i32,
|
||||
@@ -169,7 +193,7 @@ Critical_Section :: struct #ordered {
|
||||
spin_count: ^u32,
|
||||
}
|
||||
|
||||
Critical_Section_Debug :: struct #ordered {
|
||||
Critical_Section_Debug :: struct {
|
||||
typ: u16,
|
||||
creator_back_trace_index: u16,
|
||||
critical_section: ^Critical_Section,
|
||||
@@ -181,30 +205,30 @@ Critical_Section_Debug :: struct #ordered {
|
||||
spare_word: u16,
|
||||
}
|
||||
|
||||
List_Entry :: struct #ordered {flink, blink: ^List_Entry};
|
||||
List_Entry :: struct {flink, blink: ^List_Entry};
|
||||
|
||||
|
||||
Raw_Input_Device :: struct #ordered {
|
||||
Raw_Input_Device :: struct {
|
||||
usage_page: u16,
|
||||
usage: u16,
|
||||
flags: u32,
|
||||
wnd_target: Hwnd,
|
||||
}
|
||||
|
||||
Raw_Input_Header :: struct #ordered {
|
||||
Raw_Input_Header :: struct {
|
||||
kind: u32,
|
||||
size: u32,
|
||||
device: Handle,
|
||||
wparam: Wparam,
|
||||
}
|
||||
|
||||
Raw_HID :: struct #ordered {
|
||||
Raw_HID :: struct {
|
||||
size_hid: u32,
|
||||
count: u32,
|
||||
raw_data: [1]u8,
|
||||
raw_data: [1]byte,
|
||||
}
|
||||
|
||||
Raw_Keyboard :: struct #ordered {
|
||||
Raw_Keyboard :: struct {
|
||||
make_code: u16,
|
||||
flags: u16,
|
||||
reserved: u16,
|
||||
@@ -213,11 +237,11 @@ Raw_Keyboard :: struct #ordered {
|
||||
extra_information: u32,
|
||||
}
|
||||
|
||||
Raw_Mouse :: struct #ordered {
|
||||
Raw_Mouse :: struct {
|
||||
flags: u16,
|
||||
using data: struct #raw_union {
|
||||
buttons: u32,
|
||||
using _: struct #ordered {
|
||||
using _: struct {
|
||||
button_flags: u16,
|
||||
button_data: u16,
|
||||
},
|
||||
@@ -228,7 +252,7 @@ Raw_Mouse :: struct #ordered {
|
||||
extra_information: u32,
|
||||
}
|
||||
|
||||
Raw_Input :: struct #ordered {
|
||||
Raw_Input :: struct {
|
||||
using header: Raw_Input_Header,
|
||||
data: struct #raw_union {
|
||||
mouse: Raw_Mouse,
|
||||
@@ -238,6 +262,26 @@ Raw_Input :: struct #ordered {
|
||||
}
|
||||
|
||||
|
||||
Overlapped :: struct {
|
||||
internal : ^u64,
|
||||
internal_high : ^u64,
|
||||
using _ : struct #raw_union {
|
||||
using _ : struct {
|
||||
offset : u32,
|
||||
offset_high : u32,
|
||||
},
|
||||
pointer : rawptr,
|
||||
},
|
||||
event : Handle,
|
||||
}
|
||||
|
||||
File_Notify_Information :: struct {
|
||||
next_entry_offset: u32,
|
||||
action: u32,
|
||||
file_name_length: u32,
|
||||
file_name: [1]u16,
|
||||
}
|
||||
|
||||
MAPVK_VK_TO_VSC :: 0;
|
||||
MAPVK_VSC_TO_VK :: 1;
|
||||
MAPVK_VK_TO_CHAR :: 2;
|
||||
@@ -427,22 +471,87 @@ PFD_DEPTH_DONTCARE :: 0x20000000;
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
||||
PFD_STEREO_DONTCARE :: 0x80000000;
|
||||
|
||||
GET_FILEEX_INFO_LEVELS :: i32;
|
||||
GET_FILEEX_INFO_LEVELS :: distinct i32;
|
||||
GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
|
||||
GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
|
||||
|
||||
STARTF_USESHOWWINDOW :: 0x00000001;
|
||||
STARTF_USESIZE :: 0x00000002;
|
||||
STARTF_USEPOSITION :: 0x00000004;
|
||||
STARTF_USECOUNTCHARS :: 0x00000008;
|
||||
STARTF_USEFILLATTRIBUTE :: 0x00000010;
|
||||
STARTF_RUNFULLSCREEN :: 0x00000020; // ignored for non-x86 platforms
|
||||
STARTF_FORCEONFEEDBACK :: 0x00000040;
|
||||
STARTF_FORCEOFFFEEDBACK :: 0x00000080;
|
||||
STARTF_USESTDHANDLES :: 0x00000100;
|
||||
STARTF_USEHOTKEY :: 0x00000200;
|
||||
STARTF_TITLEISLINKNAME :: 0x00000800;
|
||||
STARTF_TITLEISAPPID :: 0x00001000;
|
||||
STARTF_PREVENTPINNING :: 0x00002000;
|
||||
STARTF_UNTRUSTEDSOURCE :: 0x00008000;
|
||||
|
||||
|
||||
MOVEFILE_REPLACE_EXISTING :: 0x00000001;
|
||||
MOVEFILE_COPY_ALLOWED :: 0x00000002;
|
||||
MOVEFILE_DELAY_UNTIL_REBOOT :: 0x00000004;
|
||||
MOVEFILE_WRITE_THROUGH :: 0x00000008;
|
||||
MOVEFILE_CREATE_HARDLINK :: 0x00000010;
|
||||
MOVEFILE_FAIL_IF_NOT_TRACKABLE :: 0x00000020;
|
||||
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME :: 0x00000001;
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME :: 0x00000002;
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES :: 0x00000004;
|
||||
FILE_NOTIFY_CHANGE_SIZE :: 0x00000008;
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE :: 0x00000010;
|
||||
FILE_NOTIFY_CHANGE_LAST_ACCESS :: 0x00000020;
|
||||
FILE_NOTIFY_CHANGE_CREATION :: 0x00000040;
|
||||
FILE_NOTIFY_CHANGE_SECURITY :: 0x00000100;
|
||||
|
||||
FILE_FLAG_WRITE_THROUGH :: 0x80000000;
|
||||
FILE_FLAG_OVERLAPPED :: 0x40000000;
|
||||
FILE_FLAG_NO_BUFFERING :: 0x20000000;
|
||||
FILE_FLAG_RANDOM_ACCESS :: 0x10000000;
|
||||
FILE_FLAG_SEQUENTIAL_SCAN :: 0x08000000;
|
||||
FILE_FLAG_DELETE_ON_CLOSE :: 0x04000000;
|
||||
FILE_FLAG_BACKUP_SEMANTICS :: 0x02000000;
|
||||
FILE_FLAG_POSIX_SEMANTICS :: 0x01000000;
|
||||
FILE_FLAG_SESSION_AWARE :: 0x00800000;
|
||||
FILE_FLAG_OPEN_REPARSE_POINT :: 0x00200000;
|
||||
FILE_FLAG_OPEN_NO_RECALL :: 0x00100000;
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE :: 0x00080000;
|
||||
|
||||
FILE_ACTION_ADDED :: 0x00000001;
|
||||
FILE_ACTION_REMOVED :: 0x00000002;
|
||||
FILE_ACTION_MODIFIED :: 0x00000003;
|
||||
FILE_ACTION_RENAMED_OLD_NAME :: 0x00000004;
|
||||
FILE_ACTION_RENAMED_NEW_NAME :: 0x00000005;
|
||||
|
||||
CP_ACP :: 0; // default to ANSI code page
|
||||
CP_OEMCP :: 1; // default to OEM code page
|
||||
CP_MACCP :: 2; // default to MAC code page
|
||||
CP_THREAD_ACP :: 3; // current thread's ANSI code page
|
||||
CP_SYMBOL :: 42; // SYMBOL translations
|
||||
CP_UTF7 :: 65000; // UTF-7 translation
|
||||
CP_UTF8 :: 65001; // UTF-8 translation
|
||||
|
||||
@(default_calling_convention = "std")
|
||||
foreign kernel32 {
|
||||
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
|
||||
@(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: ^byte,
|
||||
process_attributes, thread_attributes: ^Security_Attributes,
|
||||
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
|
||||
current_direcotry: ^byte, startup_info : ^Startup_Info,
|
||||
process_information : ^Process_Information) -> Bool ---;
|
||||
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
|
||||
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
|
||||
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: ^u8) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: ^byte) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: ^u16) -> Hinstance ---;
|
||||
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
|
||||
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: ^u8) ---;
|
||||
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: ^byte) ---;
|
||||
|
||||
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> ^u8 ---;
|
||||
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> ^byte ---;
|
||||
@(link_name="GetCommandLineW") get_command_line_w :: proc() -> ^u16 ---;
|
||||
@(link_name="GetSystemMetrics") get_system_metrics :: proc(index: i32) -> i32 ---;
|
||||
@(link_name="GetCurrentThreadId") get_current_thread_id :: proc() -> u32 ---;
|
||||
@@ -456,7 +565,7 @@ foreign kernel32 {
|
||||
@(link_name="GetStdHandle") get_std_handle :: proc(h: i32) -> Handle ---;
|
||||
|
||||
@(link_name="CreateFileA")
|
||||
create_file_a :: proc(filename: ^u8, desired_access, share_module: u32,
|
||||
create_file_a :: proc(filename: ^byte, desired_access, share_module: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: Handle) -> Handle ---;
|
||||
|
||||
@@ -464,27 +573,50 @@ foreign kernel32 {
|
||||
@(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---;
|
||||
|
||||
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
|
||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: ^u8) -> u32 ---;
|
||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: ^byte) -> u32 ---;
|
||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: ^byte, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
||||
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
|
||||
|
||||
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: ^byte, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
@(link_name="CreateDirectoryW") create_directory_w :: proc(path: ^u16, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
|
||||
@(link_name="GetFileType") get_file_type :: proc(file_handle: Handle) -> u32 ---;
|
||||
@(link_name="SetFilePointer") set_file_pointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 ---;
|
||||
|
||||
@(link_name="SetHandleInformation") set_handle_information :: proc(obj: Handle, mask, flags: u32) -> Bool ---;
|
||||
|
||||
@(link_name="FindFirstFileA") find_first_file_a :: proc(file_name : ^u8, data : ^Find_Data) -> Handle ---;
|
||||
@(link_name="FindFirstFileA") find_first_file_a :: proc(file_name : ^byte, data : ^Find_Data) -> Handle ---;
|
||||
@(link_name="FindNextFileA") find_next_file_a :: proc(file : Handle, data : ^Find_Data) -> Bool ---;
|
||||
@(link_name="FindClose") find_close :: proc(file : Handle) -> Bool ---;
|
||||
|
||||
@(link_name="MoveFileExA") move_file_ex_a :: proc(existing, new: ^byte, flags: u32) -> Bool ---;
|
||||
@(link_name="DeleteFileA") delete_file_a :: proc(file_name : ^byte) -> Bool ---;
|
||||
@(link_name="CopyFileA") copy_file_a :: proc(existing, new: ^byte, fail_if_exists: Bool) -> Bool ---;
|
||||
|
||||
@(link_name="MoveFileExW") move_file_ex_w :: proc(existing, new: ^u16, flags: u32) -> Bool ---;
|
||||
@(link_name="DeleteFileW") delete_file_w :: proc(file_name : ^u16) -> Bool ---;
|
||||
@(link_name="CopyFileW") copy_file_w :: proc(existing, new: ^u16, fail_if_exists: Bool) -> Bool ---;
|
||||
|
||||
@(link_name="HeapAlloc") heap_alloc :: proc(h: Handle, flags: u32, bytes: int) -> rawptr ---;
|
||||
@(link_name="HeapReAlloc") heap_realloc :: proc(h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr ---;
|
||||
@(link_name="HeapFree") heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool ---;
|
||||
@(link_name="GetProcessHeap") get_process_heap :: proc() -> Handle ---;
|
||||
|
||||
@(link_name="FindFirstChangeNotificationA") find_first_change_notification_a :: proc(path: ^byte, watch_subtree: Bool, filter: u32) -> Handle ---;
|
||||
@(link_name="FindNextChangeNotification") find_next_change_notification :: proc(h: Handle) -> Bool ---;
|
||||
@(link_name="FindCloseChangeNotification") find_close_change_notification :: proc(h: Handle) -> Bool ---;
|
||||
|
||||
@(link_name="CreateSemaphoreA") create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^u8) -> Handle ---;
|
||||
@(link_name="ReadDirectoryChangesW") read_directory_changes_w :: proc(dir: Handle, buf: rawptr, buf_length: u32,
|
||||
watch_subtree: Bool, notify_filter: u32,
|
||||
bytes_returned: ^u32, overlapped: ^Overlapped,
|
||||
completion: rawptr) -> Bool ---;
|
||||
|
||||
@(link_name="WideCharToMultiByte") wide_char_to_multi_byte :: proc(code_page: u32, flags : u32,
|
||||
wchar_str: ^u16, wchar: i32,
|
||||
multi_str: ^byte, multi: i32,
|
||||
default_char: ^byte, used_default_char: ^Bool) -> i32 ---;
|
||||
|
||||
@(link_name="CreateSemaphoreA") create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^byte) -> Handle ---;
|
||||
@(link_name="ReleaseSemaphore") release_semaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool ---;
|
||||
@(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---;
|
||||
}
|
||||
@@ -527,12 +659,12 @@ foreign kernel32 {
|
||||
@(link_name="EnterCriticalSection") enter_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||
|
||||
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: ^u8) -> Handle ---;
|
||||
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: ^byte) -> Handle ---;
|
||||
|
||||
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: ^u8) -> Hmodule ---;
|
||||
@(link_name="LoadLibraryW") load_library_a :: proc(c_str: ^u16) -> Hmodule ---;
|
||||
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: ^byte) -> Hmodule ---;
|
||||
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: ^u16) -> Hmodule ---;
|
||||
@(link_name="FreeLibrary") free_library :: proc(h: Hmodule) ---;
|
||||
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: ^u8) -> rawptr ---;
|
||||
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: ^byte) -> rawptr ---;
|
||||
|
||||
}
|
||||
|
||||
@@ -545,13 +677,13 @@ foreign user32 {
|
||||
@(link_name="ScreenToClient") screen_to_client :: proc(h: Hwnd, p: ^Point) -> Bool ---;
|
||||
@(link_name="ClientToScreen") client_to_screen :: proc(h: Hwnd, p: ^Point) -> Bool ---;
|
||||
@(link_name="PostQuitMessage") post_quit_message :: proc(exit_code: i32) ---;
|
||||
@(link_name="SetWindowTextA") set_window_text_a :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool ---;
|
||||
@(link_name="SetWindowTextA") set_window_text_a :: proc(hwnd: Hwnd, c_string: ^byte) -> Bool ---;
|
||||
@(link_name="RegisterClassExA") register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 ---;
|
||||
@(link_name="RegisterClassExW") register_class_ex_w :: proc(wc: ^Wnd_Class_Ex_W) -> i16 ---;
|
||||
|
||||
@(link_name="CreateWindowExA")
|
||||
create_window_ex_a :: proc(ex_style: u32,
|
||||
class_name, title: ^u8,
|
||||
class_name, title: ^byte,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||
@@ -601,7 +733,7 @@ foreign user32 {
|
||||
@(link_name="GetWindowLongPtrW") get_window_long_ptr_w :: proc(wnd: Hwnd, index: i32) -> Long_Ptr ---;
|
||||
@(link_name="SetWindowLongPtrW") set_window_long_ptr_w :: proc(wnd: Hwnd, index: i32, new: Long_Ptr) -> Long_Ptr ---;
|
||||
|
||||
@(link_name="GetWindowText") get_window_text :: proc(wnd: Hwnd, str: ^u8, maxCount: i32) -> i32 ---;
|
||||
@(link_name="GetWindowText") get_window_text :: proc(wnd: Hwnd, str: ^byte, maxCount: i32) -> i32 ---;
|
||||
|
||||
@(link_name="GetClientRect") get_client_rect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool ---;
|
||||
|
||||
@@ -663,12 +795,12 @@ get_query_performance_frequency :: proc() -> i64 {
|
||||
return r;
|
||||
}
|
||||
|
||||
HIWORD :: proc(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
|
||||
HIWORD :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
|
||||
LOWORD :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
|
||||
LOWORD :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
|
||||
HIWORD_W :: proc(wParam: Wparam) -> u16 { return u16((u32(wParam) >> 16) & 0xffff); }
|
||||
HIWORD_L :: proc(lParam: Lparam) -> u16 { return u16((u32(lParam) >> 16) & 0xffff); }
|
||||
LOWORD_W :: proc(wParam: Wparam) -> u16 { return u16(wParam); }
|
||||
LOWORD_L :: proc(lParam: Lparam) -> u16 { return u16(lParam); }
|
||||
|
||||
is_key_down :: inline proc(key: Key_Code) -> bool do return get_async_key_state(i32(key)) < 0;
|
||||
is_key_down :: inline proc(key: Key_Code) -> bool { return get_async_key_state(i32(key)) < 0; }
|
||||
|
||||
|
||||
|
||||
@@ -724,14 +856,14 @@ FILE_TYPE_CHAR :: 0x0002;
|
||||
FILE_TYPE_PIPE :: 0x0003;
|
||||
|
||||
|
||||
Monitor_Info :: struct #ordered {
|
||||
Monitor_Info :: struct {
|
||||
size: u32,
|
||||
monitor: Rect,
|
||||
work: Rect,
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
Window_Placement :: struct #ordered {
|
||||
Window_Placement :: struct {
|
||||
length: u32,
|
||||
flags: u32,
|
||||
show_cmd: u32,
|
||||
@@ -740,7 +872,7 @@ Window_Placement :: struct #ordered {
|
||||
normal_pos: Rect,
|
||||
}
|
||||
|
||||
Bitmap_Info_Header :: struct #ordered {
|
||||
Bitmap_Info_Header :: struct {
|
||||
size: u32,
|
||||
width, height: i32,
|
||||
planes, bit_count: i16,
|
||||
@@ -751,13 +883,13 @@ Bitmap_Info_Header :: struct #ordered {
|
||||
clr_used: u32,
|
||||
clr_important: u32,
|
||||
}
|
||||
Bitmap_Info :: struct #ordered {
|
||||
Bitmap_Info :: struct {
|
||||
using header: Bitmap_Info_Header,
|
||||
colors: [1]Rgb_Quad,
|
||||
}
|
||||
|
||||
|
||||
Rgb_Quad :: struct #ordered {blue, green, red, reserved: u8}
|
||||
Rgb_Quad :: struct {blue, green, red, reserved: byte}
|
||||
|
||||
|
||||
Key_Code :: enum i32 {
|
||||
|
||||
+2
-1
@@ -14,7 +14,7 @@ Thread_Os_Specific :: struct {
|
||||
Thread :: struct {
|
||||
using specific: Thread_Os_Specific,
|
||||
procedure: Thread_Proc,
|
||||
data: any,
|
||||
data: rawptr,
|
||||
user_index: int,
|
||||
|
||||
init_context: Context,
|
||||
@@ -69,6 +69,7 @@ join :: proc(using thread: ^Thread) {
|
||||
win32.close_handle(win32_thread);
|
||||
win32_thread = win32.INVALID_HANDLE;
|
||||
}
|
||||
|
||||
destroy :: proc(thread: ^Thread) {
|
||||
join(thread);
|
||||
free(thread);
|
||||
|
||||
+1
-12
@@ -49,6 +49,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
|
||||
case Type_Info_Pointer:
|
||||
y, ok := b.variant.(Type_Info_Pointer);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Procedure:
|
||||
@@ -78,12 +79,6 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Vector:
|
||||
y, ok := b.variant.(Type_Info_Vector);
|
||||
if !ok do return false;
|
||||
if x.count != y.count do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Tuple:
|
||||
y, ok := b.variant.(Type_Info_Tuple);
|
||||
if !ok do return false;
|
||||
@@ -102,7 +97,6 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
switch {
|
||||
case len(x.types) != len(y.types),
|
||||
x.is_packed != y.is_packed,
|
||||
x.is_ordered != y.is_ordered,
|
||||
x.is_raw_union != y.is_raw_union,
|
||||
x.custom_align != y.custom_align:
|
||||
return false;
|
||||
@@ -231,11 +225,6 @@ is_slice :: proc(info: ^Type_Info) -> bool {
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Slice);
|
||||
return ok;
|
||||
}
|
||||
is_vector :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Vector);
|
||||
return ok;
|
||||
}
|
||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Tuple);
|
||||
|
||||
+15
-19
@@ -30,25 +30,23 @@ encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
|
||||
}
|
||||
|
||||
encode :: proc(d: []u16, s: []rune) -> int {
|
||||
n := len(s);
|
||||
for r in s do if r >= _surr_self do n += 1;
|
||||
|
||||
max_n := min(len(d), n);
|
||||
n = 0;
|
||||
|
||||
for r in s {
|
||||
n, m := 0, len(d);
|
||||
loop: for r in s {
|
||||
switch r {
|
||||
case 0.._surr1, _surr3.._surr_self:
|
||||
case 0.._surr1, _surr3 .. _surr_self:
|
||||
if m+1 < n do break loop;
|
||||
d[n] = u16(r);
|
||||
n += 1;
|
||||
|
||||
case _surr_self..MAX_RUNE:
|
||||
case _surr_self .. MAX_RUNE:
|
||||
if m+2 < n do break loop;
|
||||
r1, r2 := encode_surrogate_pair(r);
|
||||
d[n] = u16(r1);
|
||||
d[n+1] = u16(r2);
|
||||
n += 2;
|
||||
|
||||
case:
|
||||
if m+1 < n do break loop;
|
||||
d[n] = u16(REPLACEMENT_CHAR);
|
||||
n += 1;
|
||||
}
|
||||
@@ -57,26 +55,24 @@ encode :: proc(d: []u16, s: []rune) -> int {
|
||||
}
|
||||
|
||||
|
||||
encode :: proc(d: []u16, s: string) -> int {
|
||||
n := utf8.rune_count(s);
|
||||
for r in s do if r >= _surr_self do n += 1;
|
||||
|
||||
max_n := min(len(d), n);
|
||||
n = 0;
|
||||
|
||||
for r in s {
|
||||
encode_string :: proc(d: []u16, s: string) -> int {
|
||||
n, m := 0, len(d);
|
||||
loop: for r in s {
|
||||
switch r {
|
||||
case 0.._surr1, _surr3.._surr_self:
|
||||
case 0.._surr1, _surr3 .. _surr_self:
|
||||
if m+1 < n do break loop;
|
||||
d[n] = u16(r);
|
||||
n += 1;
|
||||
|
||||
case _surr_self..MAX_RUNE:
|
||||
case _surr_self .. MAX_RUNE:
|
||||
if m+2 < n do break loop;
|
||||
r1, r2 := encode_surrogate_pair(r);
|
||||
d[n] = u16(r1);
|
||||
d[n+1] = u16(r2);
|
||||
n += 2;
|
||||
|
||||
case:
|
||||
if m+1 < n do break loop;
|
||||
d[n] = u16(REPLACEMENT_CHAR);
|
||||
n += 1;
|
||||
}
|
||||
|
||||
+3
-3
@@ -92,7 +92,7 @@ encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
decode_rune :: inline proc(s: string) -> (rune, int) do return decode_rune(cast([]u8)s);
|
||||
decode_rune_from_string :: inline proc(s: string) -> (rune, int) do return decode_rune(cast([]u8)s);
|
||||
decode_rune :: proc(s: []u8) -> (rune, int) {
|
||||
n := len(s);
|
||||
if n < 1 {
|
||||
@@ -132,7 +132,7 @@ decode_rune :: proc(s: []u8) -> (rune, int) {
|
||||
|
||||
|
||||
|
||||
decode_last_rune :: inline proc(s: string) -> (rune, int) do return decode_last_rune(cast([]u8)s);
|
||||
decode_last_rune_from_string :: inline proc(s: string) -> (rune, int) do return decode_last_rune(cast([]u8)s);
|
||||
decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||
r: rune;
|
||||
size: int;
|
||||
@@ -213,7 +213,7 @@ valid_string :: proc(s: string) -> bool {
|
||||
|
||||
rune_start :: inline proc(b: u8) -> bool do return b&0xc0 != 0x80;
|
||||
|
||||
rune_count :: inline proc(s: string) -> int do return rune_count(cast([]u8)s);
|
||||
rune_count_from_string :: inline proc(s: string) -> int do return rune_count(cast([]u8)s);
|
||||
rune_count :: proc(s: []u8) -> int {
|
||||
count := 0;
|
||||
n := len(s);
|
||||
|
||||
+212
-37
@@ -4,6 +4,7 @@ import "core:mem.odin"
|
||||
import "core:bits.odin"
|
||||
import "core:hash.odin"
|
||||
import "core:math.odin"
|
||||
import "core:math/rand.odin"
|
||||
import "core:os.odin"
|
||||
import "core:raw.odin"
|
||||
import "core:sort.odin"
|
||||
@@ -12,15 +13,17 @@ import "core:types.odin"
|
||||
import "core:utf16.odin"
|
||||
import "core:utf8.odin"
|
||||
|
||||
// File scope `when` statements
|
||||
when ODIN_OS == "windows" {
|
||||
import "core:atomics.odin"
|
||||
import "core:opengl.odin"
|
||||
import "core:thread.odin"
|
||||
import win32 "core:sys/windows.odin"
|
||||
}
|
||||
|
||||
@(link_name="general_stuff")
|
||||
general_stuff :: proc() {
|
||||
{ // `do` for inline statmes rather than block
|
||||
fmt.println("# general_stuff");
|
||||
{ // `do` for inline statments rather than block
|
||||
foo :: proc() do fmt.println("Foo!");
|
||||
if false do foo();
|
||||
for false do foo();
|
||||
@@ -39,12 +42,12 @@ general_stuff :: proc() {
|
||||
i := i32(137);
|
||||
ptr := &i;
|
||||
|
||||
fp1 := (^f32)(ptr);
|
||||
_ = (^f32)(ptr);
|
||||
// ^f32(ptr) == ^(f32(ptr))
|
||||
fp2 := cast(^f32)ptr;
|
||||
_ = cast(^f32)ptr;
|
||||
|
||||
f1 := (^f32)(ptr)^;
|
||||
f2 := (cast(^f32)ptr)^;
|
||||
_ = (^f32)(ptr)^;
|
||||
_ = (cast(^f32)ptr)^;
|
||||
|
||||
// Questions: Should there be two ways to do it?
|
||||
}
|
||||
@@ -74,9 +77,42 @@ general_stuff :: proc() {
|
||||
for in 0..2 {} // 0, 1
|
||||
for in 0...2 {} // 0, 1, 2
|
||||
}
|
||||
|
||||
{ // Multiple sized booleans
|
||||
|
||||
x0: bool; // default
|
||||
x1: b8 = true;
|
||||
x2: b16 = false;
|
||||
x3: b32 = true;
|
||||
x4: b64 = false;
|
||||
|
||||
fmt.printf("x1: %T = %v;\n", x1, x1);
|
||||
fmt.printf("x2: %T = %v;\n", x2, x2);
|
||||
fmt.printf("x3: %T = %v;\n", x3, x3);
|
||||
fmt.printf("x4: %T = %v;\n", x4, x4);
|
||||
|
||||
// Having specific sized booleans is very useful when dealing with foreign code
|
||||
// and to enforce specific alignment for a boolean, especially within a struct
|
||||
}
|
||||
|
||||
{ // `distinct` types
|
||||
// Originally, all type declarations would create a distinct type unless #type_alias was present.
|
||||
// Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present.
|
||||
// If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct.
|
||||
|
||||
Int32 :: i32;
|
||||
compile_assert(Int32 == i32);
|
||||
|
||||
My_Int32 :: distinct i32;
|
||||
compile_assert(My_Int32 != i32);
|
||||
|
||||
My_Struct :: struct{x: int};
|
||||
compile_assert(My_Struct != struct{x: int});
|
||||
}
|
||||
}
|
||||
|
||||
default_struct_values :: proc() {
|
||||
fmt.println("# default_struct_values");
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x: f32,
|
||||
@@ -118,10 +154,10 @@ default_struct_values :: proc() {
|
||||
heap_one := new(Vector3); defer free(heap_one);
|
||||
heap_two := new_clone(Vector3{}); defer free(heap_two);
|
||||
|
||||
fmt.println("stack_default - ", stack_default);
|
||||
fmt.println("stack_literal - ", stack_literal);
|
||||
fmt.println("heap_one - ", heap_one^);
|
||||
fmt.println("heap_two - ", heap_two^);
|
||||
fmt.println("stack_default - ", stack_default);
|
||||
fmt.println("stack_literal - ", stack_literal);
|
||||
fmt.println("heap_one - ", heap_one^);
|
||||
fmt.println("heap_two - ", heap_two^);
|
||||
|
||||
|
||||
N :: 4;
|
||||
@@ -138,6 +174,7 @@ default_struct_values :: proc() {
|
||||
|
||||
|
||||
union_type :: proc() {
|
||||
fmt.println("\n# union_type");
|
||||
{
|
||||
val: union{int, bool};
|
||||
val = 137;
|
||||
@@ -288,15 +325,15 @@ union_type :: proc() {
|
||||
/*
|
||||
Entity :: struct {
|
||||
...
|
||||
derived: union{^Frog, ^Monster};
|
||||
derived: union{^Frog, ^Monster},
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity;
|
||||
using entity: Entity,
|
||||
...
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: Entity;
|
||||
using entity: Entity,
|
||||
...
|
||||
|
||||
}
|
||||
@@ -310,6 +347,8 @@ union_type :: proc() {
|
||||
}
|
||||
|
||||
parametric_polymorphism :: proc() {
|
||||
fmt.println("# parametric_polymorphism");
|
||||
|
||||
print_value :: proc(value: $T) {
|
||||
fmt.printf("print_value: %T %v\n", value, value);
|
||||
}
|
||||
@@ -345,11 +384,7 @@ parametric_polymorphism :: proc() {
|
||||
}
|
||||
|
||||
copy_slice :: proc(dst, src: []$T) -> int {
|
||||
n := min(len(dst), len(src));
|
||||
if n > 0 {
|
||||
mem.copy(&dst[0], &src[0], n*size_of(T));
|
||||
}
|
||||
return n;
|
||||
return mem.copy(&dst[0], &src[0], n*size_of(T));
|
||||
}
|
||||
|
||||
double_params :: proc(a: $A, b: $B) -> A {
|
||||
@@ -397,7 +432,7 @@ parametric_polymorphism :: proc() {
|
||||
context <- c {
|
||||
old_slots := table.slots;
|
||||
|
||||
cap := max(2*cap(table.slots), TABLE_SIZE_MIN);
|
||||
cap := max(2*len(table.slots), TABLE_SIZE_MIN);
|
||||
allocate(table, cap);
|
||||
|
||||
for s in old_slots do if s.occupied {
|
||||
@@ -414,16 +449,16 @@ parametric_polymorphism :: proc() {
|
||||
hash := get_hash(key); // Ad-hoc method which would fail in a different scope
|
||||
index := find_index(table, key, hash);
|
||||
if index < 0 {
|
||||
if f64(table.count) >= 0.75*f64(cap(table.slots)) {
|
||||
if f64(table.count) >= 0.75*f64(len(table.slots)) {
|
||||
expand(table);
|
||||
}
|
||||
assert(table.count <= cap(table.slots));
|
||||
assert(table.count <= len(table.slots));
|
||||
|
||||
hash := get_hash(key);
|
||||
index = int(hash % u32(cap(table.slots)));
|
||||
index = int(hash % u32(len(table.slots)));
|
||||
|
||||
for table.slots[index].occupied {
|
||||
if index += 1; index >= cap(table.slots) {
|
||||
if index += 1; index >= len(table.slots) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
@@ -450,9 +485,9 @@ parametric_polymorphism :: proc() {
|
||||
}
|
||||
|
||||
find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
|
||||
if cap(table.slots) <= 0 do return -1;
|
||||
if len(table.slots) <= 0 do return -1;
|
||||
|
||||
index := int(hash % u32(cap(table.slots)));
|
||||
index := int(hash % u32(len(table.slots)));
|
||||
for table.slots[index].occupied {
|
||||
if table.slots[index].hash == hash {
|
||||
if table.slots[index].key == key {
|
||||
@@ -460,7 +495,7 @@ parametric_polymorphism :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
if index += 1; index >= cap(table.slots) {
|
||||
if index += 1; index >= len(table.slots) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
@@ -510,12 +545,14 @@ prefix_table := [...]string{
|
||||
|
||||
threading_example :: proc() {
|
||||
when ODIN_OS == "windows" {
|
||||
unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
|
||||
fmt.println("# threading_example");
|
||||
|
||||
unordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
array[index] = array[len(array)-1];
|
||||
pop(array);
|
||||
}
|
||||
ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
|
||||
ordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
copy(array[index..], array[index+1..]);
|
||||
pop(array);
|
||||
@@ -530,10 +567,10 @@ threading_example :: proc() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
threads := make([]^thread.Thread, 0, len(prefix_table));
|
||||
threads := make([dynamic]^thread.Thread, 0, len(prefix_table));
|
||||
defer free(threads);
|
||||
|
||||
for i in 0..len(prefix_table) {
|
||||
for in prefix_table {
|
||||
if t := thread.create(worker_proc); t != nil {
|
||||
t.init_context = context;
|
||||
t.use_init_context = true;
|
||||
@@ -558,13 +595,151 @@ threading_example :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when false {
|
||||
fmt.println("\n# general_stuff"); general_stuff();
|
||||
fmt.println("\n# default_struct_values"); default_struct_values();
|
||||
fmt.println("\n# union_type"); union_type();
|
||||
fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
|
||||
fmt.println("\n# threading_example"); threading_example();
|
||||
array_programming :: proc() {
|
||||
fmt.println("# array_programming");
|
||||
{
|
||||
a := [3]f32{1, 2, 3};
|
||||
b := [3]f32{5, 6, 7};
|
||||
c := a * b;
|
||||
d := a + b;
|
||||
e := 1 + (c - d) / 2;
|
||||
fmt.printf("%.1f\n", e); // [0.5, 3.0, 6.5]
|
||||
}
|
||||
|
||||
{
|
||||
a := [3]f32{1, 2, 3};
|
||||
b := swizzle(a, 2, 1, 0);
|
||||
assert(b == [3]f32{3, 2, 1});
|
||||
|
||||
c := swizzle(a, 0, 0);
|
||||
assert(c == [2]f32{1, 1});
|
||||
assert(c == 1);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 :: distinct [3]f32;
|
||||
a := Vector3{1, 2, 3};
|
||||
b := Vector3{5, 6, 7};
|
||||
c := (a * b)/2 + 1;
|
||||
d := c.x + c.y + c.z;
|
||||
fmt.printf("%.1f\n", d); // 22.0
|
||||
|
||||
cross :: proc(a, b: Vector3) -> Vector3 {
|
||||
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
|
||||
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
|
||||
return i - j;
|
||||
}
|
||||
|
||||
blah :: proc(a: Vector3) -> f32 {
|
||||
return a.x + a.y + a.z;
|
||||
}
|
||||
|
||||
x := cross(a, b);
|
||||
fmt.println(x);
|
||||
fmt.println(blah(x));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using println in import "core:fmt.odin"
|
||||
|
||||
using_in :: proc() {
|
||||
fmt.println("# using in");
|
||||
using print in fmt;
|
||||
|
||||
println("Hellope1");
|
||||
print("Hellope2\n");
|
||||
|
||||
Foo :: struct {
|
||||
x, y: int,
|
||||
b: bool,
|
||||
}
|
||||
f: Foo;
|
||||
f.x, f.y = 123, 321;
|
||||
println(f);
|
||||
using x, y in f;
|
||||
f.x, f.y = 456, 654;
|
||||
println(f);
|
||||
}
|
||||
|
||||
named_proc_return_parameters :: proc() {
|
||||
fmt.println("# named proc return parameters");
|
||||
|
||||
foo0 :: proc() -> int {
|
||||
return 123;
|
||||
}
|
||||
foo1 :: proc() -> (a: int) {
|
||||
a = 123;
|
||||
return;
|
||||
}
|
||||
foo2 :: proc() -> (a, b: int) {
|
||||
// Named return values act like variables within the scope
|
||||
a = 321;
|
||||
b = 567;
|
||||
return b, a;
|
||||
}
|
||||
fmt.println("foo0 =", foo0()); // 123
|
||||
fmt.println("foo1 =", foo1()); // 123
|
||||
fmt.println("foo2 =", foo2()); // 567 321
|
||||
}
|
||||
|
||||
|
||||
enum_export :: proc() {
|
||||
fmt.println("# enum #export");
|
||||
|
||||
Foo :: enum #export {A, B, C};
|
||||
|
||||
f0 := A;
|
||||
f1 := B;
|
||||
f2 := C;
|
||||
fmt.println(f0, f1, f2);
|
||||
}
|
||||
|
||||
explicit_procedure_overloading :: proc() {
|
||||
fmt.println("# explicit procedure overloading");
|
||||
|
||||
add_ints :: proc(a, b: int) -> int {
|
||||
x := a + b;
|
||||
fmt.println("add_ints", x);
|
||||
return x;
|
||||
}
|
||||
add_floats :: proc(a, b: f32) -> f32 {
|
||||
x := a + b;
|
||||
fmt.println("add_floats", x);
|
||||
return x;
|
||||
}
|
||||
add_numbers :: proc(a: int, b: f32, c: u8) -> int {
|
||||
x := int(a) + int(b) + int(c);
|
||||
fmt.println("add_numbers", x);
|
||||
return x;
|
||||
}
|
||||
|
||||
add :: proc[add_ints, add_floats, add_numbers];
|
||||
|
||||
add(int(1), int(2));
|
||||
add(f32(1), f32(2));
|
||||
add(int(1), f32(2), u8(3));
|
||||
|
||||
add(1, 2); // untyped ints coerce to int tighter than f32
|
||||
add(1.0, 2.0); // untyped floats coerce to f32 tighter than int
|
||||
add(1, 2, 3); // three parameters
|
||||
|
||||
// Ambiguous answers
|
||||
// add(1.0, 2);
|
||||
// add(1, 2.0);
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
general_stuff();
|
||||
default_struct_values();
|
||||
union_type();
|
||||
parametric_polymorphism();
|
||||
threading_example();
|
||||
array_programming();
|
||||
using_in();
|
||||
named_proc_return_parameters();
|
||||
enum_export();
|
||||
explicit_procedure_overloading();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import win32 "core:sys/windows.odin" when ODIN_OS == "windows";
|
||||
import wgl "core:sys/wgl.odin" when ODIN_OS == "windows";
|
||||
when ODIN_OS == "windows" do import win32 "core:sys/windows.odin";
|
||||
when ODIN_OS == "windows" import wgl "core:sys/wgl.odin";
|
||||
import "core:fmt.odin";
|
||||
import "core:math.odin";
|
||||
import "core:os.odin";
|
||||
|
||||
+15
-3
@@ -7,6 +7,7 @@ struct BuildContext {
|
||||
String ODIN_VENDOR; // compiler vendor
|
||||
String ODIN_VERSION; // compiler version
|
||||
String ODIN_ROOT; // Odin ROOT
|
||||
bool ODIN_DEBUG; // Odin in debug mode
|
||||
|
||||
// In bytes
|
||||
i64 word_size; // Size of a pointer, must be >= 4
|
||||
@@ -22,6 +23,7 @@ struct BuildContext {
|
||||
i32 optimization_level;
|
||||
bool show_timings;
|
||||
bool keep_temp_files;
|
||||
bool no_bounds_check;
|
||||
|
||||
gbAffinity affinity;
|
||||
isize thread_count;
|
||||
@@ -262,7 +264,7 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
gb_mutex_lock(&string_buffer_mutex);
|
||||
p = realpath(cast(char *)s.text, 0);
|
||||
gb_mutex_unlock(&string_buffer_mutex);
|
||||
if(p == nullptr) return make_string_c("");
|
||||
if(p == nullptr) return String{};
|
||||
return make_string_c(p);
|
||||
}
|
||||
#else
|
||||
@@ -307,7 +309,9 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
}
|
||||
|
||||
|
||||
String const ODIN_VERSION = str_lit("0.7.1");
|
||||
String const ODIN_VERSION = str_lit("0.8.1");
|
||||
String cross_compile_target = str_lit("");
|
||||
String cross_compile_lib_dir = str_lit("");
|
||||
|
||||
void init_build_context(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
@@ -329,6 +333,10 @@ void init_build_context(void) {
|
||||
bc->ODIN_OS = str_lit("linux");
|
||||
#endif
|
||||
|
||||
if (cross_compile_target.len) {
|
||||
bc->ODIN_OS = cross_compile_target;
|
||||
}
|
||||
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
bc->ODIN_ARCH = str_lit("amd64");
|
||||
#else
|
||||
@@ -375,7 +383,11 @@ void init_build_context(void) {
|
||||
bc->max_align = 16;
|
||||
|
||||
bc->llc_flags = str_lit("-march=x86-64 ");
|
||||
bc->link_flags = str_lit(LINK_FLAG_X64 " ");
|
||||
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
|
||||
bc->link_flags = str_lit(" ");
|
||||
} else {
|
||||
bc->link_flags = str_lit(LINK_FLAG_X64 " ");
|
||||
}
|
||||
} else if (bc->ODIN_ARCH == "x86") {
|
||||
bc->word_size = 4;
|
||||
bc->max_align = 8;
|
||||
|
||||
+202
-27
@@ -23,9 +23,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
}
|
||||
|
||||
|
||||
if (operand->mode == Addressing_Overload) {
|
||||
if (operand->mode == Addressing_ProcGroup) {
|
||||
if (e->type == nullptr) {
|
||||
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->overload_entities[0]->token.string));
|
||||
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->proc_group->token.string));
|
||||
} else {
|
||||
check_assignment(c, operand, e->type, str_lit("variable assignment"));
|
||||
if (operand->mode != Addressing_Type) {
|
||||
@@ -170,22 +170,57 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
e->Constant.value = operand->value;
|
||||
}
|
||||
|
||||
AstNode *remove_type_alias(AstNode *node) {
|
||||
|
||||
bool is_type_distinct(AstNode *node) {
|
||||
for (;;) {
|
||||
if (node == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (node->kind == AstNode_ParenExpr) {
|
||||
node = node->ParenExpr.expr;
|
||||
} else if (node->kind == AstNode_HelperType) {
|
||||
node = node->HelperType.type;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (node->kind) {
|
||||
case AstNode_DistinctType:
|
||||
return true;
|
||||
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_EnumType:
|
||||
case AstNode_BitFieldType:
|
||||
case AstNode_ProcType:
|
||||
return true;
|
||||
|
||||
case AstNode_PointerType:
|
||||
case AstNode_ArrayType:
|
||||
case AstNode_DynamicArrayType:
|
||||
case AstNode_MapType:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AstNode *remove_type_alias_clutter(AstNode *node) {
|
||||
for (;;) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (node->kind == AstNode_ParenExpr) {
|
||||
node = node->ParenExpr.expr;
|
||||
} else if (node->kind == AstNode_AliasType) {
|
||||
node = node->AliasType.type;
|
||||
} else if (node->kind == AstNode_DistinctType) {
|
||||
node = node->DistinctType.type;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool is_alias) {
|
||||
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||
@@ -193,7 +228,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool
|
||||
error(decl->attributes[0], "Attributes are not allowed on type declarations");
|
||||
}
|
||||
|
||||
AstNode *te = remove_type_alias(type_expr);
|
||||
bool is_distinct = is_type_distinct(type_expr);
|
||||
AstNode *te = remove_type_alias_clutter(type_expr);
|
||||
e->type = t_invalid;
|
||||
String name = e->token.string;
|
||||
Type *named = make_type_named(c->allocator, name, nullptr, e);
|
||||
@@ -205,16 +241,20 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, bool
|
||||
|
||||
Type *bt = check_type(c, te, named);
|
||||
named->Named.base = base_type(bt);
|
||||
if (is_alias) {
|
||||
if (is_type_named(bt)) {
|
||||
e->type = bt;
|
||||
e->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
gbString str = type_to_string(bt);
|
||||
error(type_expr, "Type alias declaration with a non-named type '%s'", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
if (!is_distinct) {
|
||||
e->type = bt;
|
||||
e->TypeName.is_type_alias = true;
|
||||
}
|
||||
// if (is_alias) {
|
||||
// if (is_type_named(bt)) {
|
||||
// e->type = bt;
|
||||
// e->TypeName.is_type_alias = true;
|
||||
// } else {
|
||||
// gbString str = type_to_string(bt);
|
||||
// error(type_expr, "Type alias declaration with a non-named type '%s'", str);
|
||||
// gb_string_free(str);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
|
||||
@@ -254,18 +294,18 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
switch (operand.mode) {
|
||||
case Addressing_Type: {
|
||||
e->kind = Entity_TypeName;
|
||||
e->type = nullptr;
|
||||
|
||||
DeclInfo *d = c->context.decl;
|
||||
if (d->type_expr != nullptr) {
|
||||
error(e->token, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = d->init_expr;
|
||||
check_type_decl(c, e, d->type_expr, named_type, false);
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE(bill): Check to see if the expression it to be aliases
|
||||
#if 1
|
||||
// NOTE(bill): Check to see if the expression it to be aliases
|
||||
case Addressing_Builtin:
|
||||
if (e->type != nullptr) {
|
||||
error(type_expr, "A constant alias of a built-in procedure may not have a type initializer");
|
||||
@@ -275,14 +315,16 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
e->type = t_invalid;
|
||||
return;
|
||||
|
||||
case Addressing_Overload:
|
||||
e->kind = Entity_Alias;
|
||||
e->Alias.base = operand.overload_entities[0];
|
||||
case Addressing_ProcGroup:
|
||||
GB_ASSERT(operand.proc_group != nullptr);
|
||||
GB_ASSERT(operand.proc_group->kind == Entity_ProcGroup);
|
||||
|
||||
e->kind = Entity_ProcGroup;
|
||||
e->type = t_invalid;
|
||||
gb_memmove(&e->ProcGroup, &operand.proc_group->ProcGroup, gb_size_of(e->ProcGroup));
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#if 1
|
||||
|
||||
if (entity != nullptr) {
|
||||
switch (entity->kind) {
|
||||
case Entity_Alias:
|
||||
@@ -312,7 +354,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (init != nullptr) {
|
||||
@@ -424,6 +465,7 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
} else {
|
||||
// TODO(bill): Extra stuff to do with library names?
|
||||
*foreign_library = found;
|
||||
found->LibraryName.used = true;
|
||||
add_entity_use(c, ident, found);
|
||||
}
|
||||
}
|
||||
@@ -708,11 +750,137 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
check_init_variables(c, entities, entity_count, init_expr_list, context_name);
|
||||
}
|
||||
|
||||
void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
|
||||
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
|
||||
auto *pge = &pg_entity->ProcGroup;
|
||||
String proc_group_name = pg_entity->token.string;
|
||||
|
||||
ast_node(pg, ProcGroup, d->init_expr);
|
||||
|
||||
array_init(&pge->entities, c->allocator, pg->args.count);
|
||||
|
||||
// NOTE(bill): This must be set here to prevent cycles in checking if someone
|
||||
// places the entity within itself
|
||||
pg_entity->type = t_invalid;
|
||||
|
||||
PtrSet<Entity *> entity_map = {};
|
||||
ptr_set_init(&entity_map, heap_allocator());
|
||||
defer (ptr_set_destroy(&entity_map));
|
||||
|
||||
for_array(i, pg->args) {
|
||||
AstNode *arg = pg->args[i];
|
||||
Entity *e = nullptr;
|
||||
Operand o = {};
|
||||
if (arg->kind == AstNode_Ident) {
|
||||
e = check_ident(c, &o, arg, nullptr, nullptr, true);
|
||||
} else if (arg->kind == AstNode_SelectorExpr) {
|
||||
e = check_selector(c, &o, arg, nullptr);
|
||||
}
|
||||
if (e == nullptr) {
|
||||
error(arg, "Expected a valid entity name in procedure group, got %.*s", LIT(ast_node_strings[arg->kind]));
|
||||
continue;
|
||||
}
|
||||
if (e->kind == Entity_Variable) {
|
||||
if (!is_type_proc(e->type)) {
|
||||
gbString s = type_to_string(e->type);
|
||||
defer (gb_string_free(s));
|
||||
error(arg, "Expected a procedure, got %s", s);
|
||||
continue;
|
||||
}
|
||||
} else if (e->kind != Entity_Procedure) {
|
||||
error(arg, "Expected a procedure entity");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr_set_exists(&entity_map, e)) {
|
||||
error(arg, "Previous use of `%.*s` in procedure group", LIT(e->token.string));
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&entity_map, e);
|
||||
array_add(&pge->entities, e);
|
||||
}
|
||||
|
||||
for_array(j, pge->entities) {
|
||||
Entity *p = pge->entities[j];
|
||||
if (p->type == t_invalid) {
|
||||
// NOTE(bill): This invalid overload has already been handled
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = p->token.string;
|
||||
|
||||
for (isize k = j+1; k < pge->entities.count; k++) {
|
||||
Entity *q = pge->entities[k];
|
||||
GB_ASSERT(p != q);
|
||||
|
||||
bool is_invalid = false;
|
||||
|
||||
TokenPos pos = q->token.pos;
|
||||
|
||||
if (q->type == nullptr || q->type == t_invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
switch (kind) {
|
||||
case ProcOverload_Identical:
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
// case ProcOverload_CallingConvention:
|
||||
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
|
||||
// is_invalid = true;
|
||||
// break;
|
||||
case ProcOverload_ParamVariadic:
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_ResultCount:
|
||||
case ProcOverload_ResultTypes:
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_Polymorphic:
|
||||
#if 0
|
||||
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
|
||||
is_invalid = true;
|
||||
#endif
|
||||
break;
|
||||
case ProcOverload_ParamCount:
|
||||
case ProcOverload_ParamTypes:
|
||||
// This is okay :)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (is_invalid) {
|
||||
gb_printf_err("\tprevious procedure at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
|
||||
q->type = t_invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
if (e->type != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
char buf[256] = {};
|
||||
isize n = gb_snprintf(buf, 256, "%.*s %d", LIT(e->token.string), e->kind);
|
||||
Timings timings = {};
|
||||
timings_init(&timings, make_string(cast(u8 *)buf, n-1), 16);
|
||||
defer ({
|
||||
timings_print_all(&timings);
|
||||
timings_destroy(&timings);
|
||||
});
|
||||
#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str))
|
||||
#else
|
||||
#define TIME_SECTION(str)
|
||||
#endif
|
||||
|
||||
if (d == nullptr) {
|
||||
d = decl_info_of_entity(&c->info, e);
|
||||
if (d == nullptr) {
|
||||
@@ -738,16 +906,20 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
|
||||
break;
|
||||
case Entity_TypeName: {
|
||||
bool is_alias = unparen_expr(d->type_expr)->kind == AstNode_AliasType;
|
||||
check_type_decl(c, e, d->type_expr, named_type, is_alias);
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
break;
|
||||
}
|
||||
case Entity_Procedure:
|
||||
check_proc_decl(c, e, d);
|
||||
break;
|
||||
case Entity_ProcGroup:
|
||||
check_proc_group_decl(c, e, d);
|
||||
break;
|
||||
}
|
||||
|
||||
c->context = prev;
|
||||
|
||||
#undef TIME_SECTION
|
||||
}
|
||||
|
||||
|
||||
@@ -786,6 +958,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
continue;
|
||||
}
|
||||
bool is_immutable = e->Variable.is_immutable;
|
||||
bool is_value = (e->flags & EntityFlag_Value) != 0;
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (t->kind == Type_Struct) {
|
||||
@@ -799,6 +972,8 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
|
||||
+258
-498
File diff suppressed because it is too large
Load Diff
+792
-749
File diff suppressed because it is too large
Load Diff
+105
-325
@@ -34,221 +34,6 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
|
||||
|
||||
}
|
||||
|
||||
|
||||
void check_struct_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields, Map<Entity *> *entity_map, AstNode *struct_node, String context, bool allow_default_values) {
|
||||
GB_ASSERT(fields != nullptr);
|
||||
if (decl->kind == AstNode_WhenStmt) {
|
||||
ast_node(ws, WhenStmt, decl);
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr(c, &operand, ws->cond);
|
||||
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
|
||||
error(ws->cond, "Non-constant boolean 'when' condition");
|
||||
return;
|
||||
}
|
||||
if (ws->body == nullptr || ws->body->kind != AstNode_BlockStmt) {
|
||||
error(ws->cond, "Invalid body for 'when' statement");
|
||||
return;
|
||||
}
|
||||
if (operand.value.kind == ExactValue_Bool &&
|
||||
operand.value.value_bool) {
|
||||
for_array(i, ws->body->BlockStmt.stmts) {
|
||||
AstNode *stmt = ws->body->BlockStmt.stmts[i];
|
||||
check_struct_field_decl(c, stmt, fields, entity_map, struct_node, context, allow_default_values);
|
||||
}
|
||||
} else if (ws->else_stmt) {
|
||||
switch (ws->else_stmt->kind) {
|
||||
case AstNode_BlockStmt:
|
||||
for_array(i, ws->else_stmt->BlockStmt.stmts) {
|
||||
AstNode *stmt = ws->else_stmt->BlockStmt.stmts[i];
|
||||
check_struct_field_decl(c, stmt, fields, entity_map, struct_node, context, allow_default_values);
|
||||
}
|
||||
break;
|
||||
case AstNode_WhenStmt:
|
||||
check_struct_field_decl(c, ws->else_stmt, fields, entity_map, struct_node, context, allow_default_values);
|
||||
break;
|
||||
default:
|
||||
error(ws->else_stmt, "Invalid 'else' statement in 'when' statement");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (decl->kind != AstNode_ValueDecl) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ast_node(vd, ValueDecl, decl);
|
||||
|
||||
if (!vd->is_mutable) return;
|
||||
|
||||
bool is_using = vd->is_using;
|
||||
|
||||
if (is_using && vd->names.count > 1) {
|
||||
error(vd->names[0], "Cannot apply 'using' to more than one of the same type");
|
||||
is_using = false;
|
||||
}
|
||||
|
||||
bool arity_ok = check_arity_match(c, vd);
|
||||
|
||||
if (vd->values.count > 0 && !allow_default_values) {
|
||||
error(vd->values[0], "Default values are not allowed within a %.*s", LIT(context));
|
||||
}
|
||||
|
||||
|
||||
Type *type = nullptr;
|
||||
if (vd->type != nullptr) {
|
||||
type = check_type(c, vd->type);
|
||||
} else if (!allow_default_values) {
|
||||
error(vd->names[0], "Expected a type for this field");
|
||||
type = t_invalid;
|
||||
}
|
||||
|
||||
if (type != nullptr) {
|
||||
if (is_type_empty_union(type)) {
|
||||
error(vd->names[0], "An empty union cannot be used as a field type in %.*s", LIT(context));
|
||||
type = t_invalid;
|
||||
}
|
||||
if (!c->context.allow_polymorphic_types && is_type_polymorphic(base_type(type))) {
|
||||
error(vd->names[0], "Invalid use of a polymorphic type in %.*s", LIT(context));
|
||||
type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
Array<Operand> default_values = {};
|
||||
defer (array_free(&default_values));
|
||||
if (vd->values.count > 0 && allow_default_values) {
|
||||
array_init(&default_values, heap_allocator(), 2*vd->values.count);
|
||||
|
||||
Type *type_hint = nullptr;
|
||||
if (type != t_invalid && type != nullptr) {
|
||||
type_hint = type;
|
||||
}
|
||||
|
||||
for_array(i, vd->values) {
|
||||
AstNode *v = vd->values[i];
|
||||
Operand o = {};
|
||||
|
||||
check_expr_base(c, &o, v, type_hint);
|
||||
check_not_tuple(c, &o);
|
||||
|
||||
if (o.mode == Addressing_NoValue) {
|
||||
error_operand_no_value(&o);
|
||||
} else {
|
||||
if (o.mode == Addressing_Value && o.type->kind == Type_Tuple) {
|
||||
// NOTE(bill): Tuples are not first class thus never named
|
||||
for_array(index, o.type->Tuple.variables) {
|
||||
Operand single = {Addressing_Value};
|
||||
single.type = o.type->Tuple.variables[index]->type;
|
||||
single.expr = v;
|
||||
array_add(&default_values, single);
|
||||
}
|
||||
} else {
|
||||
array_add(&default_values, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isize name_field_index = 0;
|
||||
for_array(name_index, vd->names) {
|
||||
AstNode *name = vd->names[name_index];
|
||||
if (!ast_node_expect(name, AstNode_Ident)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Token name_token = name->Ident.token;
|
||||
|
||||
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)fields->count);
|
||||
e->identifier = name;
|
||||
|
||||
if (name_field_index < default_values.count) {
|
||||
Operand a = default_values[name_field_index];
|
||||
Operand b = default_values[name_field_index];
|
||||
check_init_variable(c, e, &b, str_lit("struct field assignment"));
|
||||
if (is_operand_nil(a)) {
|
||||
e->Variable.default_is_nil = true;
|
||||
} else if (is_operand_undef(a)) {
|
||||
e->Variable.default_is_undef = true;
|
||||
} else if (b.mode != Addressing_Constant) {
|
||||
error(b.expr, "Default field value must be a constant");
|
||||
} else if (is_type_any(e->type) || is_type_union(e->type)) {
|
||||
gbString str = type_to_string(e->type);
|
||||
error(b.expr, "A struct field of type '%s' cannot have a default value", str);
|
||||
gb_string_free(str);
|
||||
} else {
|
||||
e->Variable.default_value = b.value;
|
||||
}
|
||||
|
||||
name_field_index++;
|
||||
}
|
||||
|
||||
GB_ASSERT(e->type != nullptr);
|
||||
GB_ASSERT(is_type_typed(e->type));
|
||||
|
||||
if (is_blank_ident(name_token)) {
|
||||
array_add(fields, e);
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
Entity **found = map_get(entity_map, key);
|
||||
if (found != nullptr) {
|
||||
Entity *e = *found;
|
||||
// NOTE(bill): Scope checking already checks the declaration but in many cases, this can happen so why not?
|
||||
// This may be a little janky but it's not really that much of a problem
|
||||
error(name_token, "'%.*s' is already declared in this type", LIT(name_token.string));
|
||||
error(e->token, "\tpreviously declared");
|
||||
} else {
|
||||
map_set(entity_map, key, e);
|
||||
array_add(fields, e);
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
}
|
||||
add_entity_use(c, name, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entity *using_index_expr = nullptr;
|
||||
|
||||
if (is_using && fields->count > 0) {
|
||||
Type *first_type = (*fields)[fields->count-1]->type;
|
||||
Type *t = base_type(type_deref(first_type));
|
||||
if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) &&
|
||||
vd->names.count >= 1 &&
|
||||
vd->names[0]->kind == AstNode_Ident) {
|
||||
Token name_token = vd->names[0]->Ident.token;
|
||||
if (is_type_indexable(t)) {
|
||||
bool ok = true;
|
||||
for_array(emi, entity_map->entries) {
|
||||
Entity *e = entity_map->entries[emi].value;
|
||||
if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
|
||||
if (is_type_indexable(e->type)) {
|
||||
if (e->identifier != vd->names[0]) {
|
||||
ok = false;
|
||||
using_index_expr = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
using_index_expr = (*fields)[fields->count-1];
|
||||
} else {
|
||||
(*fields)[fields->count-1]->flags &= ~EntityFlag_Using;
|
||||
error(name_token, "Previous 'using' for an index expression '%.*s'", LIT(name_token.string));
|
||||
}
|
||||
} else {
|
||||
gbString type_str = type_to_string(first_type);
|
||||
error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
|
||||
gb_string_free(type_str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
populate_using_entity_map(c, struct_node, type, entity_map);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns filled field_count
|
||||
Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *> params,
|
||||
isize init_field_capacity, Type *named_type, String context) {
|
||||
@@ -324,6 +109,10 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
|
||||
|
||||
type = default_type(o.type);
|
||||
} else {
|
||||
if (type_expr->kind == AstNode_Ident && type_expr->Ident.token.string == "Element") {
|
||||
gb_printf_err("Element\n");
|
||||
}
|
||||
|
||||
type = check_type(c, type_expr);
|
||||
|
||||
if (default_value != nullptr) {
|
||||
@@ -380,12 +169,6 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
|
||||
}
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_empty_union(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(params[i], "Invalid use of an empty union '%s'", str);
|
||||
gb_string_free(str);
|
||||
type = t_invalid;
|
||||
}
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
|
||||
@@ -408,7 +191,6 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
|
||||
field_src_index += 1;
|
||||
}
|
||||
|
||||
Entity *using_index_expr = nullptr;
|
||||
|
||||
if (is_using && p->names.count > 0) {
|
||||
Type *first_type = fields[fields.count-1]->type;
|
||||
@@ -418,51 +200,22 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
|
||||
p->names.count >= 1 &&
|
||||
p->names[0]->kind == AstNode_Ident) {
|
||||
Token name_token = p->names[0]->Ident.token;
|
||||
if (is_type_indexable(t)) {
|
||||
bool ok = true;
|
||||
for_array(emi, entity_map.entries) {
|
||||
Entity *e = entity_map.entries[emi].value;
|
||||
if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
|
||||
if (is_type_indexable(e->type)) {
|
||||
if (e->identifier != p->names[0]) {
|
||||
ok = false;
|
||||
using_index_expr = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
using_index_expr = fields[fields.count-1];
|
||||
} else {
|
||||
fields[fields.count-1]->flags &= ~EntityFlag_Using;
|
||||
error(name_token, "Previous 'using' for an index expression '%.*s'", LIT(name_token.string));
|
||||
}
|
||||
} else {
|
||||
gbString type_str = type_to_string(first_type);
|
||||
error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
|
||||
gb_string_free(type_str);
|
||||
continue;
|
||||
}
|
||||
gbString type_str = type_to_string(first_type);
|
||||
error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
|
||||
gb_string_free(type_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
populate_using_entity_map(c, node, type, &entity_map);
|
||||
}
|
||||
}
|
||||
|
||||
// for_array(decl_index, params) {
|
||||
// check_struct_field_decl(c, params[decl_index], &fields, &entity_map, node, context, context == "struct");
|
||||
// }
|
||||
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
// TODO(bill): Cleanup struct field reordering
|
||||
// TODO(bill): Inline sorting procedure?
|
||||
gb_global gbAllocator __checker_allocator = {};
|
||||
|
||||
GB_COMPARE_PROC(cmp_reorder_struct_fields) {
|
||||
// Rule:
|
||||
// 'using' over non-'using'
|
||||
@@ -477,10 +230,10 @@ GB_COMPARE_PROC(cmp_reorder_struct_fields) {
|
||||
GB_ASSERT(y->kind == Entity_Variable);
|
||||
bool xu = (x->flags & EntityFlag_Using) != 0;
|
||||
bool yu = (y->flags & EntityFlag_Using) != 0;
|
||||
i64 xa = type_align_of(__checker_allocator, x->type);
|
||||
i64 ya = type_align_of(__checker_allocator, y->type);
|
||||
i64 xs = type_size_of(__checker_allocator, x->type);
|
||||
i64 ys = type_size_of(__checker_allocator, y->type);
|
||||
i64 xa = type_align_of(heap_allocator(), x->type);
|
||||
i64 ya = type_align_of(heap_allocator(), y->type);
|
||||
i64 xs = type_size_of(heap_allocator(), x->type);
|
||||
i64 ys = type_size_of(heap_allocator(), y->type);
|
||||
|
||||
if (xu != yu) {
|
||||
return xu ? -1 : +1;
|
||||
@@ -518,7 +271,7 @@ bool check_custom_align(Checker *c, AstNode *node, i64 *align_) {
|
||||
Type *type = base_type(o.type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o.value.kind == ExactValue_Integer) {
|
||||
i64 align = i128_to_i64(o.value.value_integer);
|
||||
i64 align = o.value.value_integer;
|
||||
if (align < 1 || !gb_is_power_of_two(align)) {
|
||||
error(node, "#align must be a power of 2, got %lld", align);
|
||||
return false;
|
||||
@@ -540,8 +293,10 @@ bool check_custom_align(Checker *c, AstNode *node, i64 *align_) {
|
||||
|
||||
|
||||
Entity *find_polymorphic_struct_entity(Checker *c, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
|
||||
auto *found_gen_types = map_get(&c->info.gen_types, hash_pointer(original_type));
|
||||
gb_mutex_lock(&c->mutex);
|
||||
defer (gb_mutex_unlock(&c->mutex));
|
||||
|
||||
auto *found_gen_types = map_get(&c->info.gen_types, hash_pointer(original_type));
|
||||
if (found_gen_types != nullptr) {
|
||||
for_array(i, *found_gen_types) {
|
||||
Entity *e = (*found_gen_types)[i];
|
||||
@@ -788,7 +543,6 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
|
||||
struct_type->Struct.scope = c->context.scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.is_ordered = st->is_ordered;
|
||||
struct_type->Struct.polymorphic_params = polymorphic_params;
|
||||
struct_type->Struct.is_polymorphic = is_polymorphic;
|
||||
struct_type->Struct.is_poly_specialized = is_poly_specialized;
|
||||
@@ -813,12 +567,15 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// TODO(bill): Move this to the appropriate place
|
||||
if (!struct_type->Struct.is_raw_union) {
|
||||
type_set_offsets(c->allocator, struct_type);
|
||||
|
||||
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
|
||||
struct_type->failure = false;
|
||||
struct_type->Struct.are_offsets_set = false;
|
||||
struct_type->Struct.are_offsets_being_processed = false;
|
||||
gb_zero_item(&struct_type->Struct.offsets);
|
||||
// NOTE(bill): Reorder fields for reduced size/performance
|
||||
|
||||
@@ -830,7 +587,6 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
|
||||
// NOTE(bill): Hacky thing
|
||||
// TODO(bill): Probably make an inline sorting procedure rather than use global variables
|
||||
__checker_allocator = c->allocator;
|
||||
// NOTE(bill): compound literal order must match source not layout
|
||||
gb_sort_array(reordered_fields.data, fields.count, cmp_reorder_struct_fields);
|
||||
|
||||
@@ -843,7 +599,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
|
||||
type_set_offsets(c->allocator, struct_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (st->align != nullptr) {
|
||||
if (st->is_packed) {
|
||||
@@ -937,6 +693,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
|
||||
// NOTE(bill): Must be up here for the 'check_init_constant' system
|
||||
enum_type->Enum.base_type = base_type;
|
||||
enum_type->Enum.scope = c->context.scope;
|
||||
|
||||
Map<Entity *> entity_map = {}; // Key: String
|
||||
map_init(&entity_map, c->tmp_allocator, 2*(et->fields.count));
|
||||
@@ -1039,6 +796,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
|
||||
enum_type->Enum.fields = fields.data;
|
||||
enum_type->Enum.field_count = cast(i32)fields.count;
|
||||
enum_type->Enum.is_export = et->is_export;
|
||||
if (et->is_export) {
|
||||
Scope *parent = c->context.scope->parent;
|
||||
for_array(i, fields) {
|
||||
Entity *f = fields[i];
|
||||
if (f->kind != Entity_Constant) {
|
||||
continue;
|
||||
}
|
||||
String name = f->token.string;
|
||||
if (is_blank_ident(name)) {
|
||||
continue;
|
||||
}
|
||||
add_entity(c, parent, nullptr, f);
|
||||
}
|
||||
}
|
||||
|
||||
enum_type->Enum.count = make_entity_constant(c->allocator, c->context.scope,
|
||||
make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
|
||||
@@ -1090,9 +862,9 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
|
||||
error(value, "Bit field bit size must be a constant integer");
|
||||
continue;
|
||||
}
|
||||
i64 bits = i128_to_i64(v.value_integer);
|
||||
if (bits < 0 || bits > 128) {
|
||||
error(value, "Bit field's bit size must be within the range 1..<128, got %lld", cast(long long)bits);
|
||||
i64 bits = v.value_integer;
|
||||
if (bits < 0 || bits > 64) {
|
||||
error(value, "Bit field's bit size must be within the range 1..<64, got %lld", cast(long long)bits);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1271,8 +1043,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
bool detemine_type_from_operand = false;
|
||||
Type *specialization = nullptr;
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
|
||||
bool is_using = (p->flags&FieldFlag_using) != 0;
|
||||
|
||||
if (type_expr == nullptr) {
|
||||
if (default_value->kind == AstNode_BasicDirective &&
|
||||
@@ -1444,6 +1215,18 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_in) {
|
||||
if (is_type_param) {
|
||||
error(param, "'in' cannot be applied to a type parameter");
|
||||
p->flags &= ~FieldFlag_in;
|
||||
} else if (is_variadic) {
|
||||
error(param, "'in' cannot be applied to a variadic parameter");
|
||||
p->flags &= ~FieldFlag_in;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_in = (p->flags&FieldFlag_in) != 0;
|
||||
|
||||
for_array(j, p->names) {
|
||||
AstNode *name = p->names[j];
|
||||
if (!ast_node_expect(name, AstNode_Ident)) {
|
||||
@@ -1507,7 +1290,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
}
|
||||
|
||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type, is_using, false);
|
||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type, is_using, is_in);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
param->Variable.default_is_location = default_is_location;
|
||||
@@ -1655,10 +1438,16 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
token = name->Ident.token;
|
||||
}
|
||||
|
||||
if (is_blank_ident(token)) {
|
||||
error(name, "Result value cannot be a blank identifer `_`");
|
||||
}
|
||||
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
param->flags |= EntityFlag_Result;
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
array_add(&variables, param);
|
||||
add_entity(c, scope, name, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1687,6 +1476,10 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
||||
Type *new_type = original_type;
|
||||
|
||||
if (is_type_boolean(original_type)) {
|
||||
return t_llvm_bool;
|
||||
}
|
||||
|
||||
if (build_context.ODIN_ARCH == "x86") {
|
||||
return new_type;
|
||||
}
|
||||
@@ -1701,7 +1494,8 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
||||
// Especially the only Odin types
|
||||
case Type_Basic: {
|
||||
i64 sz = bt->Basic.size;
|
||||
if (sz > 8 && build_context.word_size < 8) {
|
||||
// if (sz > 8 && build_context.word_size < 8) {
|
||||
if (sz > 8) {
|
||||
new_type = make_type_pointer(a, original_type);
|
||||
}
|
||||
break;
|
||||
@@ -1709,17 +1503,15 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
||||
case Type_Pointer: break;
|
||||
case Type_Proc: break; // NOTE(bill): Just a pointer
|
||||
|
||||
// Odin only types
|
||||
// Odin specific
|
||||
case Type_Slice:
|
||||
case Type_Array:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
break;
|
||||
|
||||
// Odin specific
|
||||
case Type_Array:
|
||||
case Type_Vector:
|
||||
case Type_Union:
|
||||
// Could be in C too
|
||||
case Type_Struct: {
|
||||
case Type_Struct:
|
||||
{
|
||||
i64 align = type_align_of(a, original_type);
|
||||
i64 size = type_size_of(a, original_type);
|
||||
switch (8*size) {
|
||||
@@ -1743,7 +1535,8 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
||||
// Especially the only Odin types
|
||||
case Type_Basic: {
|
||||
i64 sz = bt->Basic.size;
|
||||
if (sz > 8 && build_context.word_size < 8) {
|
||||
// if (sz > 8 && build_context.word_size < 8) {
|
||||
if (sz > 8) {
|
||||
new_type = make_type_pointer(a, original_type);
|
||||
}
|
||||
|
||||
@@ -1752,15 +1545,12 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
||||
case Type_Pointer: break;
|
||||
case Type_Proc: break; // NOTE(bill): Just a pointer
|
||||
|
||||
// Odin only types
|
||||
// Odin specific
|
||||
case Type_Slice:
|
||||
case Type_Array:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
break;
|
||||
|
||||
// Odin specific
|
||||
case Type_Array:
|
||||
case Type_Vector:
|
||||
case Type_Union:
|
||||
// Could be in C too
|
||||
case Type_Struct: {
|
||||
i64 align = type_align_of(a, original_type);
|
||||
@@ -1881,6 +1671,10 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
||||
c->context.polymorphic_scope = c->context.scope;
|
||||
}
|
||||
|
||||
CheckerContext prev = c->context;
|
||||
defer (c->context = prev);
|
||||
c->context.curr_proc_sig = type;
|
||||
|
||||
bool variadic = false;
|
||||
isize variadic_index = -1;
|
||||
bool success = true;
|
||||
@@ -1904,6 +1698,12 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
|
||||
}
|
||||
}
|
||||
|
||||
if (result_count > 0) {
|
||||
Entity *first = results->Tuple.variables[0];
|
||||
type->Proc.has_named_results = first->token.string != "";
|
||||
}
|
||||
|
||||
|
||||
ProcCallingConvention cc = pt->calling_convention;
|
||||
if (cc == ProcCC_ForeignBlockDefault) {
|
||||
cc = ProcCC_CDecl;
|
||||
@@ -1998,7 +1798,7 @@ i64 check_array_count(Checker *c, Operand *o, AstNode *e) {
|
||||
Type *type = base_type(o->type);
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o->value.kind == ExactValue_Integer) {
|
||||
i64 count = i128_to_i64(o->value.value_integer);
|
||||
i64 count = o->value.value_integer;
|
||||
if (count >= 0) {
|
||||
return count;
|
||||
}
|
||||
@@ -2049,7 +1849,6 @@ void generate_map_entry_type(gbAllocator a, Type *type) {
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("value")), type->Map.value, false, 2));
|
||||
|
||||
|
||||
entry_type->Struct.is_ordered = true;
|
||||
entry_type->Struct.fields = fields;
|
||||
entry_type->Struct.fields_in_src_order = fields;
|
||||
|
||||
@@ -2060,7 +1859,9 @@ void generate_map_entry_type(gbAllocator a, Type *type) {
|
||||
void generate_map_internal_types(gbAllocator a, Type *type) {
|
||||
GB_ASSERT(type->kind == Type_Map);
|
||||
generate_map_entry_type(a, type);
|
||||
if (type->Map.internal_type != nullptr) return;
|
||||
if (type->Map.generated_struct_type != nullptr) return;
|
||||
|
||||
Type *key = type->Map.key;
|
||||
Type *value = type->Map.value;
|
||||
GB_ASSERT(key != nullptr);
|
||||
@@ -2087,13 +1888,13 @@ void generate_map_internal_types(gbAllocator a, Type *type) {
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("hashes")), hashes_type, false, 0));
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("entries")), entries_type, false, 1));
|
||||
|
||||
generated_struct_type->Struct.is_ordered = true;
|
||||
generated_struct_type->Struct.fields = fields;
|
||||
generated_struct_type->Struct.fields_in_src_order = fields;
|
||||
|
||||
type_set_offsets(a, generated_struct_type);
|
||||
type->Map.generated_struct_type = generated_struct_type;
|
||||
type->Map.lookup_result_type = make_optional_ok_type(a, value);
|
||||
type->Map.internal_type = generated_struct_type;
|
||||
type->Map.lookup_result_type = make_optional_ok_type(a, value);
|
||||
}
|
||||
|
||||
void check_map_type(Checker *c, Type *type, AstNode *node) {
|
||||
@@ -2162,10 +1963,10 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
return check_type_internal(c, ht->type, type, named_type);
|
||||
case_end;
|
||||
|
||||
case_ast_node(at, AliasType, e);
|
||||
error(e, "Invalid use of '#alias'");
|
||||
case_ast_node(dt, DistinctType, e);
|
||||
error(e, "Invalid use of a distinct type");
|
||||
// NOTE(bill): Treat it as a HelperType to remove errors
|
||||
return check_type_internal(c, at->type, type, named_type);
|
||||
return check_type_internal(c, dt->type, type, named_type);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, PolyType, e);
|
||||
@@ -2207,6 +2008,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
return false;
|
||||
}
|
||||
*type = t;
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
@@ -2237,23 +2039,22 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
|
||||
case_ast_node(pe, ParenExpr, e);
|
||||
*type = check_type(c, pe->expr, named_type);
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ue, UnaryExpr, e);
|
||||
if (ue->op.kind == Token_Pointer) {
|
||||
switch (ue->op.kind) {
|
||||
case Token_Pointer:
|
||||
*type = make_type_pointer(c->allocator, check_type(c, ue->expr));
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
} /* else if (ue->op.kind == Token_Maybe) {
|
||||
*type = make_type_maybe(c->allocator, check_type(c, ue->expr));
|
||||
return true;
|
||||
} */
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, PointerType, e);
|
||||
Type *elem = check_type(c, pt->type);
|
||||
i64 esz = type_size_of(c->allocator, elem);
|
||||
*type = make_type_pointer(c->allocator, elem);
|
||||
*type = make_type_pointer(c->allocator, check_type(c, pt->type));
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
@@ -2275,37 +2076,14 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
Type *elem = check_type(c, at->elem);
|
||||
*type = make_type_slice(c->allocator, elem);
|
||||
}
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
case_ast_node(dat, DynamicArrayType, e);
|
||||
Type *elem = check_type(c, dat->elem);
|
||||
*type = make_type_dynamic_array(c->allocator, elem);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
|
||||
|
||||
case_ast_node(vt, VectorType, e);
|
||||
|
||||
Operand o = {};
|
||||
i64 count = check_array_count(c, &o, vt->count);
|
||||
Type *generic_type = nullptr;
|
||||
if (o.mode == Addressing_Type && o.type->kind == Type_Generic) {
|
||||
generic_type = o.type;
|
||||
}
|
||||
if (count < 0) {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
Type *elem = check_type(c, vt->elem);
|
||||
Type *be = base_type(elem);
|
||||
if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be) && be->kind != Type_Generic)) {
|
||||
gbString err_str = type_to_string(elem);
|
||||
error(vt->elem, "Vector element type must be numerical or a boolean, got '%s'", err_str);
|
||||
gb_string_free(err_str);
|
||||
}
|
||||
*type = make_type_vector(c->allocator, elem, count, generic_type);
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
|
||||
@@ -2369,6 +2147,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
check_expr_or_type(c, &o, e);
|
||||
if (o.mode == Addressing_Type) {
|
||||
*type = o.type;
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
@@ -2378,6 +2157,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
check_expr_or_type(c, &o, e);
|
||||
if (o.mode == Addressing_Type) {
|
||||
*type = o.type;
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
|
||||
+335
-703
File diff suppressed because it is too large
Load Diff
+405
@@ -0,0 +1,405 @@
|
||||
// checker.hpp
|
||||
|
||||
struct Type;
|
||||
struct Entity;
|
||||
struct Scope;
|
||||
struct DeclInfo;
|
||||
struct AstFile;
|
||||
|
||||
enum AddressingMode {
|
||||
Addressing_Invalid, // invalid addressing mode
|
||||
Addressing_NoValue, // no value (void in C)
|
||||
Addressing_Value, // computed value (rvalue)
|
||||
Addressing_Immutable, // immutable computed value (const rvalue)
|
||||
Addressing_Variable, // addressable variable (lvalue)
|
||||
Addressing_Constant, // constant
|
||||
Addressing_Type, // type
|
||||
Addressing_Builtin, // built-in procedure
|
||||
Addressing_ProcGroup, // procedure group (overloaded procedure)
|
||||
Addressing_MapIndex, // map index expression -
|
||||
// lhs: acts like a Variable
|
||||
// rhs: acts like OptionalOk
|
||||
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||
};
|
||||
|
||||
struct TypeAndValue {
|
||||
AddressingMode mode;
|
||||
Type * type;
|
||||
ExactValue value;
|
||||
};
|
||||
|
||||
|
||||
// ExprInfo stores information used for "untyped" expressions
|
||||
struct ExprInfo {
|
||||
AddressingMode mode;
|
||||
Type * type; // Type_Basic
|
||||
ExactValue value;
|
||||
bool is_lhs; // Debug info
|
||||
};
|
||||
|
||||
gb_inline ExprInfo make_expr_info(AddressingMode mode, Type *type, ExactValue value, bool is_lhs) {
|
||||
ExprInfo ei = {};
|
||||
ei.is_lhs = is_lhs;
|
||||
ei.mode = mode;
|
||||
ei.type = type;
|
||||
ei.value = value;
|
||||
return ei;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
enum ExprKind {
|
||||
Expr_Expr,
|
||||
Expr_Stmt,
|
||||
};
|
||||
|
||||
// Statements and Declarations
|
||||
enum StmtFlag {
|
||||
Stmt_BreakAllowed = 1<<0,
|
||||
Stmt_ContinueAllowed = 1<<1,
|
||||
Stmt_FallthroughAllowed = 1<<2,
|
||||
|
||||
Stmt_CheckScopeDecls = 1<<5,
|
||||
};
|
||||
|
||||
struct BuiltinProc {
|
||||
String name;
|
||||
isize arg_count;
|
||||
bool variadic;
|
||||
ExprKind kind;
|
||||
};
|
||||
enum BuiltinProcId {
|
||||
BuiltinProc_Invalid,
|
||||
|
||||
BuiltinProc_len,
|
||||
BuiltinProc_cap,
|
||||
|
||||
// BuiltinProc_new,
|
||||
BuiltinProc_make,
|
||||
// BuiltinProc_free,
|
||||
|
||||
// BuiltinProc_reserve,
|
||||
// BuiltinProc_clear,
|
||||
// BuiltinProc_append,
|
||||
// BuiltinProc_delete,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_align_of,
|
||||
BuiltinProc_offset_of,
|
||||
BuiltinProc_type_of,
|
||||
BuiltinProc_type_info_of,
|
||||
|
||||
BuiltinProc_compile_assert,
|
||||
|
||||
BuiltinProc_swizzle,
|
||||
|
||||
BuiltinProc_complex,
|
||||
BuiltinProc_real,
|
||||
BuiltinProc_imag,
|
||||
BuiltinProc_conj,
|
||||
|
||||
// BuiltinProc_slice_ptr,
|
||||
// BuiltinProc_slice_to_bytes,
|
||||
|
||||
BuiltinProc_expand_to_tuple,
|
||||
|
||||
BuiltinProc_min,
|
||||
BuiltinProc_max,
|
||||
BuiltinProc_abs,
|
||||
BuiltinProc_clamp,
|
||||
|
||||
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
||||
|
||||
BuiltinProc_COUNT,
|
||||
};
|
||||
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT(""), 0, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("len"), 1, false, Expr_Expr},
|
||||
{STR_LIT("cap"), 1, false, Expr_Expr},
|
||||
|
||||
// {STR_LIT("new"), 1, false, Expr_Expr},
|
||||
{STR_LIT("make"), 1, true, Expr_Expr},
|
||||
// {STR_LIT("free"), 1, false, Expr_Stmt},
|
||||
|
||||
// {STR_LIT("reserve"), 2, false, Expr_Stmt},
|
||||
// {STR_LIT("clear"), 1, false, Expr_Stmt},
|
||||
// {STR_LIT("append"), 1, true, Expr_Expr},
|
||||
// {STR_LIT("delete"), 2, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("align_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("offset_of"), 2, false, Expr_Expr},
|
||||
{STR_LIT("type_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("type_info_of"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("compile_assert"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("swizzle"), 1, true, Expr_Expr},
|
||||
|
||||
{STR_LIT("complex"), 2, false, Expr_Expr},
|
||||
{STR_LIT("real"), 1, false, Expr_Expr},
|
||||
{STR_LIT("imag"), 1, false, Expr_Expr},
|
||||
{STR_LIT("conj"), 1, false, Expr_Expr},
|
||||
|
||||
// {STR_LIT("slice_ptr"), 2, true, Expr_Expr},
|
||||
// {STR_LIT("slice_to_bytes"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("min"), 2, false, Expr_Expr},
|
||||
{STR_LIT("max"), 2, false, Expr_Expr},
|
||||
{STR_LIT("abs"), 1, false, Expr_Expr},
|
||||
{STR_LIT("clamp"), 3, false, Expr_Expr},
|
||||
|
||||
{STR_LIT(""), 0, true, Expr_Expr}, // DIRECTIVE
|
||||
};
|
||||
|
||||
|
||||
// Operand is used as an intermediate value whilst checking
|
||||
// Operands store an addressing mode, the expression being evaluated,
|
||||
// its type and node, and other specific information for certain
|
||||
// addressing modes
|
||||
// Its zero-value is a valid "invalid operand"
|
||||
struct Operand {
|
||||
AddressingMode mode;
|
||||
Type * type;
|
||||
ExactValue value;
|
||||
AstNode * expr;
|
||||
BuiltinProcId builtin_id;
|
||||
Entity * proc_group;
|
||||
};
|
||||
|
||||
|
||||
struct BlockLabel {
|
||||
String name;
|
||||
AstNode *label; // AstNode_Label;
|
||||
};
|
||||
|
||||
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
||||
struct DeclInfo {
|
||||
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
|
||||
Scope * scope;
|
||||
|
||||
Entity ** entities;
|
||||
isize entity_count;
|
||||
|
||||
AstNode * type_expr;
|
||||
AstNode * init_expr;
|
||||
Array<AstNode *> init_expr_list;
|
||||
Array<AstNode *> attributes;
|
||||
AstNode * proc_lit; // AstNode_ProcLit
|
||||
Type * gen_proc_type; // Precalculated
|
||||
|
||||
PtrSet<Entity *> deps;
|
||||
Array<BlockLabel> labels;
|
||||
};
|
||||
|
||||
// ProcedureInfo stores the information needed for checking a procedure
|
||||
|
||||
|
||||
struct ProcedureInfo {
|
||||
AstFile * file;
|
||||
Token token;
|
||||
DeclInfo * decl;
|
||||
Type * type; // Type_Procedure
|
||||
AstNode * body; // AstNode_BlockStmt
|
||||
u64 tags;
|
||||
bool generated_from_polymorphic;
|
||||
};
|
||||
|
||||
|
||||
struct Scope {
|
||||
AstNode * node;
|
||||
Scope * parent;
|
||||
Scope * prev, *next;
|
||||
Scope * first_child;
|
||||
Scope * last_child;
|
||||
Map<Entity *> elements; // Key: String
|
||||
PtrSet<Entity *> implicit;
|
||||
|
||||
Array<Scope *> shared;
|
||||
Array<AstNode *> delayed_file_decls;
|
||||
PtrSet<Scope *> imported;
|
||||
PtrSet<Scope *> exported; // NOTE(bhall): Contains 'using import' too
|
||||
bool is_proc;
|
||||
bool is_global;
|
||||
bool is_file;
|
||||
bool is_init;
|
||||
bool is_struct;
|
||||
bool has_been_imported; // This is only applicable to file scopes
|
||||
AstFile * file;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct EntityGraphNode;
|
||||
typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet;
|
||||
|
||||
struct EntityGraphNode {
|
||||
Entity * entity; // Procedure, Variable, Constant
|
||||
EntityGraphNodeSet pred;
|
||||
EntityGraphNodeSet succ;
|
||||
isize index; // Index in array/queue
|
||||
isize dep_count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct ImportGraphNode;
|
||||
typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
|
||||
|
||||
|
||||
struct ImportGraphNode {
|
||||
Scope * scope;
|
||||
String path;
|
||||
isize file_id;
|
||||
ImportGraphNodeSet pred;
|
||||
ImportGraphNodeSet succ;
|
||||
isize index; // Index in array/queue
|
||||
isize dep_count;
|
||||
};
|
||||
|
||||
|
||||
struct ForeignContext {
|
||||
AstNode * curr_library;
|
||||
ProcCallingConvention default_cc;
|
||||
String link_prefix;
|
||||
bool in_export;
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
Scope * file_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;
|
||||
|
||||
bool collect_delayed_decls;
|
||||
bool allow_polymorphic_types;
|
||||
bool no_polymorphic_errors;
|
||||
Scope * polymorphic_scope;
|
||||
};
|
||||
|
||||
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
struct CheckerInfo {
|
||||
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
||||
Map<ExprInfo> untyped; // Key: AstNode * | Expression -> ExprInfo
|
||||
Map<AstFile *> files; // Key: String (full path)
|
||||
Map<Entity *> foreigns; // Key: String
|
||||
Array<Entity *> definitions;
|
||||
Array<Entity *> entities;
|
||||
Array<DeclInfo *> variable_init_order;
|
||||
|
||||
Map<Array<Entity *> > gen_procs; // Key: AstNode * | Identifier -> Entity
|
||||
Map<Array<Entity *> > gen_types; // Key: Type *
|
||||
|
||||
Array<Type *> type_info_types;
|
||||
Map<isize> type_info_map; // Key: Type *
|
||||
|
||||
Scope * init_scope;
|
||||
Entity * entry_point;
|
||||
PtrSet<Entity *> minimum_dependency_set;
|
||||
};
|
||||
|
||||
struct Checker {
|
||||
Parser * parser;
|
||||
CheckerInfo info;
|
||||
gbMutex mutex;
|
||||
|
||||
AstFile * curr_ast_file;
|
||||
Scope * global_scope;
|
||||
// NOTE(bill): Procedures to check
|
||||
Array<ProcedureInfo> procs;
|
||||
Map<Scope *> file_scopes; // Key: String (fullpath)
|
||||
Array<ImportGraphNode *> file_order;
|
||||
|
||||
gbAllocator allocator;
|
||||
gbArena arena;
|
||||
gbArena tmp_arena;
|
||||
gbAllocator tmp_allocator;
|
||||
|
||||
CheckerContext context;
|
||||
|
||||
Array<Type *> proc_stack;
|
||||
bool done_preload;
|
||||
|
||||
PtrSet<AstFile *> checked_files;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
HashKey hash_node (AstNode *node) { return hash_pointer(node); }
|
||||
HashKey hash_ast_file (AstFile *file) { return hash_pointer(file); }
|
||||
HashKey hash_entity (Entity *e) { return hash_pointer(e); }
|
||||
HashKey hash_type (Type *t) { return hash_pointer(t); }
|
||||
HashKey hash_decl_info(DeclInfo *decl) { return hash_pointer(decl); }
|
||||
|
||||
|
||||
|
||||
// CheckerInfo API
|
||||
TypeAndValue type_and_value_of_expr (CheckerInfo *i, AstNode *expr);
|
||||
Type * type_of_expr (CheckerInfo *i, AstNode *expr);
|
||||
Entity * entity_of_ident (CheckerInfo *i, AstNode *identifier);
|
||||
Entity * implicit_entity_of_node(CheckerInfo *i, AstNode *clause);
|
||||
Scope * scope_of_node (CheckerInfo *i, AstNode *node);
|
||||
DeclInfo * decl_info_of_ident (CheckerInfo *i, AstNode *ident);
|
||||
DeclInfo * decl_info_of_entity (CheckerInfo *i, Entity * e);
|
||||
AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
||||
// IMPORTANT: Only to use once checking is done
|
||||
isize type_info_index (CheckerInfo *i, Type * type, bool error_on_failure = true);
|
||||
|
||||
|
||||
Entity *current_scope_lookup_entity(Scope *s, String name);
|
||||
Entity *scope_lookup_entity (Scope *s, String name);
|
||||
void scope_lookup_parent_entity (Scope *s, String name, Scope **scope_, Entity **entity_);
|
||||
Entity *scope_insert_entity (Scope *s, Entity *entity);
|
||||
|
||||
|
||||
ExprInfo *check_get_expr_info (CheckerInfo *i, AstNode *expr);
|
||||
void check_set_expr_info (CheckerInfo *i, AstNode *expr, ExprInfo info);
|
||||
void check_remove_expr_info (CheckerInfo *i, AstNode *expr);
|
||||
void add_untyped (CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value);
|
||||
void add_type_and_value (CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value);
|
||||
void add_entity_use (Checker *c, AstNode *identifier, Entity *entity);
|
||||
void add_implicit_entity (Checker *c, AstNode *node, Entity *e);
|
||||
void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d);
|
||||
|
||||
void check_add_import_decl(Checker *c, AstNodeImportDecl *id);
|
||||
void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
|
||||
void check_add_foreign_import_decl(Checker *c, AstNode *decl);
|
||||
|
||||
|
||||
|
||||
bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global = false);
|
||||
void check_collect_entities(Checker *c, Array<AstNode *> nodes);
|
||||
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
|
||||
void check_delayed_file_import_entity(Checker *c, AstNode *decl);
|
||||
|
||||
|
||||
struct AttributeContext {
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
isize init_expr_list_count;
|
||||
String thread_local_model;
|
||||
};
|
||||
|
||||
AttributeContext make_attribute_context(String link_prefix) {
|
||||
AttributeContext ac = {};
|
||||
ac.link_prefix = link_prefix;
|
||||
return ac;
|
||||
}
|
||||
|
||||
#define DECL_ATTRIBUTE_PROC(_name) bool _name(Checker *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
|
||||
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
|
||||
|
||||
void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
|
||||
+130
-7
@@ -12,6 +12,21 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
gb_inline i64 align_formula(i64 size, i64 align) {
|
||||
if (align > 0) {
|
||||
i64 result = size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
gb_inline isize align_formula_isize(isize size, isize align) {
|
||||
if (align > 0) {
|
||||
isize result = size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc);
|
||||
|
||||
gbAllocator heap_allocator(void) {
|
||||
@@ -26,13 +41,18 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
void *ptr = NULL;
|
||||
gb_unused(allocator_data);
|
||||
gb_unused(old_size);
|
||||
|
||||
|
||||
|
||||
// TODO(bill): Throughly test!
|
||||
switch (type) {
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
#if 0
|
||||
case gbAllocation_Alloc:
|
||||
ptr = _aligned_malloc(size, alignment);
|
||||
if (flags & gbAllocatorFlag_ClearToZero)
|
||||
if (flags & gbAllocatorFlag_ClearToZero) {
|
||||
gb_zero_size(ptr, size);
|
||||
}
|
||||
break;
|
||||
case gbAllocation_Free:
|
||||
_aligned_free(old_memory);
|
||||
@@ -40,6 +60,18 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
case gbAllocation_Resize:
|
||||
ptr = _aligned_realloc(old_memory, size, alignment);
|
||||
break;
|
||||
#else
|
||||
case gbAllocation_Alloc:
|
||||
// TODO(bill): Make sure this is aligned correctly
|
||||
ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, align_formula_isize(size, alignment));
|
||||
break;
|
||||
case gbAllocation_Free:
|
||||
HeapFree(GetProcessHeap(), 0, old_memory);
|
||||
break;
|
||||
case gbAllocation_Resize:
|
||||
ptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, old_memory, align_formula_isize(size, alignment));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#elif defined(GB_SYSTEM_LINUX)
|
||||
// TODO(bill): *nix version that's decent
|
||||
@@ -95,23 +127,114 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
#include "unicode.cpp"
|
||||
#include "string.cpp"
|
||||
#include "array.cpp"
|
||||
#include "integer128.cpp"
|
||||
#include "murmurhash3.cpp"
|
||||
|
||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||
|
||||
|
||||
u128 fnv128a(void const *data, isize len) {
|
||||
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
|
||||
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
|
||||
u64 fnv64a(void const *data, isize len) {
|
||||
u8 const *bytes = cast(u8 const *)data;
|
||||
u64 h = 0xcbf29ce484222325ull;
|
||||
for (isize i = 0; i < len; i++) {
|
||||
h.lo ^= bytes[i];
|
||||
h = h * o;
|
||||
u64 b = cast(u64)bytes[i];
|
||||
h = (h ^ b) * 0x100000001b3ull;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
u64 u64_digit_value(Rune r) {
|
||||
if ('0' <= r && r <= '9') {
|
||||
return r - '0';
|
||||
} else if ('a' <= r && r <= 'f') {
|
||||
return r - 'a' + 10;
|
||||
} else if ('A' <= r && r <= 'F') {
|
||||
return r - 'A' + 10;
|
||||
}
|
||||
return 16; // NOTE(bill): Larger than highest possible
|
||||
}
|
||||
|
||||
|
||||
u64 u64_from_string(String string) {
|
||||
u64 base = 10;
|
||||
bool has_prefix = false;
|
||||
if (string.len > 2 && string[0] == '0') {
|
||||
switch (string[1]) {
|
||||
case 'b': base = 2; has_prefix = true; break;
|
||||
case 'o': base = 8; has_prefix = true; break;
|
||||
case 'd': base = 10; has_prefix = true; break;
|
||||
case 'z': base = 12; has_prefix = true; break;
|
||||
case 'x': base = 16; has_prefix = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *text = string.text;
|
||||
isize len = string.len;
|
||||
if (has_prefix) {
|
||||
text += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
u64 result = 0ull;
|
||||
for (isize i = 0; i < len; i++) {
|
||||
Rune r = cast(Rune)text[i];
|
||||
if (r == '_') {
|
||||
continue;
|
||||
}
|
||||
u64 v = u64_digit_value(r);
|
||||
if (v >= base) {
|
||||
break;
|
||||
}
|
||||
result *= base;
|
||||
result += v;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||
char buf[200] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
|
||||
u64 b = 10;
|
||||
while (v >= b) {
|
||||
buf[--i] = gb__num_to_char_table[v%b];
|
||||
v /= b;
|
||||
}
|
||||
buf[--i] = gb__num_to_char_table[v%b];
|
||||
|
||||
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
|
||||
gb_memcopy(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||
char buf[200] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
bool negative = false;
|
||||
if (a < 0) {
|
||||
negative = true;
|
||||
a = -a;
|
||||
}
|
||||
|
||||
u64 v = cast(u64)a;
|
||||
u64 b = 10;
|
||||
while (v >= b) {
|
||||
buf[--i] = gb__num_to_char_table[v%b];
|
||||
v /= b;
|
||||
}
|
||||
buf[--i] = gb__num_to_char_table[v%b];
|
||||
|
||||
if (negative) {
|
||||
buf[--i] = '-';
|
||||
}
|
||||
|
||||
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
|
||||
gb_memcopy(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "map.cpp"
|
||||
#include "ptr_set.cpp"
|
||||
#include "string_set.cpp"
|
||||
|
||||
+37
-21
@@ -10,6 +10,7 @@ struct DeclInfo;
|
||||
ENTITY_KIND(Variable) \
|
||||
ENTITY_KIND(TypeName) \
|
||||
ENTITY_KIND(Procedure) \
|
||||
ENTITY_KIND(ProcGroup) \
|
||||
ENTITY_KIND(Builtin) \
|
||||
ENTITY_KIND(Alias) \
|
||||
ENTITY_KIND(ImportName) \
|
||||
@@ -36,14 +37,15 @@ enum EntityFlag {
|
||||
EntityFlag_Using = 1<<2,
|
||||
EntityFlag_Field = 1<<3,
|
||||
EntityFlag_Param = 1<<4,
|
||||
EntityFlag_VectorElem = 1<<5,
|
||||
EntityFlag_Ellipsis = 1<<6,
|
||||
EntityFlag_NoAlias = 1<<7,
|
||||
EntityFlag_TypeField = 1<<8,
|
||||
EntityFlag_Value = 1<<9,
|
||||
EntityFlag_Sret = 1<<10,
|
||||
EntityFlag_BitFieldValue = 1<<11,
|
||||
EntityFlag_PolyConst = 1<<12,
|
||||
EntityFlag_Result = 1<<5,
|
||||
EntityFlag_ArrayElem = 1<<6,
|
||||
EntityFlag_Ellipsis = 1<<7,
|
||||
EntityFlag_NoAlias = 1<<8,
|
||||
EntityFlag_TypeField = 1<<9,
|
||||
EntityFlag_Value = 1<<10,
|
||||
EntityFlag_Sret = 1<<11,
|
||||
EntityFlag_BitFieldValue = 1<<12,
|
||||
EntityFlag_PolyConst = 1<<13,
|
||||
|
||||
EntityFlag_CVarArg = 1<<20,
|
||||
};
|
||||
@@ -65,6 +67,7 @@ struct Entity {
|
||||
Scope * scope;
|
||||
Type * type;
|
||||
AstNode * identifier; // Can be nullptr
|
||||
DeclInfo * decl_info;
|
||||
DeclInfo * parent_proc_decl; // nullptr if in file/global scope
|
||||
|
||||
// TODO(bill): Cleanup how `using` works for entities
|
||||
@@ -81,21 +84,22 @@ struct Entity {
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
ExactValue default_value;
|
||||
bool default_is_nil;
|
||||
bool default_is_undef;
|
||||
bool default_is_location;
|
||||
bool is_immutable;
|
||||
String thread_local_model;
|
||||
bool is_foreign;
|
||||
bool is_export;
|
||||
Entity * foreign_library;
|
||||
AstNode * foreign_library_ident;
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
String thread_local_model;
|
||||
bool default_is_nil;
|
||||
bool default_is_undef;
|
||||
bool default_is_location;
|
||||
bool is_immutable;
|
||||
bool is_foreign;
|
||||
bool is_export;
|
||||
} Variable;
|
||||
struct {
|
||||
bool is_type_alias;
|
||||
Type *type_parameter_specialization;
|
||||
bool is_type_alias;
|
||||
Type * type_parameter_specialization;
|
||||
String ir_mangled_name;
|
||||
} TypeName;
|
||||
struct {
|
||||
OverloadKind overload_kind;
|
||||
@@ -107,6 +111,9 @@ struct Entity {
|
||||
Entity * foreign_library;
|
||||
AstNode * foreign_library_ident;
|
||||
} Procedure;
|
||||
struct {
|
||||
Array<Entity *> entities;
|
||||
} ProcGroup;
|
||||
struct {
|
||||
i32 id;
|
||||
} Builtin;
|
||||
@@ -185,6 +192,7 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
|
||||
entity->using_parent = parent;
|
||||
entity->parent_proc_decl = parent->parent_proc_decl;
|
||||
entity->flags |= EntityFlag_Using;
|
||||
entity->flags |= EntityFlag_Used;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -200,11 +208,13 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_immutable) {
|
||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
|
||||
bool is_immutable = false;
|
||||
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
if (is_using) entity->flags |= EntityFlag_Using;
|
||||
entity->flags |= EntityFlag_Param;
|
||||
if (is_using) entity->flags |= EntityFlag_Using;
|
||||
if (is_value) entity->flags |= EntityFlag_Value;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -227,12 +237,12 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_vector_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
||||
Entity *make_entity_array_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||
entity->Variable.field_src_index = field_src_index;
|
||||
entity->Variable.field_index = field_src_index;
|
||||
entity->flags |= EntityFlag_Field;
|
||||
entity->flags |= EntityFlag_VectorElem;
|
||||
entity->flags |= EntityFlag_ArrayElem;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -242,6 +252,12 @@ Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *si
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_proc_group(gbAllocator a, Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = alloc_entity(a, Entity_ProcGroup, scope, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
|
||||
entity->Builtin.id = id;
|
||||
|
||||
+27
-32
@@ -33,7 +33,7 @@ struct ExactValue {
|
||||
union {
|
||||
bool value_bool;
|
||||
String value_string;
|
||||
i128 value_integer; // NOTE(bill): This must be an integer and not a pointer
|
||||
i64 value_integer; // NOTE(bill): This must be an integer and not a pointer
|
||||
f64 value_float;
|
||||
i64 value_pointer;
|
||||
Complex128 value_complex;
|
||||
@@ -70,19 +70,14 @@ ExactValue exact_value_string(String string) {
|
||||
}
|
||||
|
||||
ExactValue exact_value_i64(i64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
result.value_integer = i128_from_i64(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_i128(i128 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
result.value_integer = i;
|
||||
return result;
|
||||
}
|
||||
ExactValue exact_value_u128(u128 i) {
|
||||
|
||||
ExactValue exact_value_u64(u64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
result.value_integer = u128_to_i128(i);
|
||||
result.value_integer = i64(i);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -119,7 +114,8 @@ ExactValue exact_value_procedure(AstNode *node) {
|
||||
|
||||
|
||||
ExactValue exact_value_integer_from_string(String string) {
|
||||
return exact_value_u128(u128_from_string(string));
|
||||
u64 u = u64_from_string(string);
|
||||
return exact_value_u64(u);
|
||||
}
|
||||
|
||||
f64 float_from_string(String string) {
|
||||
@@ -273,10 +269,10 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
||||
case ExactValue_Integer:
|
||||
return v;
|
||||
case ExactValue_Float: {
|
||||
i128 i = i128_from_f64(v.value_float);
|
||||
f64 f = i128_to_f64(i);
|
||||
i64 i = cast(i64)v.value_float;
|
||||
f64 f = cast(f64)i;
|
||||
if (f == v.value_float) {
|
||||
return exact_value_i128(i);
|
||||
return exact_value_i64(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -291,7 +287,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
||||
ExactValue exact_value_to_float(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_float(i128_to_f64(v.value_integer));
|
||||
return exact_value_float(cast(f64)v.value_integer);
|
||||
case ExactValue_Float:
|
||||
return v;
|
||||
}
|
||||
@@ -302,7 +298,7 @@ ExactValue exact_value_to_float(ExactValue v) {
|
||||
ExactValue exact_value_to_complex(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_complex(i128_to_f64(v.value_integer), 0);
|
||||
return exact_value_complex(cast(f64)v.value_integer, 0);
|
||||
case ExactValue_Float:
|
||||
return exact_value_complex(v.value_float, 0);
|
||||
case ExactValue_Complex:
|
||||
@@ -388,7 +384,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
}
|
||||
|
||||
case Token_Xor: {
|
||||
i128 i = I128_ZERO;
|
||||
i64 i = 0;
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid:
|
||||
return v;
|
||||
@@ -402,12 +398,11 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
||||
// NOTE(bill): unsigned integers will be negative and will need to be
|
||||
// limited to the types precision
|
||||
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
|
||||
if (0 < precision && precision < 128) {
|
||||
i = i & ~(I128_NEG_ONE << precision);
|
||||
if (0 < precision && precision < 64) {
|
||||
i = i & ~(-1ll << precision);
|
||||
}
|
||||
|
||||
return exact_value_i128(i);
|
||||
break;
|
||||
return exact_value_i64(i);
|
||||
}
|
||||
|
||||
case Token_Not: {
|
||||
@@ -472,10 +467,10 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
return;
|
||||
case ExactValue_Float:
|
||||
// TODO(bill): Is this good enough?
|
||||
*x = exact_value_float(i128_to_f64(x->value_integer));
|
||||
*x = exact_value_float(cast(f64)x->value_integer);
|
||||
return;
|
||||
case ExactValue_Complex:
|
||||
*x = exact_value_complex(i128_to_f64(x->value_integer), 0);
|
||||
*x = exact_value_complex(cast(f64)x->value_integer, 0);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -513,27 +508,27 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
break;
|
||||
|
||||
case ExactValue_Integer: {
|
||||
i128 a = x.value_integer;
|
||||
i128 b = y.value_integer;
|
||||
i128 c = I128_ZERO;
|
||||
i64 a = x.value_integer;
|
||||
i64 b = y.value_integer;
|
||||
i64 c = 0ll;
|
||||
switch (op) {
|
||||
case Token_Add: c = a + b; break;
|
||||
case Token_Sub: c = a - b; break;
|
||||
case Token_Mul: c = a * b; break;
|
||||
case Token_Quo: return exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b)));
|
||||
case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
|
||||
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
|
||||
case Token_Mod: c = a % b; break;
|
||||
case Token_ModMod: c = ((a % b) + b) % b; break;
|
||||
case Token_And: c = a & b; break;
|
||||
case Token_Or: c = a | b; break;
|
||||
case Token_Xor: c = a ^ b; break;
|
||||
case Token_AndNot: c = i128_and_not(a, b); break;
|
||||
case Token_Shl: c = a << cast(u32)i128_to_u64(b); break;
|
||||
case Token_Shr: c = a >> cast(u32)i128_to_u64(b); break;
|
||||
case Token_AndNot: c = a & (~b); break;
|
||||
case Token_Shl: c = a << b; break;
|
||||
case Token_Shr: c = a >> b; break;
|
||||
default: goto error;
|
||||
}
|
||||
|
||||
return exact_value_i128(c);
|
||||
return exact_value_i64(c);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -628,8 +623,8 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
break;
|
||||
|
||||
case ExactValue_Integer: {
|
||||
i128 a = x.value_integer;
|
||||
i128 b = y.value_integer;
|
||||
i64 a = x.value_integer;
|
||||
i64 b = y.value_integer;
|
||||
switch (op) {
|
||||
case Token_CmpEq: return a == b;
|
||||
case Token_NotEq: return a != b;
|
||||
|
||||
+26
-3
@@ -1,4 +1,4 @@
|
||||
/* gb.h - v0.31 - Ginger Bill's C Helper Library - public domain
|
||||
/* gb.h - v0.32 - Ginger Bill's C Helper Library - public domain
|
||||
- no warranty implied; use at your own risk
|
||||
|
||||
This is a single header file with a bunch of useful stuff
|
||||
@@ -58,6 +58,7 @@ TODOS
|
||||
- More date & time functions
|
||||
|
||||
VERSION HISTORY
|
||||
0.32 - Minor fixes
|
||||
0.31 - Add gb_file_remove
|
||||
0.30 - Changes to gbThread (and gbMutex on Windows)
|
||||
0.29 - Add extras for gbString
|
||||
@@ -1515,6 +1516,7 @@ typedef struct gbStringHeader {
|
||||
|
||||
#define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1)
|
||||
|
||||
GB_DEF gbString gb_string_make_reserve (gbAllocator a, isize capacity);
|
||||
GB_DEF gbString gb_string_make (gbAllocator a, char const *str);
|
||||
GB_DEF gbString gb_string_make_length (gbAllocator a, void const *str, isize num_bytes);
|
||||
GB_DEF void gb_string_free (gbString str);
|
||||
@@ -6504,6 +6506,27 @@ gb_inline void gb__set_string_length (gbString str, isize len) { GB_STRING_HEAD
|
||||
gb_inline void gb__set_string_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; }
|
||||
|
||||
|
||||
gbString gb_string_make_reserve(gbAllocator a, isize capacity) {
|
||||
isize header_size = gb_size_of(gbStringHeader);
|
||||
void *ptr = gb_alloc(a, header_size + capacity + 1);
|
||||
|
||||
gbString str;
|
||||
gbStringHeader *header;
|
||||
|
||||
if (ptr == NULL) return NULL;
|
||||
gb_zero_size(ptr, header_size + capacity + 1);
|
||||
|
||||
str = cast(char *)ptr + header_size;
|
||||
header = GB_STRING_HEADER(str);
|
||||
header->allocator = a;
|
||||
header->length = 0;
|
||||
header->capacity = capacity;
|
||||
str[capacity] = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
gb_inline gbString gb_string_make(gbAllocator a, char const *str) {
|
||||
isize len = str ? gb_strlen(str) : 0;
|
||||
return gb_string_make_length(a, str, len);
|
||||
@@ -6516,8 +6539,8 @@ gbString gb_string_make_length(gbAllocator a, void const *init_str, isize num_by
|
||||
gbString str;
|
||||
gbStringHeader *header;
|
||||
|
||||
if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1);
|
||||
if (ptr == NULL) return NULL;
|
||||
if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1);
|
||||
|
||||
str = cast(char *)ptr + header_size;
|
||||
header = GB_STRING_HEADER(str);
|
||||
@@ -6592,7 +6615,7 @@ gbString gb_string_append_fmt(gbString str, char const *fmt, ...) {
|
||||
char buf[4096] = {0};
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = gb_snprintf_va(str, gb_count_of(buf)-1, fmt, va);
|
||||
res = gb_snprintf_va(buf, gb_count_of(buf)-1, fmt, va)-1;
|
||||
va_end(va);
|
||||
return gb_string_append_length(str, buf, res);
|
||||
}
|
||||
|
||||
+6
-1
@@ -491,6 +491,11 @@ void u128_divide(u128 a, u128 b, u128 *quo, u128 *rem) {
|
||||
if (rem) *rem = U128_ZERO;
|
||||
return;
|
||||
}
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
if (quo) *quo = u128_from_u64(a.lo/b.lo);
|
||||
if (rem) *rem = u128_from_u64(a.lo%b.lo);
|
||||
return;
|
||||
}
|
||||
u128 r = a;
|
||||
u128 d = b;
|
||||
u128 x = U128_ONE;
|
||||
@@ -670,7 +675,7 @@ i128 i128_mul(i128 a, i128 b) {
|
||||
}
|
||||
|
||||
void i128_divide(i128 a, i128 b, i128 *quo_, i128 *rem_) {
|
||||
// TODO(bill): Optimize this i128 division calculation
|
||||
// IMPORTANT TODO(bill): Optimize this i128 division calculation
|
||||
i128 iquo = {0};
|
||||
i128 irem = {0};
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
|
||||
+753
-840
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -232,7 +232,7 @@ bool ir_opt_block_fusion(irProcedure *proc, irBlock *a) {
|
||||
array_pop(&a->instrs); // Remove branch at end
|
||||
for_array(i, b->instrs) {
|
||||
array_add(&a->instrs, b->instrs[i]);
|
||||
ir_set_instr_parent(b->instrs[i], a);
|
||||
ir_set_instr_block(b->instrs[i], a);
|
||||
}
|
||||
|
||||
array_clear(&a->succs);
|
||||
|
||||
+353
-507
File diff suppressed because it is too large
Load Diff
+114
-100
@@ -1,26 +1,25 @@
|
||||
#define ALLOW_ARRAY_PROGRAMMING
|
||||
|
||||
#define USE_CUSTOM_BACKEND 0
|
||||
// #define NO_ARRAY_BOUNDS_CHECK
|
||||
#if !defined(USE_THREADED_PARSER)
|
||||
#define USE_THREADED_PARSER 0
|
||||
#endif
|
||||
// #define NO_POINTER_ARITHMETIC
|
||||
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
#include "build_settings.cpp"
|
||||
#include "tokenizer.cpp"
|
||||
#include "exact_value.cpp"
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "checker.hpp"
|
||||
|
||||
#include "parser.cpp"
|
||||
#include "docs.cpp"
|
||||
#include "checker.cpp"
|
||||
#include "ssa.cpp"
|
||||
#include "ir.cpp"
|
||||
#include "ir_opt.cpp"
|
||||
#include "ir_print.cpp"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
// NOTE(bill): 'name' is used in debugging and profiling modes
|
||||
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
char cmd_line[4096] = {0};
|
||||
@@ -43,6 +42,7 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
// gb_printf_err("%.*s\n", cast(int)cmd_len, cmd_line);
|
||||
|
||||
tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
|
||||
|
||||
@@ -60,11 +60,9 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
exit_code = -1;
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
|
||||
char cmd_line[4096] = {0};
|
||||
isize cmd_len;
|
||||
@@ -77,6 +75,7 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
va_end(va);
|
||||
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
|
||||
|
||||
//printf("do: %s\n", cmd_line);
|
||||
exit_code = system(&cmd_line[0]);
|
||||
|
||||
// pid_t pid = fork();
|
||||
@@ -107,8 +106,8 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
|
||||
// exit_code = status;
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -209,6 +208,10 @@ enum BuildFlagKind {
|
||||
BuildFlag_KeepTempFiles,
|
||||
BuildFlag_Collection,
|
||||
BuildFlag_BuildMode,
|
||||
BuildFlag_Debug,
|
||||
BuildFlag_CrossCompile,
|
||||
BuildFlag_CrossLibDir,
|
||||
BuildFlag_NoBoundsCheck,
|
||||
|
||||
BuildFlag_COUNT,
|
||||
};
|
||||
@@ -244,8 +247,13 @@ bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
|
||||
|
||||
|
||||
GB_ASSERT(args.count >= 3);
|
||||
Array<String> flag_args = args;
|
||||
flag_args.data += 3;
|
||||
flag_args.count -= 3;
|
||||
@@ -294,29 +302,13 @@ bool parse_build_flags(Array<String> args) {
|
||||
switch (bf.param_kind) {
|
||||
default: ok = false; break;
|
||||
case BuildFlagParam_Boolean: {
|
||||
if (param == "t") {
|
||||
if (str_eq_ignore_case(param, str_lit("t")) ||
|
||||
str_eq_ignore_case(param, str_lit("true")) ||
|
||||
param == "1") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "T") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "true") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "TRUE") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "True") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "1") {
|
||||
value = exact_value_bool(true);
|
||||
} else if (param == "f") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "F") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "false") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "FALSE") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "False") {
|
||||
value = exact_value_bool(false);
|
||||
} else if (param == "0") {
|
||||
} else if (str_eq_ignore_case(param, str_lit("f")) ||
|
||||
str_eq_ignore_case(param, str_lit("false")) ||
|
||||
param == "0") {
|
||||
value = exact_value_bool(false);
|
||||
} else {
|
||||
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
|
||||
@@ -375,7 +367,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
if (ok) switch (bf.kind) {
|
||||
case BuildFlag_OptimizationLevel:
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
build_context.optimization_level = cast(i32)i128_to_i64(value.value_integer);
|
||||
build_context.optimization_level = cast(i32)value.value_integer;
|
||||
break;
|
||||
case BuildFlag_ShowTimings:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
@@ -383,7 +375,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
break;
|
||||
case BuildFlag_ThreadCount: {
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
isize count = cast(isize)i128_to_i64(value.value_integer);
|
||||
isize count = cast(isize)value.value_integer;
|
||||
if (count <= 0) {
|
||||
gb_printf_err("%.*s expected a positive non-zero number, got %.*s", LIT(name), LIT(param));
|
||||
build_context.thread_count = 0;
|
||||
@@ -397,6 +389,33 @@ bool parse_build_flags(Array<String> args) {
|
||||
build_context.keep_temp_files = true;
|
||||
break;
|
||||
|
||||
case BuildFlag_CrossCompile: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
cross_compile_target = value.value_string;
|
||||
#if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
|
||||
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
|
||||
gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_CrossLibDir: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
if (cross_compile_lib_dir.len) {
|
||||
gb_printf_err("Multiple cross compilation library directories\n");
|
||||
bad_flags = true;
|
||||
} else {
|
||||
cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_Collection: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
String str = value.value_string;
|
||||
@@ -483,6 +502,14 @@ bool parse_build_flags(Array<String> args) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_Debug:
|
||||
build_context.ODIN_DEBUG = true;
|
||||
break;
|
||||
|
||||
case BuildFlag_NoBoundsCheck:
|
||||
build_context.no_bounds_check = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +528,6 @@ bool parse_build_flags(Array<String> args) {
|
||||
return !bad_flags;
|
||||
}
|
||||
|
||||
|
||||
void show_timings(Checker *c, Timings *t) {
|
||||
Parser *p = c->parser;
|
||||
isize lines = p->total_line_count;
|
||||
@@ -518,7 +544,7 @@ void show_timings(Checker *c, Timings *t) {
|
||||
{
|
||||
TimeStamp ts = t->sections[0];
|
||||
GB_ASSERT(ts.label == "parse files");
|
||||
f64 parse_time = time_stamp_as_second(ts, t->freq);
|
||||
f64 parse_time = time_stamp_as_s(ts, t->freq);
|
||||
gb_printf("Parse pass\n");
|
||||
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time);
|
||||
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||
@@ -570,6 +596,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
Timings timings = {0};
|
||||
timings_init(&timings, str_lit("Total Time"), 128);
|
||||
defer (timings_destroy(&timings));
|
||||
|
||||
init_string_buffer_memory();
|
||||
init_scratch_memory(gb_megabytes(10));
|
||||
init_global_error_collector();
|
||||
@@ -580,8 +607,6 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
Array<String> args = setup_args(arg_count, arg_ptr);
|
||||
|
||||
#if 1
|
||||
|
||||
String command = args[1];
|
||||
|
||||
String init_filename = {};
|
||||
@@ -660,7 +685,6 @@ int main(int arg_count, char **arg_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
timings_start_section(&timings, str_lit("type check"));
|
||||
|
||||
Checker checker = {0};
|
||||
@@ -670,26 +694,11 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
check_parsed_files(&checker);
|
||||
|
||||
|
||||
#endif
|
||||
#if defined(USE_CUSTOM_BACKEND) && USE_CUSTOM_BACKEND
|
||||
if (global_error_collector.count != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (checker.parser->total_token_count < 2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ssa_generate(&parser, &checker.info)) {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
irGen ir_gen = {0};
|
||||
if (!ir_gen_init(&ir_gen, &checker)) {
|
||||
return 1;
|
||||
}
|
||||
defer (ir_gen_destroy(&ir_gen));
|
||||
// defer (ir_gen_destroy(&ir_gen));
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm ir gen"));
|
||||
ir_gen_tree(&ir_gen);
|
||||
@@ -700,10 +709,6 @@ int main(int arg_count, char **arg_ptr) {
|
||||
timings_start_section(&timings, str_lit("llvm ir print"));
|
||||
print_llvm_ir(&ir_gen);
|
||||
|
||||
// prof_print_all();
|
||||
|
||||
#if 1
|
||||
timings_start_section(&timings, str_lit("llvm-opt"));
|
||||
|
||||
String output_name = ir_gen.output_name;
|
||||
String output_base = ir_gen.output_base;
|
||||
@@ -712,10 +717,11 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
i32 exit_code = 0;
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm-opt"));
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
// For more passes arguments: http://llvm.org/docs/Passes.html
|
||||
exit_code = system_exec_command_line_app("llvm-opt", false,
|
||||
"\"%.*sbin/opt\" \"%.*s\".ll -o \"%.*s\".bc %.*s "
|
||||
"\"%.*sbin/opt\" \"%.*s.ll\" -o \"%.*s.bc\" %.*s "
|
||||
"-mem2reg "
|
||||
"-memcpyopt "
|
||||
"-die "
|
||||
@@ -723,6 +729,11 @@ int main(int arg_count, char **arg_ptr) {
|
||||
LIT(build_context.ODIN_ROOT),
|
||||
LIT(output_base), LIT(output_base),
|
||||
LIT(build_context.opt_flags));
|
||||
// exit_code = system_exec_command_line_app("llvm-opt", false,
|
||||
// "\"%.*sbin/llvm-as\" \"%.*s.ll\" -o \"%.*s.bc\" "
|
||||
// "",
|
||||
// LIT(build_context.ODIN_ROOT),
|
||||
// LIT(output_base), LIT(output_base));
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
@@ -730,16 +741,10 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// NOTE(zangent): This is separate because it seems that LLVM tools are packaged
|
||||
// with the Windows version, while they will be system-provided on MacOS and GNU/Linux
|
||||
exit_code = system_exec_command_line_app("llvm-opt", false,
|
||||
"opt \"%.*s\".ll -o \"%.*s\".bc %.*s "
|
||||
"opt \"%.*s.ll\" -o \"%.*s.bc\" %.*s "
|
||||
"-mem2reg "
|
||||
"-memcpyopt "
|
||||
"-die "
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
||||
// make sure to also change the 'macosx_version_min' param passed to 'llc'
|
||||
"-mtriple=x86_64-apple-macosx10.8 "
|
||||
#endif
|
||||
"",
|
||||
LIT(output_base), LIT(output_base),
|
||||
LIT(build_context.opt_flags));
|
||||
@@ -753,12 +758,14 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||
exit_code = system_exec_command_line_app("llvm-llc", false,
|
||||
"\"%.*sbin/llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
||||
"-o \"%.*s.obj\" "
|
||||
"%.*s "
|
||||
// "-debug-pass=Arguments "
|
||||
"",
|
||||
LIT(build_context.ODIN_ROOT),
|
||||
LIT(output_base),
|
||||
build_context.optimization_level,
|
||||
LIT(output_base),
|
||||
LIT(build_context.llc_flags));
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
@@ -778,19 +785,24 @@ int main(int arg_count, char **arg_ptr) {
|
||||
}
|
||||
|
||||
char *output_ext = "exe";
|
||||
char *link_settings = "";
|
||||
gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
|
||||
defer (gb_string_free(link_settings));
|
||||
|
||||
if (build_context.is_dll) {
|
||||
output_ext = "dll";
|
||||
link_settings = "/DLL";
|
||||
link_settings = gb_string_append_fmt(link_settings, "/DLL");
|
||||
} else {
|
||||
link_settings = "/ENTRY:mainCRTStartup";
|
||||
link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup");
|
||||
}
|
||||
|
||||
if (ir_gen.module.generate_debug_info) {
|
||||
link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
|
||||
}
|
||||
|
||||
exit_code = system_exec_command_line_app("msvc-link", true,
|
||||
"link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
|
||||
"/defaultlib:libcmt "
|
||||
// "/nodefaultlib "
|
||||
// "/debug "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
|
||||
" %.*s "
|
||||
" %s "
|
||||
@@ -798,7 +810,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
LIT(output_base), LIT(output_base), output_ext,
|
||||
lib_str, LIT(build_context.link_flags),
|
||||
link_settings
|
||||
);
|
||||
);
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
@@ -812,7 +824,6 @@ int main(int arg_count, char **arg_ptr) {
|
||||
if (run_output) {
|
||||
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
|
||||
@@ -824,10 +835,12 @@ int main(int arg_count, char **arg_ptr) {
|
||||
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
|
||||
"%.*s "
|
||||
// "-debug-pass=Arguments "
|
||||
"%s"
|
||||
"",
|
||||
LIT(output_base),
|
||||
build_context.optimization_level,
|
||||
LIT(build_context.llc_flags));
|
||||
LIT(build_context.llc_flags),
|
||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
@@ -840,9 +853,8 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
|
||||
// files can be passed with -l:
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "-L/");
|
||||
|
||||
defer (gb_string_free(lib_str));
|
||||
char lib_str_buf[1024] = {0};
|
||||
|
||||
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||
String lib = ir_gen.module.foreign_library_paths[i];
|
||||
|
||||
@@ -850,19 +862,18 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// This allows you to specify '-f' in a #foreign_system_library,
|
||||
// without having to implement any new syntax specifically for MacOS.
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
isize len;
|
||||
if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
||||
if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
||||
// framework thingie
|
||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
|
||||
} else if (string_has_extension(lib, str_lit("a"))) {
|
||||
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
|
||||
} else if (string_ends_with(lib, str_lit(".a"))) {
|
||||
// static libs, absolute full path relative to the file in which the lib was imported from
|
||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " %.*s ", LIT(lib));
|
||||
} else if (string_has_extension(lib, str_lit("dylib"))) {
|
||||
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
|
||||
} else if (string_ends_with(lib, str_lit(".dylib"))) {
|
||||
// dynamic lib, relative path to executable
|
||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
|
||||
} else {
|
||||
// dynamic or static system lib, just link regularly searching system library paths
|
||||
len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib));
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||
}
|
||||
#else
|
||||
// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
|
||||
@@ -870,20 +881,19 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// available at runtime wherever the executable is run, so we make require those to be
|
||||
// local to the executable (unless the system collection is used, in which case we search
|
||||
// the system library paths for the library file).
|
||||
if (string_has_extension(lib, str_lit("a"))) {
|
||||
if (string_ends_with(lib, str_lit(".a"))) {
|
||||
// static libs, absolute full path relative to the file in which the lib was imported from
|
||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%.*s ", LIT(lib));
|
||||
} else if (string_has_extension(lib, str_lit("so"))) {
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l:%.*s ", LIT(lib));
|
||||
} else if (string_ends_with(lib, str_lit(".so"))) {
|
||||
// dynamic lib, relative path to executable
|
||||
// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
|
||||
// at runtimeto the executable
|
||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
|
||||
} else {
|
||||
// dynamic or static system lib, just link regularly searching system library paths
|
||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib));
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||
}
|
||||
#endif
|
||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||
}
|
||||
|
||||
// Unlike the Win32 linker code, the output_ext includes the dot, because
|
||||
@@ -912,14 +922,19 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// It probably has to do with including the entire CRT, but
|
||||
// that's quite a complicated issue to solve while remaining distro-agnostic.
|
||||
// Clang can figure out linker flags for us, and that's good enough _for now_.
|
||||
linker = "clang -Wno-unused-command-line-argument";
|
||||
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
|
||||
linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
|
||||
} else {
|
||||
linker = "clang -Wno-unused-command-line-argument";
|
||||
}
|
||||
#endif
|
||||
|
||||
exit_code = system_exec_command_line_app("ld-link", true,
|
||||
"%s \"%.*s.o\" -o \"%.*s%s\" %s "
|
||||
"-lc -lm "
|
||||
" %s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
" %.*s "
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
||||
@@ -929,8 +944,11 @@ int main(int arg_count, char **arg_ptr) {
|
||||
" -e _main "
|
||||
#endif
|
||||
, linker, LIT(output_base), LIT(output_base), output_ext,
|
||||
lib_str, LIT(build_context.link_flags),
|
||||
link_settings
|
||||
lib_str,
|
||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "" : "-lc -lm",
|
||||
LIT(build_context.link_flags),
|
||||
link_settings,
|
||||
LIT(cross_compile_lib_dir)
|
||||
);
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
@@ -945,11 +963,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
if (run_output) {
|
||||
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+13
-8
@@ -2,6 +2,8 @@
|
||||
// with the use of the `multi_*` procedures.
|
||||
// TODO(bill): I should probably allow the `multi_map_*` stuff to be #ifdefed out
|
||||
|
||||
#define MAP_ENABLE_MULTI_MAP 1
|
||||
|
||||
#ifndef MAP_UTIL_STUFF
|
||||
#define MAP_UTIL_STUFF
|
||||
// NOTE(bill): This util stuff is the same for every `Map`
|
||||
@@ -110,6 +112,7 @@ template <typename T> void map_clear (Map<T> *h);
|
||||
template <typename T> void map_grow (Map<T> *h);
|
||||
template <typename T> void map_rehash (Map<T> *h, isize new_count);
|
||||
|
||||
#if MAP_ENABLE_MULTI_MAP
|
||||
// Mutlivalued map procedure
|
||||
template <typename T> MapEntry<T> * multi_map_find_first(Map<T> *h, HashKey key);
|
||||
template <typename T> MapEntry<T> * multi_map_find_next (Map<T> *h, MapEntry<T> *e);
|
||||
@@ -119,19 +122,17 @@ template <typename T> void multi_map_get_all (Map<T> *h, HashKey key, T *item
|
||||
template <typename T> void multi_map_insert (Map<T> *h, HashKey key, T const &value);
|
||||
template <typename T> void multi_map_remove (Map<T> *h, HashKey key, MapEntry<T> *e);
|
||||
template <typename T> void multi_map_remove_all(Map<T> *h, HashKey key);
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_init(Map<T> *h, gbAllocator a, isize capacity) {
|
||||
array_init(&h->hashes, a, capacity);
|
||||
array_init(&h->entries, a, capacity);
|
||||
}
|
||||
array_init(&h->entries, a, capacity);}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_destroy(Map<T> *h) {
|
||||
array_free(&h->entries);
|
||||
array_free(&h->hashes);
|
||||
}
|
||||
array_free(&h->hashes);}
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize map__add_entry(Map<T> *h, HashKey key) {
|
||||
@@ -182,9 +183,12 @@ gb_internal b32 map__full(Map<T> *h) {
|
||||
return 0.75f * h->hashes.count <= h->entries.count;
|
||||
}
|
||||
|
||||
#define MAP_ARRAY_GROW_FORMULA(x) (4*(x) + 7)
|
||||
GB_STATIC_ASSERT(MAP_ARRAY_GROW_FORMULA(0) > 0);
|
||||
|
||||
template <typename T>
|
||||
gb_inline void map_grow(Map<T> *h) {
|
||||
isize new_count = ARRAY_GROW_FORMULA(h->entries.count);
|
||||
isize new_count = MAP_ARRAY_GROW_FORMULA(h->entries.count);
|
||||
map_rehash(h, new_count);
|
||||
}
|
||||
|
||||
@@ -234,8 +238,9 @@ template <typename T>
|
||||
void map_set(Map<T> *h, HashKey key, T const &value) {
|
||||
isize index;
|
||||
MapFindResult fr;
|
||||
if (h->hashes.count == 0)
|
||||
if (h->hashes.count == 0) {
|
||||
map_grow(h);
|
||||
}
|
||||
fr = map__find(h, key);
|
||||
if (fr.entry_index >= 0) {
|
||||
index = fr.entry_index;
|
||||
@@ -291,7 +296,7 @@ gb_inline void map_clear(Map<T> *h) {
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
#if MAP_ENABLE_MULTI_MAP
|
||||
template <typename T>
|
||||
MapEntry<T> *multi_map_find_first(Map<T> *h, HashKey key) {
|
||||
isize i = map__find(h, key).entry_index;
|
||||
|
||||
+9
-9
@@ -212,14 +212,14 @@ void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) {
|
||||
((u32 *)out)[3] = h4;
|
||||
}
|
||||
|
||||
gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
|
||||
u128 res;
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
MurmurHash3_x64_128(key, len, seed, &res);
|
||||
#else
|
||||
MurmurHash3_x86_128(key, len, seed, &res);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
// gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
|
||||
// u128 res;
|
||||
// #if defined(GB_ARCH_64_BIT)
|
||||
// MurmurHash3_x64_128(key, len, seed, &res);
|
||||
// #else
|
||||
// MurmurHash3_x86_128(key, len, seed, &res);
|
||||
// #endif
|
||||
// return res;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
+224
-1149
File diff suppressed because it is too large
Load Diff
+532
@@ -0,0 +1,532 @@
|
||||
struct AstNode;
|
||||
struct Scope;
|
||||
struct Type;
|
||||
struct Entity;
|
||||
struct DeclInfo;
|
||||
|
||||
|
||||
enum ParseFileError {
|
||||
ParseFile_None,
|
||||
|
||||
ParseFile_WrongExtension,
|
||||
ParseFile_InvalidFile,
|
||||
ParseFile_EmptyFile,
|
||||
ParseFile_Permission,
|
||||
ParseFile_NotFound,
|
||||
ParseFile_InvalidToken,
|
||||
|
||||
ParseFile_Count,
|
||||
};
|
||||
|
||||
struct CommentGroup {
|
||||
Array<Token> list; // Token_Comment
|
||||
};
|
||||
|
||||
|
||||
enum ImportedFileKind {
|
||||
ImportedFile_Normal,
|
||||
ImportedFile_Shared,
|
||||
ImportedFile_Init,
|
||||
};
|
||||
|
||||
struct ImportedFile {
|
||||
ImportedFileKind kind;
|
||||
String path;
|
||||
String rel_path;
|
||||
TokenPos pos; // import
|
||||
isize index;
|
||||
};
|
||||
|
||||
|
||||
struct AstFile {
|
||||
isize id;
|
||||
String fullpath;
|
||||
gbArena arena;
|
||||
Tokenizer tokenizer;
|
||||
Array<Token> tokens;
|
||||
isize curr_token_index;
|
||||
Token curr_token;
|
||||
Token prev_token; // previous non-comment
|
||||
|
||||
// >= 0: In Expression
|
||||
// < 0: In Control Clause
|
||||
// NOTE(bill): Used to prevent type literals in control clauses
|
||||
isize expr_level;
|
||||
bool allow_range; // NOTE(bill): Ranges are only allowed in certain cases
|
||||
bool in_foreign_block;
|
||||
bool allow_type;
|
||||
isize when_level;
|
||||
|
||||
Array<AstNode *> decls;
|
||||
ImportedFileKind file_kind;
|
||||
bool is_global_scope;
|
||||
Array<AstNode *> imports_and_exports; // 'import' 'using import' 'export'
|
||||
|
||||
|
||||
AstNode * curr_proc;
|
||||
isize scope_level;
|
||||
Scope * scope; // NOTE(bill): Created in checker
|
||||
DeclInfo * decl_info; // NOTE(bill): Created in checker
|
||||
|
||||
|
||||
CommentGroup lead_comment; // Comment (block) before the decl
|
||||
CommentGroup line_comment; // Comment after the semicolon
|
||||
CommentGroup docs; // current docs
|
||||
Array<CommentGroup> comments; // All the comments!
|
||||
|
||||
|
||||
#define PARSER_MAX_FIX_COUNT 6
|
||||
isize fix_count;
|
||||
TokenPos fix_prev_pos;
|
||||
};
|
||||
|
||||
|
||||
struct Parser {
|
||||
String init_fullpath;
|
||||
Array<AstFile *> files;
|
||||
Array<ImportedFile> imports;
|
||||
isize total_token_count;
|
||||
isize total_line_count;
|
||||
gbMutex file_add_mutex;
|
||||
gbMutex file_decl_mutex;
|
||||
};
|
||||
|
||||
enum ProcInlining {
|
||||
ProcInlining_none = 0,
|
||||
ProcInlining_inline = 1,
|
||||
ProcInlining_no_inline = 2,
|
||||
};
|
||||
|
||||
enum ProcTag {
|
||||
ProcTag_bounds_check = 1<<0,
|
||||
ProcTag_no_bounds_check = 1<<1,
|
||||
ProcTag_require_results = 1<<4,
|
||||
};
|
||||
|
||||
enum ProcCallingConvention {
|
||||
ProcCC_Invalid = 0,
|
||||
ProcCC_Odin,
|
||||
ProcCC_Contextless,
|
||||
ProcCC_CDecl,
|
||||
ProcCC_StdCall,
|
||||
ProcCC_FastCall,
|
||||
|
||||
// TODO(bill): Add extra calling conventions
|
||||
// ProcCC_VectorCall,
|
||||
// ProcCC_ClrCall,
|
||||
|
||||
ProcCC_ForeignBlockDefault = -1,
|
||||
};
|
||||
|
||||
enum StmtStateFlag {
|
||||
StmtStateFlag_bounds_check = 1<<0,
|
||||
StmtStateFlag_no_bounds_check = 1<<1,
|
||||
};
|
||||
|
||||
enum FieldFlag {
|
||||
FieldFlag_NONE = 0,
|
||||
FieldFlag_ellipsis = 1<<0,
|
||||
FieldFlag_using = 1<<1,
|
||||
FieldFlag_no_alias = 1<<2,
|
||||
FieldFlag_c_vararg = 1<<3,
|
||||
|
||||
FieldFlag_in = 1<<5,
|
||||
|
||||
|
||||
FieldFlag_Results = 1<<16,
|
||||
|
||||
// FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_in,
|
||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg,
|
||||
FieldFlag_Struct = FieldFlag_using,
|
||||
};
|
||||
|
||||
enum StmtAllowFlag {
|
||||
StmtAllowFlag_None = 0,
|
||||
StmtAllowFlag_In = 1<<0,
|
||||
StmtAllowFlag_Label = 1<<1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
|
||||
Array<AstNode *> a;
|
||||
array_init(&a, heap_allocator(), init_capacity);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): This massive define is so it is possible to create a discriminated union (and extra debug info)
|
||||
// for the AstNode. I personally prefer discriminated unions over subtype polymorphism as I can preallocate
|
||||
// all the nodes and even memcpy in a different kind of node
|
||||
#define AST_NODE_KINDS \
|
||||
AST_NODE_KIND(Ident, "identifier", struct { \
|
||||
Token token; \
|
||||
Entity *entity; \
|
||||
}) \
|
||||
AST_NODE_KIND(Implicit, "implicit", Token) \
|
||||
AST_NODE_KIND(Undef, "undef", Token) \
|
||||
AST_NODE_KIND(BasicLit, "basic literal", struct { \
|
||||
Token token; \
|
||||
}) \
|
||||
AST_NODE_KIND(BasicDirective, "basic directive", struct { \
|
||||
Token token; \
|
||||
String name; \
|
||||
}) \
|
||||
AST_NODE_KIND(Ellipsis, "ellipsis", struct { \
|
||||
Token token; \
|
||||
AstNode *expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcGroup, "procedure group", struct { \
|
||||
Token token; \
|
||||
Token open; \
|
||||
Token close; \
|
||||
Array<AstNode *> args; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcLit, "procedure literal", struct { \
|
||||
AstNode * type; \
|
||||
AstNode * body; \
|
||||
u64 tags; \
|
||||
ProcInlining inlining; \
|
||||
}) \
|
||||
AST_NODE_KIND(CompoundLit, "compound literal", struct { \
|
||||
AstNode *type; \
|
||||
Array<AstNode *> elems; \
|
||||
Token open, close; \
|
||||
}) \
|
||||
AST_NODE_KIND(_ExprBegin, "", struct {}) \
|
||||
AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
|
||||
AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \
|
||||
AST_NODE_KIND(RunExpr, "run expression", struct { Token token, name; AstNode *expr; }) \
|
||||
AST_NODE_KIND(UnaryExpr, "unary expression", struct { Token op; AstNode *expr; }) \
|
||||
AST_NODE_KIND(BinaryExpr, "binary expression", struct { Token op; AstNode *left, *right; } ) \
|
||||
AST_NODE_KIND(ParenExpr, "parentheses expression", struct { AstNode *expr; Token open, close; }) \
|
||||
AST_NODE_KIND(SelectorExpr, "selector expression", struct { Token token; AstNode *expr, *selector; }) \
|
||||
AST_NODE_KIND(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \
|
||||
AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \
|
||||
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
|
||||
AstNode *expr; \
|
||||
Token open, close; \
|
||||
Token interval; \
|
||||
AstNode *low, *high; \
|
||||
}) \
|
||||
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
||||
AstNode * proc; \
|
||||
Array<AstNode *> args; \
|
||||
Token open; \
|
||||
Token close; \
|
||||
Token ellipsis; \
|
||||
}) \
|
||||
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
|
||||
AST_NODE_KIND(TernaryExpr, "ternary expression", struct { AstNode *cond, *x, *y; }) \
|
||||
AST_NODE_KIND(TypeAssertion, "type assertion", struct { AstNode *expr; Token dot; AstNode *type; }) \
|
||||
AST_NODE_KIND(TypeCast, "type cast", struct { Token token; AstNode *type, *expr; }) \
|
||||
AST_NODE_KIND(_ExprEnd, "", struct {}) \
|
||||
AST_NODE_KIND(_StmtBegin, "", struct {}) \
|
||||
AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
|
||||
AST_NODE_KIND(EmptyStmt, "empty statement", struct { Token token; }) \
|
||||
AST_NODE_KIND(ExprStmt, "expression statement", struct { AstNode *expr; } ) \
|
||||
AST_NODE_KIND(TagStmt, "tag statement", struct { \
|
||||
Token token; \
|
||||
Token name; \
|
||||
AstNode *stmt; \
|
||||
}) \
|
||||
AST_NODE_KIND(AssignStmt, "assign statement", struct { \
|
||||
Token op; \
|
||||
Array<AstNode *> lhs, rhs; \
|
||||
}) \
|
||||
AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \
|
||||
Token op; \
|
||||
AstNode *expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(_ComplexStmtBegin, "", struct {}) \
|
||||
AST_NODE_KIND(BlockStmt, "block statement", struct { \
|
||||
Array<AstNode *> stmts; \
|
||||
Token open, close; \
|
||||
}) \
|
||||
AST_NODE_KIND(IfStmt, "if statement", struct { \
|
||||
Token token; \
|
||||
AstNode *init; \
|
||||
AstNode *cond; \
|
||||
AstNode *body; \
|
||||
AstNode *else_stmt; \
|
||||
}) \
|
||||
AST_NODE_KIND(WhenStmt, "when statement", struct { \
|
||||
Token token; \
|
||||
AstNode *cond; \
|
||||
AstNode *body; \
|
||||
AstNode *else_stmt; \
|
||||
bool is_cond_determined; \
|
||||
bool determined_cond; \
|
||||
}) \
|
||||
AST_NODE_KIND(ReturnStmt, "return statement", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> results; \
|
||||
}) \
|
||||
AST_NODE_KIND(ForStmt, "for statement", struct { \
|
||||
Token token; \
|
||||
AstNode *label; \
|
||||
AstNode *init; \
|
||||
AstNode *cond; \
|
||||
AstNode *post; \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(RangeStmt, "range statement", struct { \
|
||||
Token token; \
|
||||
AstNode *label; \
|
||||
AstNode *val0; \
|
||||
AstNode *val1; \
|
||||
Token in_token; \
|
||||
AstNode *expr; \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(CaseClause, "case clause", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> list; \
|
||||
Array<AstNode *> stmts; \
|
||||
Entity *implicit_entity; \
|
||||
}) \
|
||||
AST_NODE_KIND(SwitchStmt, "switch statement", struct { \
|
||||
Token token; \
|
||||
AstNode *label; \
|
||||
AstNode *init; \
|
||||
AstNode *tag; \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(TypeSwitchStmt, "type switch statement", struct { \
|
||||
Token token; \
|
||||
AstNode *label; \
|
||||
AstNode *tag; \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
|
||||
AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \
|
||||
AST_NODE_KIND(UsingStmt, "using statement", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> list; \
|
||||
}) \
|
||||
AST_NODE_KIND(UsingInStmt, "using in statement", struct { \
|
||||
Token using_token; \
|
||||
Array<AstNode *> list; \
|
||||
Token in_token; \
|
||||
AstNode *expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(PushContext, "context <- statement", struct { \
|
||||
Token token; \
|
||||
AstNode *expr; \
|
||||
AstNode *body; \
|
||||
}) \
|
||||
AST_NODE_KIND(_ComplexStmtEnd, "", struct {}) \
|
||||
AST_NODE_KIND(_StmtEnd, "", struct {}) \
|
||||
AST_NODE_KIND(_DeclBegin, "", struct {}) \
|
||||
AST_NODE_KIND(BadDecl, "bad declaration", struct { Token begin, end; }) \
|
||||
AST_NODE_KIND(ForeignBlockDecl, "foreign block declaration", struct { \
|
||||
Token token; \
|
||||
AstNode * foreign_library; \
|
||||
Token open, close; \
|
||||
Array<AstNode *> decls; \
|
||||
Array<AstNode *> attributes; \
|
||||
CommentGroup docs; \
|
||||
bool been_handled; \
|
||||
}) \
|
||||
AST_NODE_KIND(Label, "label", struct { \
|
||||
Token token; \
|
||||
AstNode *name; \
|
||||
}) \
|
||||
AST_NODE_KIND(ValueDecl, "value declaration", struct { \
|
||||
Array<AstNode *> names; \
|
||||
AstNode * type; \
|
||||
Array<AstNode *> values; \
|
||||
Array<AstNode *> attributes; \
|
||||
CommentGroup docs; \
|
||||
CommentGroup comment; \
|
||||
bool is_using; \
|
||||
bool is_mutable; \
|
||||
bool been_handled; \
|
||||
}) \
|
||||
AST_NODE_KIND(ImportDecl, "import declaration", struct { \
|
||||
AstFile *file; \
|
||||
Token token; \
|
||||
Token relpath; \
|
||||
String fullpath; \
|
||||
Token import_name; \
|
||||
Array<AstNode *> using_in_list; \
|
||||
CommentGroup docs; \
|
||||
CommentGroup comment; \
|
||||
bool is_using; \
|
||||
bool been_handled; \
|
||||
}) \
|
||||
AST_NODE_KIND(ExportDecl, "export declaration", struct { \
|
||||
AstFile *file; \
|
||||
Token token; \
|
||||
Token relpath; \
|
||||
String fullpath; \
|
||||
Array<AstNode *> using_in_list; \
|
||||
CommentGroup docs; \
|
||||
CommentGroup comment; \
|
||||
bool been_handled; \
|
||||
}) \
|
||||
AST_NODE_KIND(ForeignImportDecl, "foreign import declaration", struct { \
|
||||
Token token; \
|
||||
Token filepath; \
|
||||
Token library_name; \
|
||||
String base_dir; \
|
||||
String collection_name; \
|
||||
String fullpath; \
|
||||
CommentGroup docs; \
|
||||
CommentGroup comment; \
|
||||
bool been_handled; \
|
||||
}) \
|
||||
AST_NODE_KIND(_DeclEnd, "", struct {}) \
|
||||
AST_NODE_KIND(Attribute, "attribute", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
Array<AstNode *> elems; \
|
||||
Token open, close; \
|
||||
}) \
|
||||
AST_NODE_KIND(Field, "field", struct { \
|
||||
Array<AstNode *> names; \
|
||||
AstNode * type; \
|
||||
AstNode * default_value; \
|
||||
u32 flags; \
|
||||
CommentGroup docs; \
|
||||
CommentGroup comment; \
|
||||
}) \
|
||||
AST_NODE_KIND(FieldList, "field list", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> list; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionField, "union field", struct { \
|
||||
AstNode *name; \
|
||||
AstNode *list; \
|
||||
}) \
|
||||
AST_NODE_KIND(_TypeBegin, "", struct {}) \
|
||||
AST_NODE_KIND(TypeType, "type", struct { \
|
||||
Token token; \
|
||||
AstNode *specialization; \
|
||||
}) \
|
||||
AST_NODE_KIND(HelperType, "helper type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
}) \
|
||||
AST_NODE_KIND(DistinctType, "distinct type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
}) \
|
||||
AST_NODE_KIND(PolyType, "polymorphic type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
AstNode *specialization; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcType, "procedure type", struct { \
|
||||
Token token; \
|
||||
AstNode *params; \
|
||||
AstNode *results; \
|
||||
u64 tags; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
bool generic; \
|
||||
}) \
|
||||
AST_NODE_KIND(PointerType, "pointer type", struct { \
|
||||
Token token; \
|
||||
AstNode *type; \
|
||||
}) \
|
||||
AST_NODE_KIND(ArrayType, "array type", struct { \
|
||||
Token token; \
|
||||
AstNode *count; \
|
||||
AstNode *elem; \
|
||||
}) \
|
||||
AST_NODE_KIND(DynamicArrayType, "dynamic array type", struct { \
|
||||
Token token; \
|
||||
AstNode *elem; \
|
||||
}) \
|
||||
AST_NODE_KIND(StructType, "struct type", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> fields; \
|
||||
isize field_count; \
|
||||
AstNode * polymorphic_params; \
|
||||
AstNode * align; \
|
||||
bool is_packed; \
|
||||
bool is_raw_union; \
|
||||
}) \
|
||||
AST_NODE_KIND(UnionType, "union type", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> variants; \
|
||||
AstNode * align; \
|
||||
}) \
|
||||
AST_NODE_KIND(EnumType, "enum type", struct { \
|
||||
Token token; \
|
||||
AstNode * base_type; \
|
||||
Array<AstNode *> fields; /* FieldValue */ \
|
||||
bool is_export; \
|
||||
}) \
|
||||
AST_NODE_KIND(BitFieldType, "bit field type", struct { \
|
||||
Token token; \
|
||||
Array<AstNode *> fields; /* FieldValue with : */ \
|
||||
AstNode * align; \
|
||||
}) \
|
||||
AST_NODE_KIND(MapType, "map type", struct { \
|
||||
Token token; \
|
||||
AstNode *count; \
|
||||
AstNode *key; \
|
||||
AstNode *value; \
|
||||
}) \
|
||||
AST_NODE_KIND(_TypeEnd, "", struct {})
|
||||
|
||||
enum AstNodeKind {
|
||||
AstNode_Invalid,
|
||||
#define AST_NODE_KIND(_kind_name_, ...) GB_JOIN2(AstNode_, _kind_name_),
|
||||
AST_NODE_KINDS
|
||||
#undef AST_NODE_KIND
|
||||
AstNode_Count,
|
||||
};
|
||||
|
||||
String const ast_node_strings[] = {
|
||||
{cast(u8 *)"invalid node", gb_size_of("invalid node")},
|
||||
#define AST_NODE_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
|
||||
AST_NODE_KINDS
|
||||
#undef AST_NODE_KIND
|
||||
};
|
||||
|
||||
#define AST_NODE_KIND(_kind_name_, name, ...) typedef __VA_ARGS__ GB_JOIN2(AstNode, _kind_name_);
|
||||
AST_NODE_KINDS
|
||||
#undef AST_NODE_KIND
|
||||
|
||||
struct AstNode {
|
||||
AstNodeKind kind;
|
||||
u32 stmt_state_flags;
|
||||
AstFile * file;
|
||||
Scope * scope;
|
||||
|
||||
union {
|
||||
#define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
|
||||
AST_NODE_KINDS
|
||||
#undef AST_NODE_KIND
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
|
||||
#define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
|
||||
#ifndef case_end
|
||||
#define case_end } break;
|
||||
#endif
|
||||
|
||||
|
||||
gb_inline bool is_ast_node_expr(AstNode *node) {
|
||||
return gb_is_between(node->kind, AstNode__ExprBegin+1, AstNode__ExprEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_node_stmt(AstNode *node) {
|
||||
return gb_is_between(node->kind, AstNode__StmtBegin+1, AstNode__StmtEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_node_complex_stmt(AstNode *node) {
|
||||
return gb_is_between(node->kind, AstNode__ComplexStmtBegin+1, AstNode__ComplexStmtEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_node_decl(AstNode *node) {
|
||||
return gb_is_between(node->kind, AstNode__DeclBegin+1, AstNode__DeclEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_node_type(AstNode *node) {
|
||||
return gb_is_between(node->kind, AstNode__TypeBegin+1, AstNode__TypeEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_node_when_stmt(AstNode *node) {
|
||||
return node->kind == AstNode_WhenStmt;
|
||||
}
|
||||
|
||||
+16
-14
@@ -17,27 +17,25 @@ struct PtrSet {
|
||||
Array<PtrSetEntry<T>> entries;
|
||||
};
|
||||
|
||||
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
|
||||
template <typename T> void ptr_set_destroy (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_add (PtrSet<T> *s, T ptr);
|
||||
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_grow (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
|
||||
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
|
||||
template <typename T> void ptr_set_destroy(PtrSet<T> *s);
|
||||
template <typename T> T ptr_set_add (PtrSet<T> *s, T ptr);
|
||||
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_grow (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
|
||||
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
|
||||
array_init(&s->hashes, a, capacity);
|
||||
array_init(&s->entries, a, capacity);
|
||||
}
|
||||
array_init(&s->entries, a, capacity);}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_destroy(PtrSet<T> *s) {
|
||||
array_free(&s->hashes);
|
||||
array_free(&s->entries);
|
||||
}
|
||||
array_free(&s->entries);}
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize ptr_set__add_entry(PtrSet<T> *s, T ptr) {
|
||||
@@ -90,9 +88,12 @@ gb_internal b32 ptr_set__full(PtrSet<T> *s) {
|
||||
return 0.75f * s->hashes.count <= s->entries.count;
|
||||
}
|
||||
|
||||
#define PTR_ARRAY_GROW_FORMULA(x) (4*(x) + 7)
|
||||
GB_STATIC_ASSERT(PTR_ARRAY_GROW_FORMULA(0) > 0);
|
||||
|
||||
template <typename T>
|
||||
gb_inline void ptr_set_grow(PtrSet<T> *s) {
|
||||
isize new_count = ARRAY_GROW_FORMULA(s->entries.count);
|
||||
isize new_count = PTR_ARRAY_GROW_FORMULA(s->entries.count);
|
||||
ptr_set_rehash(s, new_count);
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
|
||||
|
||||
// Returns true if it already exists
|
||||
template <typename T>
|
||||
void ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
isize index;
|
||||
PtrSetFindResult fr;
|
||||
if (s->hashes.count == 0) {
|
||||
@@ -156,6 +157,7 @@ void ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-2561
File diff suppressed because it is too large
Load Diff
-275
@@ -1,275 +0,0 @@
|
||||
#define SSA_OPS \
|
||||
SSA_OP(Invalid)\
|
||||
\
|
||||
SSA_OP(Unknown)\
|
||||
\
|
||||
SSA_OP(Comment) /* Does nothing */\
|
||||
\
|
||||
SSA_OP(SP) /* Stack Pointer */\
|
||||
SSA_OP(SB) /* Stack Base */\
|
||||
\
|
||||
SSA_OP(Local)\
|
||||
SSA_OP(Global)\
|
||||
SSA_OP(Proc)\
|
||||
\
|
||||
SSA_OP(Load)\
|
||||
SSA_OP(Store)\
|
||||
SSA_OP(Move)\
|
||||
SSA_OP(LoadReg)\
|
||||
SSA_OP(StoreReg)\
|
||||
SSA_OP(Zero) /* Zero initialize */\
|
||||
\
|
||||
SSA_OP(ArrayIndex) /* Index for a fixed array */\
|
||||
SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\
|
||||
SSA_OP(PtrOffset)\
|
||||
SSA_OP(ValueIndex) /* Extract for a value from a register */\
|
||||
\
|
||||
SSA_OP(Phi)\
|
||||
SSA_OP(Copy)\
|
||||
\
|
||||
/* TODO(bill): calling conventions */\
|
||||
SSA_OP(CallOdin)\
|
||||
SSA_OP(CallC)\
|
||||
SSA_OP(CallStd)\
|
||||
SSA_OP(CallFast)\
|
||||
\
|
||||
SSA_OP(BoundsCheck)\
|
||||
SSA_OP(SliceBoundsCheck)\
|
||||
\
|
||||
/* Built in operations/procedures */\
|
||||
SSA_OP(Bswap16)\
|
||||
SSA_OP(Bswap32)\
|
||||
SSA_OP(Bswap64)\
|
||||
\
|
||||
SSA_OP(Assume)\
|
||||
SSA_OP(DebugTrap)\
|
||||
SSA_OP(Trap)\
|
||||
SSA_OP(ReadCycleCounter)\
|
||||
\
|
||||
\
|
||||
SSA_OP(ConstBool)\
|
||||
SSA_OP(ConstString)\
|
||||
SSA_OP(ConstSlice)\
|
||||
SSA_OP(ConstNil)\
|
||||
SSA_OP(Const8)\
|
||||
SSA_OP(Const16)\
|
||||
SSA_OP(Const32)\
|
||||
SSA_OP(Const64)\
|
||||
SSA_OP(Const32F)\
|
||||
SSA_OP(Const64F)\
|
||||
\
|
||||
/* These should be all the operations I could possibly need for the mean time */\
|
||||
SSA_OP(Add8)\
|
||||
SSA_OP(Add16)\
|
||||
SSA_OP(Add32)\
|
||||
SSA_OP(Add64)\
|
||||
SSA_OP(AddPtr)\
|
||||
SSA_OP(Add32F)\
|
||||
SSA_OP(Add64F)\
|
||||
SSA_OP(Sub8)\
|
||||
SSA_OP(Sub16)\
|
||||
SSA_OP(Sub32)\
|
||||
SSA_OP(Sub64)\
|
||||
SSA_OP(SubPtr)\
|
||||
SSA_OP(Sub32F)\
|
||||
SSA_OP(Sub64F)\
|
||||
SSA_OP(Mul8)\
|
||||
SSA_OP(Mul16)\
|
||||
SSA_OP(Mul32)\
|
||||
SSA_OP(Mul64)\
|
||||
SSA_OP(Mul32F)\
|
||||
SSA_OP(Mul64F)\
|
||||
SSA_OP(Div8)\
|
||||
SSA_OP(Div8U)\
|
||||
SSA_OP(Div16)\
|
||||
SSA_OP(Div16U)\
|
||||
SSA_OP(Div32)\
|
||||
SSA_OP(Div32U)\
|
||||
SSA_OP(Div64)\
|
||||
SSA_OP(Div64U)\
|
||||
SSA_OP(Div32F)\
|
||||
SSA_OP(Div64F)\
|
||||
SSA_OP(Mod8)\
|
||||
SSA_OP(Mod8U)\
|
||||
SSA_OP(Mod16)\
|
||||
SSA_OP(Mod16U)\
|
||||
SSA_OP(Mod32)\
|
||||
SSA_OP(Mod32U)\
|
||||
SSA_OP(Mod64)\
|
||||
SSA_OP(Mod64U)\
|
||||
\
|
||||
SSA_OP(And8)\
|
||||
SSA_OP(And16)\
|
||||
SSA_OP(And32)\
|
||||
SSA_OP(And64)\
|
||||
SSA_OP(Or8)\
|
||||
SSA_OP(Or16)\
|
||||
SSA_OP(Or32)\
|
||||
SSA_OP(Or64)\
|
||||
SSA_OP(Xor8)\
|
||||
SSA_OP(Xor16)\
|
||||
SSA_OP(Xor32)\
|
||||
SSA_OP(Xor64)\
|
||||
SSA_OP(AndNot8)\
|
||||
SSA_OP(AndNot16)\
|
||||
SSA_OP(AndNot32)\
|
||||
SSA_OP(AndNot64)\
|
||||
\
|
||||
SSA_OP(Lsh8x8)\
|
||||
SSA_OP(Lsh8x16)\
|
||||
SSA_OP(Lsh8x32)\
|
||||
SSA_OP(Lsh8x64)\
|
||||
SSA_OP(Lsh16x8)\
|
||||
SSA_OP(Lsh16x16)\
|
||||
SSA_OP(Lsh16x32)\
|
||||
SSA_OP(Lsh16x64)\
|
||||
SSA_OP(Lsh32x8)\
|
||||
SSA_OP(Lsh32x16)\
|
||||
SSA_OP(Lsh32x32)\
|
||||
SSA_OP(Lsh32x64)\
|
||||
SSA_OP(Lsh64x8)\
|
||||
SSA_OP(Lsh64x16)\
|
||||
SSA_OP(Lsh64x32)\
|
||||
SSA_OP(Lsh64x64)\
|
||||
SSA_OP(Rsh8x8)\
|
||||
SSA_OP(Rsh8x16)\
|
||||
SSA_OP(Rsh8x32)\
|
||||
SSA_OP(Rsh8x64)\
|
||||
SSA_OP(Rsh16x8)\
|
||||
SSA_OP(Rsh16x16)\
|
||||
SSA_OP(Rsh16x32)\
|
||||
SSA_OP(Rsh16x64)\
|
||||
SSA_OP(Rsh32x8)\
|
||||
SSA_OP(Rsh32x16)\
|
||||
SSA_OP(Rsh32x32)\
|
||||
SSA_OP(Rsh32x64)\
|
||||
SSA_OP(Rsh64x8)\
|
||||
SSA_OP(Rsh64x16)\
|
||||
SSA_OP(Rsh64x32)\
|
||||
SSA_OP(Rsh64x64)\
|
||||
SSA_OP(Rsh8Ux8)\
|
||||
SSA_OP(Rsh8Ux16)\
|
||||
SSA_OP(Rsh8Ux32)\
|
||||
SSA_OP(Rsh8Ux64)\
|
||||
SSA_OP(Rsh16Ux8)\
|
||||
SSA_OP(Rsh16Ux16)\
|
||||
SSA_OP(Rsh16Ux32)\
|
||||
SSA_OP(Rsh16Ux64)\
|
||||
SSA_OP(Rsh32Ux8)\
|
||||
SSA_OP(Rsh32Ux16)\
|
||||
SSA_OP(Rsh32Ux32)\
|
||||
SSA_OP(Rsh32Ux64)\
|
||||
SSA_OP(Rsh64Ux8)\
|
||||
SSA_OP(Rsh64Ux16)\
|
||||
SSA_OP(Rsh64Ux32)\
|
||||
SSA_OP(Rsh64Ux64)\
|
||||
\
|
||||
SSA_OP(Eq8)\
|
||||
SSA_OP(Eq16)\
|
||||
SSA_OP(Eq32)\
|
||||
SSA_OP(Eq64)\
|
||||
SSA_OP(EqPtr)\
|
||||
SSA_OP(Eq32F)\
|
||||
SSA_OP(Eq64F)\
|
||||
SSA_OP(Ne8)\
|
||||
SSA_OP(Ne16)\
|
||||
SSA_OP(Ne32)\
|
||||
SSA_OP(Ne64)\
|
||||
SSA_OP(NePtr)\
|
||||
SSA_OP(Ne32F)\
|
||||
SSA_OP(Ne64F)\
|
||||
SSA_OP(Lt8)\
|
||||
SSA_OP(Lt16)\
|
||||
SSA_OP(Lt32)\
|
||||
SSA_OP(Lt64)\
|
||||
SSA_OP(LtPtr)\
|
||||
SSA_OP(Lt32F)\
|
||||
SSA_OP(Lt64F)\
|
||||
SSA_OP(Gt8)\
|
||||
SSA_OP(Gt16)\
|
||||
SSA_OP(Gt32)\
|
||||
SSA_OP(Gt64)\
|
||||
SSA_OP(GtPtr)\
|
||||
SSA_OP(Gt32F)\
|
||||
SSA_OP(Gt64F)\
|
||||
SSA_OP(Le8)\
|
||||
SSA_OP(Le16)\
|
||||
SSA_OP(Le32)\
|
||||
SSA_OP(Le64)\
|
||||
SSA_OP(LePtr)\
|
||||
SSA_OP(Le32F)\
|
||||
SSA_OP(Le64F)\
|
||||
SSA_OP(Ge8)\
|
||||
SSA_OP(Ge16)\
|
||||
SSA_OP(Ge32)\
|
||||
SSA_OP(Ge64)\
|
||||
SSA_OP(GePtr)\
|
||||
SSA_OP(Ge32F)\
|
||||
SSA_OP(Ge64F)\
|
||||
\
|
||||
SSA_OP(NotB)\
|
||||
SSA_OP(EqB)\
|
||||
SSA_OP(NeB)\
|
||||
\
|
||||
SSA_OP(Neg8)\
|
||||
SSA_OP(Neg16)\
|
||||
SSA_OP(Neg32)\
|
||||
SSA_OP(Neg64)\
|
||||
SSA_OP(Neg32F)\
|
||||
SSA_OP(Neg64F)\
|
||||
\
|
||||
SSA_OP(Not8)\
|
||||
SSA_OP(Not16)\
|
||||
SSA_OP(Not32)\
|
||||
SSA_OP(Not64)\
|
||||
\
|
||||
SSA_OP(SignExt8to16)\
|
||||
SSA_OP(SignExt8to32)\
|
||||
SSA_OP(SignExt8to64)\
|
||||
SSA_OP(SignExt16to32)\
|
||||
SSA_OP(SignExt16to64)\
|
||||
SSA_OP(SignExt32to64)\
|
||||
SSA_OP(ZeroExt8to16)\
|
||||
SSA_OP(ZeroExt8to32)\
|
||||
SSA_OP(ZeroExt8to64)\
|
||||
SSA_OP(ZeroExt16to32)\
|
||||
SSA_OP(ZeroExt16to64)\
|
||||
SSA_OP(ZeroExt32to64)\
|
||||
SSA_OP(Trunc16to8)\
|
||||
SSA_OP(Trunc32to8)\
|
||||
SSA_OP(Trunc32to16)\
|
||||
SSA_OP(Trunc64to8)\
|
||||
SSA_OP(Trunc64to16)\
|
||||
SSA_OP(Trunc64to32)\
|
||||
\
|
||||
SSA_OP(Cvt32to32F)\
|
||||
SSA_OP(Cvt32to64F)\
|
||||
SSA_OP(Cvt64to32F)\
|
||||
SSA_OP(Cvt64to64F)\
|
||||
SSA_OP(Cvt32Fto32)\
|
||||
SSA_OP(Cvt32Fto64)\
|
||||
SSA_OP(Cvt64Fto32)\
|
||||
SSA_OP(Cvt64Fto64)\
|
||||
SSA_OP(Cvt32Fto64F)\
|
||||
SSA_OP(Cvt64Fto32F)\
|
||||
SSA_OP(Cvt32Uto32F)\
|
||||
SSA_OP(Cvt32Uto64F)\
|
||||
SSA_OP(Cvt32Fto32U)\
|
||||
SSA_OP(Cvt64Fto32U)\
|
||||
SSA_OP(Cvt64Uto32F)\
|
||||
SSA_OP(Cvt64Uto64F)\
|
||||
SSA_OP(Cvt32Fto64U)\
|
||||
SSA_OP(Cvt64Fto64U)\
|
||||
|
||||
|
||||
enum ssaOp {
|
||||
#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
|
||||
SSA_OPS
|
||||
#undef SSA_OP
|
||||
};
|
||||
|
||||
String const ssa_op_strings[] = {
|
||||
#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
||||
SSA_OPS
|
||||
#undef SSA_OP
|
||||
};
|
||||
+11
-28
@@ -180,17 +180,20 @@ template <isize N> bool operator >= (String const &a, char const (&b)[N]) { retu
|
||||
|
||||
|
||||
|
||||
gb_inline bool str_has_prefix(String s, String prefix) {
|
||||
isize i;
|
||||
if (prefix.len < s.len) {
|
||||
gb_inline bool string_starts_with(String s, String prefix) {
|
||||
if (prefix.len > s.len) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < prefix.len; i++) {
|
||||
if (s[i] != prefix[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return substring(s, 0, prefix.len) == prefix;
|
||||
}
|
||||
|
||||
gb_inline bool string_ends_with(String s, String suffix) {
|
||||
if (suffix.len > s.len) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return substring(s, s.len-suffix.len, s.len) == suffix;
|
||||
}
|
||||
|
||||
gb_inline isize string_extension_position(String str) {
|
||||
@@ -225,26 +228,6 @@ String string_trim_whitespace(String str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
gb_inline bool string_has_extension(String str, String ext) {
|
||||
str = string_trim_whitespace(str);
|
||||
if (str.len <= ext.len+1) {
|
||||
return false;
|
||||
}
|
||||
isize len = str.len;
|
||||
for (isize i = len-1; i >= 0; i--) {
|
||||
if (str[i] == '.') {
|
||||
break;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 *s = str.text + len;
|
||||
return gb_memcompare(s, ext.text, ext.len) == 0;
|
||||
}
|
||||
|
||||
bool string_contains_char(String s, u8 c) {
|
||||
isize i;
|
||||
for (i = 0; i < s.len; i++) {
|
||||
|
||||
+39
-11
@@ -104,16 +104,40 @@ void timings_start_section(Timings *t, String label) {
|
||||
array_add(&t->sections, make_time_stamp(label));
|
||||
}
|
||||
|
||||
f64 time_stamp_as_second(TimeStamp ts, u64 freq) {
|
||||
f64 time_stamp_as_s(TimeStamp const &ts, u64 freq) {
|
||||
GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label));
|
||||
return cast(f64)(ts.finish - ts.start) / cast(f64)freq;
|
||||
}
|
||||
|
||||
f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
|
||||
return 1000.0*time_stamp_as_second(ts, freq);
|
||||
f64 time_stamp_as_ms(TimeStamp const &ts, u64 freq) {
|
||||
return 1000.0*time_stamp_as_s(ts, freq);
|
||||
}
|
||||
|
||||
void timings_print_all(Timings *t) {
|
||||
f64 time_stamp_as_us(TimeStamp const &ts, u64 freq) {
|
||||
return 1000000.0*time_stamp_as_s(ts, freq);
|
||||
}
|
||||
|
||||
enum TimingUnit {
|
||||
TimingUnit_Second,
|
||||
TimingUnit_Millisecond,
|
||||
TimingUnit_Microsecond,
|
||||
|
||||
TimingUnit_COUNT,
|
||||
};
|
||||
|
||||
char const *timing_unit_strings[TimingUnit_COUNT] = {"s", "ms", "us"};
|
||||
|
||||
f64 time_stamp(TimeStamp const &ts, u64 freq, TimingUnit unit) {
|
||||
f64 total_time = 0;
|
||||
switch (unit) {
|
||||
case TimingUnit_Millisecond: return time_stamp_as_ms(ts, freq);
|
||||
case TimingUnit_Microsecond: return time_stamp_as_us(ts, freq);
|
||||
default: /*fallthrough*/
|
||||
case TimingUnit_Second: return time_stamp_as_s (ts, freq);
|
||||
}
|
||||
}
|
||||
|
||||
void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Millisecond) {
|
||||
char const SPACES[] = " ";
|
||||
isize max_len;
|
||||
|
||||
@@ -121,6 +145,7 @@ void timings_print_all(Timings *t) {
|
||||
t->total.finish = time_stamp_time_now();
|
||||
|
||||
max_len = t->total.label.len;
|
||||
max_len = 36;
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
max_len = gb_max(max_len, ts.label.len);
|
||||
@@ -128,22 +153,25 @@ void timings_print_all(Timings *t) {
|
||||
|
||||
GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
|
||||
|
||||
t->total_time_seconds = time_stamp_as_second(t->total, t->freq);
|
||||
t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
|
||||
|
||||
f64 total_ms = time_stamp_as_ms(t->total, t->freq);
|
||||
f64 total_time = time_stamp(t->total, t->freq, unit);
|
||||
|
||||
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
|
||||
gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
|
||||
LIT(t->total.label),
|
||||
cast(int)(max_len-t->total.label.len), SPACES,
|
||||
total_ms,
|
||||
total_time,
|
||||
timing_unit_strings[unit],
|
||||
cast(f64)100.0);
|
||||
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
f64 section_ms = time_stamp_as_ms(ts, t->freq);
|
||||
gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
|
||||
f64 section_time = time_stamp(ts, t->freq, unit);
|
||||
gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
|
||||
LIT(ts.label),
|
||||
cast(int)(max_len-ts.label.len), SPACES,
|
||||
section_ms, 100*section_ms/total_ms);
|
||||
section_time,
|
||||
timing_unit_strings[unit],
|
||||
100.0*section_time/total_time);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -105,12 +105,12 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_union, "union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
TOKEN_KIND(Token_cast, "cast"), \
|
||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||
TOKEN_KIND(Token_distinct, "distinct"), \
|
||||
TOKEN_KIND(Token_using, "using"), \
|
||||
TOKEN_KIND(Token_inline, "inline"), \
|
||||
TOKEN_KIND(Token_no_inline, "no_inline"), \
|
||||
@@ -120,6 +120,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
||||
TOKEN_KIND(Token_type_of, "type_of"), \
|
||||
TOKEN_KIND(Token_type_info_of, "type_info_of"), \
|
||||
TOKEN_KIND(Token_const, "const"), \
|
||||
TOKEN_KIND(Token_asm, "asm"), \
|
||||
TOKEN_KIND(Token_yield, "yield"), \
|
||||
TOKEN_KIND(Token_await, "await"), \
|
||||
@@ -169,8 +170,8 @@ bool operator>=(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a,
|
||||
|
||||
struct Token {
|
||||
TokenKind kind;
|
||||
String string;
|
||||
TokenPos pos;
|
||||
String string;
|
||||
TokenPos pos;
|
||||
};
|
||||
|
||||
Token empty_token = {Token_Invalid};
|
||||
|
||||
+113
-180
@@ -4,7 +4,13 @@ struct AstNode;
|
||||
enum BasicKind {
|
||||
Basic_Invalid,
|
||||
|
||||
Basic_llvm_bool,
|
||||
Basic_bool,
|
||||
Basic_b8,
|
||||
Basic_b16,
|
||||
Basic_b32,
|
||||
Basic_b64,
|
||||
|
||||
Basic_i8,
|
||||
Basic_u8,
|
||||
Basic_i16,
|
||||
@@ -13,8 +19,6 @@ enum BasicKind {
|
||||
Basic_u32,
|
||||
Basic_i64,
|
||||
Basic_u64,
|
||||
Basic_i128,
|
||||
Basic_u128,
|
||||
|
||||
Basic_rune,
|
||||
|
||||
@@ -80,7 +84,6 @@ struct TypeStruct {
|
||||
bool are_offsets_set;
|
||||
bool are_offsets_being_processed;
|
||||
bool is_packed;
|
||||
bool is_ordered;
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
@@ -94,6 +97,11 @@ struct TypeStruct {
|
||||
|
||||
#define TYPE_KINDS \
|
||||
TYPE_KIND(Basic, BasicType) \
|
||||
TYPE_KIND(Named, struct { \
|
||||
String name; \
|
||||
Type * base; \
|
||||
Entity *type_name; /* Entity_TypeName */ \
|
||||
}) \
|
||||
TYPE_KIND(Generic, struct { \
|
||||
i64 id; \
|
||||
String name; \
|
||||
@@ -106,13 +114,16 @@ struct TypeStruct {
|
||||
i64 count; \
|
||||
Type *generic_type; \
|
||||
}) \
|
||||
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
||||
TYPE_KIND(Vector, struct { \
|
||||
Type *elem; \
|
||||
i64 count; \
|
||||
Type *generic_type; \
|
||||
}) \
|
||||
TYPE_KIND(Slice, struct { Type *elem; }) \
|
||||
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
|
||||
TYPE_KIND(Map, struct { \
|
||||
Type * key; \
|
||||
Type * value; \
|
||||
Type * entry_type; \
|
||||
Type * generated_struct_type; \
|
||||
Type * internal_type; \
|
||||
Type * lookup_result_type; \
|
||||
}) \
|
||||
TYPE_KIND(Struct, TypeStruct) \
|
||||
TYPE_KIND(Enum, struct { \
|
||||
Entity **fields; \
|
||||
@@ -121,6 +132,7 @@ struct TypeStruct {
|
||||
Scope * scope; \
|
||||
Entity * names; \
|
||||
Type * base_type; \
|
||||
bool is_export; \
|
||||
Entity * count; \
|
||||
Entity * min_value; \
|
||||
Entity * max_value; \
|
||||
@@ -131,11 +143,7 @@ struct TypeStruct {
|
||||
Scope * scope; \
|
||||
i64 variant_block_size; \
|
||||
i64 custom_align; \
|
||||
}) \
|
||||
TYPE_KIND(Named, struct { \
|
||||
String name; \
|
||||
Type * base; \
|
||||
Entity *type_name; /* Entity_TypeName */ \
|
||||
i64 tag_size; \
|
||||
}) \
|
||||
TYPE_KIND(Tuple, struct { \
|
||||
Array<Entity *> variables; /* Entity_Variable */ \
|
||||
@@ -159,16 +167,10 @@ struct TypeStruct {
|
||||
bool is_polymorphic; \
|
||||
bool is_poly_specialized; \
|
||||
bool has_proc_default_values; \
|
||||
bool has_named_results; \
|
||||
isize specialization_count; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
}) \
|
||||
TYPE_KIND(Map, struct { \
|
||||
Type * key; \
|
||||
Type * value; \
|
||||
Type * entry_type; \
|
||||
Type * generated_struct_type; \
|
||||
Type * lookup_result_type; \
|
||||
}) \
|
||||
TYPE_KIND(BitFieldValue, struct { u32 bits; }) \
|
||||
TYPE_KIND(BitField, struct { \
|
||||
Scope * scope; \
|
||||
@@ -207,12 +209,16 @@ struct Type {
|
||||
TYPE_KINDS
|
||||
#undef TYPE_KIND
|
||||
};
|
||||
|
||||
// NOTE(bill): These need to be at the end to not affect the unionized data
|
||||
i64 cached_size;
|
||||
i64 cached_align;
|
||||
bool failure;
|
||||
};
|
||||
|
||||
|
||||
// TODO(bill): Should I add extra information here specifying the kind of selection?
|
||||
// e.g. field, constant, vector field, type field, etc.
|
||||
// e.g. field, constant, array field, type field, etc.
|
||||
struct Selection {
|
||||
Entity * entity;
|
||||
Array<i32> index;
|
||||
@@ -240,7 +246,13 @@ void selection_add_index(Selection *s, isize index) {
|
||||
gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}},
|
||||
|
||||
{Type_Basic, {Basic_llvm_bool, BasicFlag_Boolean, 1, STR_LIT("llvm bool")}},
|
||||
|
||||
{Type_Basic, {Basic_bool, BasicFlag_Boolean, 1, STR_LIT("bool")}},
|
||||
{Type_Basic, {Basic_b8, BasicFlag_Boolean, 1, STR_LIT("b8")}},
|
||||
{Type_Basic, {Basic_b16, BasicFlag_Boolean, 2, STR_LIT("b16")}},
|
||||
{Type_Basic, {Basic_b32, BasicFlag_Boolean, 4, STR_LIT("b32")}},
|
||||
{Type_Basic, {Basic_b64, BasicFlag_Boolean, 8, STR_LIT("b64")}},
|
||||
|
||||
{Type_Basic, {Basic_i8, BasicFlag_Integer, 1, STR_LIT("i8")}},
|
||||
{Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("u8")}},
|
||||
@@ -250,8 +262,6 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, 4, STR_LIT("u32")}},
|
||||
{Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}},
|
||||
{Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}},
|
||||
{Type_Basic, {Basic_i128, BasicFlag_Integer, 16, STR_LIT("i128")}},
|
||||
{Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, 16, STR_LIT("u128")}},
|
||||
|
||||
{Type_Basic, {Basic_rune, BasicFlag_Integer | BasicFlag_Rune, 4, STR_LIT("rune")}},
|
||||
|
||||
@@ -287,6 +297,7 @@ gb_global Type basic_types[] = {
|
||||
// };
|
||||
|
||||
gb_global Type *t_invalid = &basic_types[Basic_Invalid];
|
||||
gb_global Type *t_llvm_bool = &basic_types[Basic_llvm_bool];
|
||||
gb_global Type *t_bool = &basic_types[Basic_bool];
|
||||
gb_global Type *t_i8 = &basic_types[Basic_i8];
|
||||
gb_global Type *t_u8 = &basic_types[Basic_u8];
|
||||
@@ -296,8 +307,6 @@ gb_global Type *t_i32 = &basic_types[Basic_i32];
|
||||
gb_global Type *t_u32 = &basic_types[Basic_u32];
|
||||
gb_global Type *t_i64 = &basic_types[Basic_i64];
|
||||
gb_global Type *t_u64 = &basic_types[Basic_u64];
|
||||
gb_global Type *t_i128 = &basic_types[Basic_i128];
|
||||
gb_global Type *t_u128 = &basic_types[Basic_u128];
|
||||
|
||||
gb_global Type *t_rune = &basic_types[Basic_rune];
|
||||
|
||||
@@ -327,10 +336,10 @@ gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
|
||||
gb_global Type *t_untyped_undef = &basic_types[Basic_UntypedUndef];
|
||||
|
||||
|
||||
|
||||
gb_global Type *t_u8_ptr = nullptr;
|
||||
gb_global Type *t_int_ptr = nullptr;
|
||||
gb_global Type *t_i64_ptr = nullptr;
|
||||
gb_global Type *t_i128_ptr = nullptr;
|
||||
gb_global Type *t_f64_ptr = nullptr;
|
||||
gb_global Type *t_u8_slice = nullptr;
|
||||
gb_global Type *t_string_slice = nullptr;
|
||||
@@ -355,7 +364,6 @@ gb_global Type *t_type_info_procedure = nullptr;
|
||||
gb_global Type *t_type_info_array = nullptr;
|
||||
gb_global Type *t_type_info_dynamic_array = nullptr;
|
||||
gb_global Type *t_type_info_slice = nullptr;
|
||||
gb_global Type *t_type_info_vector = nullptr;
|
||||
gb_global Type *t_type_info_tuple = nullptr;
|
||||
gb_global Type *t_type_info_struct = nullptr;
|
||||
gb_global Type *t_type_info_union = nullptr;
|
||||
@@ -377,7 +385,6 @@ gb_global Type *t_type_info_procedure_ptr = nullptr;
|
||||
gb_global Type *t_type_info_array_ptr = nullptr;
|
||||
gb_global Type *t_type_info_dynamic_array_ptr = nullptr;
|
||||
gb_global Type *t_type_info_slice_ptr = nullptr;
|
||||
gb_global Type *t_type_info_vector_ptr = nullptr;
|
||||
gb_global Type *t_type_info_tuple_ptr = nullptr;
|
||||
gb_global Type *t_type_info_struct_ptr = nullptr;
|
||||
gb_global Type *t_type_info_union_ptr = nullptr;
|
||||
@@ -466,6 +473,8 @@ Type *alloc_type(gbAllocator a, TypeKind kind) {
|
||||
Type *t = gb_alloc_item(a, Type);
|
||||
gb_zero_item(t);
|
||||
t->kind = kind;
|
||||
t->cached_size = -1;
|
||||
t->cached_align = -1;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -505,14 +514,6 @@ Type *make_type_dynamic_array(gbAllocator a, Type *elem) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_vector(gbAllocator a, Type *elem, i64 count, Type *generic_type = nullptr) {
|
||||
Type *t = alloc_type(a, Type_Vector);
|
||||
t->Vector.elem = elem;
|
||||
t->Vector.count = count;
|
||||
t->Vector.generic_type = generic_type;
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_slice(gbAllocator a, Type *elem) {
|
||||
Type *t = alloc_type(a, Type_Slice);
|
||||
t->Array.elem = elem;
|
||||
@@ -672,14 +673,9 @@ bool is_type_numeric(Type *t) {
|
||||
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
||||
}
|
||||
// TODO(bill): Should this be here?
|
||||
if (t->kind == Type_Vector) {
|
||||
return is_type_numeric(t->Vector.elem);
|
||||
}
|
||||
#if defined(ALLOW_ARRAY_PROGRAMMING)
|
||||
if (t->kind == Type_Array) {
|
||||
return is_type_numeric(t->Array.elem);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
bool is_type_string(Type *t) {
|
||||
@@ -713,8 +709,6 @@ bool is_type_ordered(Type *t) {
|
||||
return (t->Basic.flags & BasicFlag_Ordered) != 0;
|
||||
case Type_Pointer:
|
||||
return true;
|
||||
case Type_Vector:
|
||||
return is_type_ordered(t->Vector.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -772,12 +766,6 @@ bool is_type_uintptr(Type *t) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_i128_or_u128(Type *t) {
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.kind == Basic_i128) || (t->Basic.kind == Basic_u128);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_rawptr(Type *t) {
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_rawptr;
|
||||
@@ -809,10 +797,6 @@ bool is_type_u8_slice(Type *t) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_vector(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Vector;
|
||||
}
|
||||
bool is_type_proc(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Proc;
|
||||
@@ -821,13 +805,6 @@ bool is_type_poly_proc(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Proc && t->Proc.is_polymorphic;
|
||||
}
|
||||
Type *base_vector_type(Type *t) {
|
||||
if (is_type_vector(t)) {
|
||||
t = base_type(t);
|
||||
return t->Vector.elem;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
Type *base_array_type(Type *t) {
|
||||
if (is_type_array(t)) {
|
||||
t = base_type(t);
|
||||
@@ -842,11 +819,10 @@ bool is_type_generic(Type *t) {
|
||||
}
|
||||
|
||||
|
||||
Type *core_array_or_vector_type(Type *t) {
|
||||
Type *core_array_type(Type *t) {
|
||||
for (;;) {
|
||||
Type *prev = t;
|
||||
t = base_array_type(t);
|
||||
t = base_vector_type(t);
|
||||
if (prev == t) break;
|
||||
}
|
||||
return t;
|
||||
@@ -949,7 +925,17 @@ bool is_type_valid_for_keys(Type *t) {
|
||||
|
||||
|
||||
bool is_type_indexable(Type *t) {
|
||||
return is_type_array(t) || is_type_slice(t) || is_type_vector(t) || is_type_string(t);
|
||||
Type *bt = base_type(t);
|
||||
switch (bt->kind) {
|
||||
case Type_Basic:
|
||||
return is_type_string(bt);
|
||||
case Type_Array:
|
||||
case Type_Slice:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_type_polymorphic_struct(Type *t) {
|
||||
@@ -984,8 +970,6 @@ bool is_type_polymorphic(Type *t) {
|
||||
return true;
|
||||
}
|
||||
return is_type_polymorphic(t->Array.elem);
|
||||
case Type_Vector:
|
||||
return is_type_polymorphic(t->Vector.elem);
|
||||
case Type_DynamicArray:
|
||||
return is_type_polymorphic(t->DynamicArray.elem);
|
||||
case Type_Slice:
|
||||
@@ -1112,8 +1096,6 @@ bool is_type_comparable(Type *t) {
|
||||
return is_type_comparable(core_type(t));
|
||||
case Type_Array:
|
||||
return is_type_comparable(t->Array.elem);
|
||||
case Type_Vector:
|
||||
return is_type_comparable(t->Vector.elem);
|
||||
case Type_Proc:
|
||||
return true;
|
||||
}
|
||||
@@ -1155,12 +1137,6 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
if (y->kind == Type_Vector) {
|
||||
return (x->Vector.count == y->Vector.count) && are_types_identical(x->Vector.elem, y->Vector.elem);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
if (y->kind == Type_Slice) {
|
||||
return are_types_identical(x->Slice.elem, y->Slice.elem);
|
||||
@@ -1209,7 +1185,6 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
|
||||
x->Struct.fields.count == y->Struct.fields.count &&
|
||||
x->Struct.is_packed == y->Struct.is_packed &&
|
||||
x->Struct.is_ordered == y->Struct.is_ordered &&
|
||||
x->Struct.custom_align == y->Struct.custom_align) {
|
||||
// TODO(bill); Fix the custom alignment rule
|
||||
for_array(i, x->Struct.fields) {
|
||||
@@ -1293,7 +1268,6 @@ Type *default_bit_field_value_type(Type *type) {
|
||||
case 16: return t_u16;
|
||||
case 32: return t_u32;
|
||||
case 64: return t_u64;
|
||||
case 128: return t_u128;
|
||||
default: GB_PANIC("Too big of a bit size!"); break;
|
||||
}
|
||||
}
|
||||
@@ -1344,9 +1318,6 @@ bool is_type_cte_safe(Type *type) {
|
||||
case Type_Map:
|
||||
return false;
|
||||
|
||||
case Type_Vector: // NOTE(bill): This should always to be true but this is for sanity reasons
|
||||
return is_type_cte_safe(type->Vector.elem);
|
||||
|
||||
case Type_Slice:
|
||||
return false;
|
||||
|
||||
@@ -1395,25 +1366,35 @@ i64 union_variant_index(Type *u, Type *v) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
i64 union_tag_size(Type *u) {
|
||||
i64 union_tag_size(gbAllocator a, Type *u) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
u64 cl2 = ceil_log2(cast(u64)u->Union.variants.count);
|
||||
i64 s = (next_pow2(cast(i64)cl2) + 7)/8;
|
||||
return gb_clamp(s, 1, build_context.word_size);
|
||||
if (u->Union.tag_size > 0) {
|
||||
return u->Union.tag_size;
|
||||
}
|
||||
|
||||
u64 n = cast(u64)u->Union.variants.count;
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
i64 bytes = next_pow2(cast(i64)(floor_log2(n)/8 + 1));
|
||||
i64 tag_size = gb_max(bytes, 1);
|
||||
|
||||
u->Union.tag_size = tag_size;
|
||||
return tag_size;
|
||||
}
|
||||
|
||||
Type *union_tag_type(Type *u) {
|
||||
i64 s = union_tag_size(u);
|
||||
Type *union_tag_type(gbAllocator a, Type *u) {
|
||||
i64 s = union_tag_size(a, u);
|
||||
switch (s) {
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
case 8: return t_u64;
|
||||
case 16: return t_u128;
|
||||
}
|
||||
GB_PANIC("Invalid union_tag_size");
|
||||
return t_int;
|
||||
return t_uint;
|
||||
}
|
||||
|
||||
|
||||
@@ -1608,26 +1589,26 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
||||
}
|
||||
|
||||
return sel;
|
||||
} else if (type->kind == Type_Vector) {
|
||||
if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) {
|
||||
} else if (type->kind == Type_Array) {
|
||||
if (type->Array.count <= 4) {
|
||||
// HACK(bill): Memory leak
|
||||
switch (type->Vector.count) {
|
||||
#define _VECTOR_FIELD_CASE(_length, _name) \
|
||||
switch (type->Array.count) {
|
||||
#define _ARRAY_FIELD_CASE(_length, _name) \
|
||||
case (_length): \
|
||||
if (field_name == _name) { \
|
||||
selection_add_index(&sel, (_length)-1); \
|
||||
sel.entity = make_entity_vector_elem(a, nullptr, make_token_ident(str_lit(_name)), type->Vector.elem, (_length)-1); \
|
||||
sel.entity = make_entity_array_elem(a, nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
|
||||
return sel; \
|
||||
} \
|
||||
/*fallthrough*/
|
||||
|
||||
_VECTOR_FIELD_CASE(4, "w");
|
||||
_VECTOR_FIELD_CASE(3, "z");
|
||||
_VECTOR_FIELD_CASE(2, "y");
|
||||
_VECTOR_FIELD_CASE(1, "x");
|
||||
_ARRAY_FIELD_CASE(4, "w");
|
||||
_ARRAY_FIELD_CASE(3, "z");
|
||||
_ARRAY_FIELD_CASE(2, "y");
|
||||
_ARRAY_FIELD_CASE(1, "x");
|
||||
default: break;
|
||||
|
||||
#undef _VECTOR_FIELD_CASE
|
||||
#undef _ARRAY_FIELD_CASE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1812,36 +1793,37 @@ void type_path_pop(TypePath *tp) {
|
||||
i64 type_size_of_internal (gbAllocator allocator, Type *t, TypePath *path);
|
||||
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path);
|
||||
|
||||
i64 align_formula(i64 size, i64 align) {
|
||||
if (align > 0) {
|
||||
i64 result = size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
i64 type_size_of(gbAllocator allocator, Type *t) {
|
||||
if (t == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
i64 size;
|
||||
// NOTE(bill): Always calculate the size when it is a Type_Basic
|
||||
if (t->kind != Type_Basic && t->cached_size >= 0) {
|
||||
return t->cached_size;
|
||||
}
|
||||
TypePath path = {0};
|
||||
type_path_init(&path);
|
||||
size = type_size_of_internal(allocator, t, &path);
|
||||
t->cached_size = type_size_of_internal(allocator, t, &path);
|
||||
type_path_free(&path);
|
||||
return size;
|
||||
return t->cached_size;
|
||||
}
|
||||
|
||||
i64 type_align_of(gbAllocator allocator, Type *t) {
|
||||
if (t == nullptr) {
|
||||
return 1;
|
||||
}
|
||||
i64 align;
|
||||
// NOTE(bill): Always calculate the size when it is a Type_Basic
|
||||
if (t->kind != Type_Basic && t->cached_align > 0) {
|
||||
return t->cached_align;
|
||||
}
|
||||
|
||||
TypePath path = {0};
|
||||
type_path_init(&path);
|
||||
align = type_align_of_internal(allocator, t, &path);
|
||||
t->cached_align = type_align_of_internal(allocator, t, &path);
|
||||
type_path_free(&path);
|
||||
return align;
|
||||
return t->cached_align;
|
||||
}
|
||||
|
||||
|
||||
@@ -1878,18 +1860,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (pop) type_path_pop(path);
|
||||
return align;
|
||||
}
|
||||
case Type_Vector: {
|
||||
Type *elem = t->Vector.elem;
|
||||
bool pop = type_path_push(path, elem);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
|
||||
if (pop) type_path_pop(path);
|
||||
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
|
||||
i64 total = size * count;
|
||||
return gb_clamp(total, 1, build_context.max_align);
|
||||
} break;
|
||||
|
||||
case Type_DynamicArray:
|
||||
// data, count, capacity, allocator
|
||||
@@ -1912,8 +1882,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
|
||||
case Type_Map:
|
||||
generate_map_internal_types(allocator, t);
|
||||
return type_align_of_internal(allocator, t->Map.generated_struct_type, path);
|
||||
|
||||
return type_align_of_internal(allocator, t->Map.internal_type, path);
|
||||
case Type_Enum:
|
||||
return type_align_of_internal(allocator, t->Enum.base_type, path);
|
||||
|
||||
@@ -1925,7 +1894,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
return gb_clamp(t->Union.custom_align, 1, build_context.max_align);
|
||||
}
|
||||
|
||||
i64 max = union_tag_size(t);
|
||||
i64 max = 1;
|
||||
for_array(i, t->Union.variants) {
|
||||
Type *variant = t->Union.variants[i];
|
||||
bool pop = type_path_push(path, variant);
|
||||
@@ -2011,8 +1980,9 @@ Array<i64> type_set_offsets_of(gbAllocator allocator, Array<Entity *> fields, bo
|
||||
}
|
||||
} else {
|
||||
for_array(i, fields) {
|
||||
i64 align = gb_max(type_align_of(allocator, fields[i]->type), 1);
|
||||
i64 size = gb_max(type_size_of(allocator, fields[i]->type), 0);
|
||||
Type *t = fields[i]->type;
|
||||
i64 align = gb_max(type_align_of(allocator, t), 1);
|
||||
i64 size = gb_max(type_size_of(allocator, t), 0);
|
||||
curr_offset = align_formula(curr_offset, align);
|
||||
offsets[i] = curr_offset;
|
||||
curr_offset += size;
|
||||
@@ -2027,6 +1997,7 @@ bool type_set_offsets(gbAllocator allocator, Type *t) {
|
||||
if (!t->Struct.are_offsets_set) {
|
||||
t->Struct.are_offsets_being_processed = true;
|
||||
t->Struct.offsets = type_set_offsets_of(allocator, t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union);
|
||||
t->Struct.are_offsets_being_processed = false;
|
||||
t->Struct.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
@@ -2034,6 +2005,7 @@ bool type_set_offsets(gbAllocator allocator, Type *t) {
|
||||
if (!t->Tuple.are_offsets_set) {
|
||||
t->Struct.are_offsets_being_processed = true;
|
||||
t->Tuple.offsets = type_set_offsets_of(allocator, t->Tuple.variables, false, false);
|
||||
t->Struct.are_offsets_being_processed = false;
|
||||
t->Tuple.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
@@ -2075,6 +2047,9 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case Type_Pointer:
|
||||
return build_context.word_size;
|
||||
|
||||
case Type_Array: {
|
||||
i64 count, align, size, alignment;
|
||||
count = t->Array.count;
|
||||
@@ -2090,45 +2065,8 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
return alignment*(count-1) + size;
|
||||
} break;
|
||||
|
||||
case Type_Vector: {
|
||||
#if 0
|
||||
i64 count, bit_size, total_size_in_bits, total_size;
|
||||
count = t->Vector.count;
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
bool pop = type_path_push(path, t->Vector.elem);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path);
|
||||
if (pop) type_path_pop(path);
|
||||
if (is_type_boolean(t->Vector.elem)) {
|
||||
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
|
||||
// Silly LLVM spec
|
||||
}
|
||||
total_size_in_bits = bit_size * count;
|
||||
total_size = (total_size_in_bits+7)/8;
|
||||
return total_size;
|
||||
#else
|
||||
i64 count = t->Vector.count;
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
i64 elem_align = type_align_of_internal(allocator, t->Vector.elem, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
i64 vector_align = type_align_of_internal(allocator, t, path);
|
||||
i64 elem_size = type_size_of_internal(allocator, t->Vector.elem, path);
|
||||
i64 alignment = align_formula(elem_size, elem_align);
|
||||
return align_formula(alignment*(count-1) + elem_size, vector_align);
|
||||
#endif
|
||||
} break;
|
||||
|
||||
|
||||
case Type_Slice: // ptr + count
|
||||
return 3 * build_context.word_size;
|
||||
case Type_Slice: // ptr + len
|
||||
return 2 * build_context.word_size;
|
||||
|
||||
case Type_DynamicArray:
|
||||
// data + len + cap + allocator(procedure+data)
|
||||
@@ -2136,7 +2074,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
|
||||
case Type_Map:
|
||||
generate_map_internal_types(allocator, t);
|
||||
return type_size_of_internal(allocator, t->Map.generated_struct_type, path);
|
||||
return type_size_of_internal(allocator, t->Map.internal_type, path);
|
||||
|
||||
case Type_Tuple: {
|
||||
i64 count, align, size;
|
||||
@@ -2174,14 +2112,13 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
}
|
||||
|
||||
// NOTE(bill): Align to tag
|
||||
i64 tag_size = union_tag_size(t);
|
||||
i64 tag_size = union_tag_size(allocator, t);
|
||||
i64 size = align_formula(max, tag_size);
|
||||
// NOTE(bill): Calculate the padding between the common fields and the tag
|
||||
t->Union.tag_size = tag_size;
|
||||
t->Union.variant_block_size = size - field_size;
|
||||
|
||||
size += tag_size;
|
||||
size = align_formula(size, align);
|
||||
return size;
|
||||
return align_formula(size + tag_size, align);
|
||||
} break;
|
||||
|
||||
|
||||
@@ -2202,11 +2139,13 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
// TODO(bill): Is this how it should work?
|
||||
return align_formula(max, align);
|
||||
} else {
|
||||
i64 count = t->Struct.fields.count;
|
||||
i64 count = 0, size = 0, align = 0;
|
||||
|
||||
count = t->Struct.fields.count;
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
}
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
@@ -2215,7 +2154,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
type_set_offsets(allocator, t);
|
||||
i64 size = t->Struct.offsets[count-1] + type_size_of_internal(allocator, t->Struct.fields[count-1]->type, path);
|
||||
size = t->Struct.offsets[count-1] + type_size_of_internal(allocator, t->Struct.fields[count-1]->type, path);
|
||||
return align_formula(size, align);
|
||||
}
|
||||
} break;
|
||||
@@ -2366,11 +2305,6 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
str = write_type_to_string(str, type->Array.elem);
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
str = gb_string_appendc(str, gb_bprintf("[vector %d]", cast(int)type->Vector.count));
|
||||
str = write_type_to_string(str, type->Vector.elem);
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
str = gb_string_appendc(str, "[]");
|
||||
str = write_type_to_string(str, type->Array.elem);
|
||||
@@ -2413,7 +2347,6 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
case Type_Struct: {
|
||||
str = gb_string_appendc(str, "struct");
|
||||
if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed");
|
||||
if (type->Struct.is_ordered) str = gb_string_appendc(str, " #ordered");
|
||||
if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union");
|
||||
str = gb_string_appendc(str, " {");
|
||||
for_array(i, type->Struct.fields) {
|
||||
|
||||
Reference in New Issue
Block a user