Compare commits

...

135 Commits

Author SHA1 Message Date
gingerBill 14eeee40b2 Update demo.odin 2018-02-11 11:16:17 +00:00
gingerBill 038dea9202 v0.8.1
Fix initialization values for variables
2018-02-11 11:15:53 +00:00
gingerBill 0ae3484171 Fix zero value initialization in IR 2018-02-11 11:13:52 +00:00
gingerBill 54976c3249 v0.8.0 2018-02-09 18:03:06 +00:00
gingerBill 8f913c656c Fix error reporting for assignment to a built-in procedure (#183) 2018-02-07 18:55:01 +00:00
gingerBill 001b48a5c6 Change local variable alignment to 16 bytes for the time being 2018-02-05 23:27:18 +00:00
gingerBill 54929a1b92 Minor context fix 2018-02-05 23:09:34 +00:00
gingerBill 92780e2683 distinct keyword for type declarations 2018-02-05 22:46:30 +00:00
gingerBill 2891988d3b Add extra check to ir_emit_zero_init 2018-02-05 22:26:22 +00:00
gingerBill c1728914c6 Fix typos #type_alias 2018-02-04 21:34:45 +00:00
gingerBill ed2f49e8d2 Remove dead code; Fix issue regarding order of evaluation of function parameters (in C++) depending on the compiler (clang vs gcc vs msvc) 2018-02-04 20:07:05 +00:00
gingerBill 8a76a370a9 Merge pull request #182 from ThisDrunkDane/master
Functions, structs and constants related to getting file notifications
2018-02-04 19:49:04 +00:00
Mikkel Hjortshoej 1160fd4331 functions, structs and constants related to getting file notifications 2018-02-03 21:56:15 +01:00
gingerBill 0134c38759 Fix issue #181 2018-02-03 10:32:47 +00:00
gingerBill d079095517 Fix bug #179 2018-02-03 10:27:33 +00:00
gingerBill 028d628e9f Add extra zero init for IR 2018-01-31 18:27:08 +00:00
gingerBill 5e4b62acfe Fix literal 2018-01-28 15:59:37 +00:00
gingerBill 9366fa8e95 Simplify printing for float and complex types 2018-01-28 15:58:34 +00:00
gingerBill 369db3a8e3 Add __print_type to runtime 2018-01-28 15:55:37 +00:00
gingerBill 8c360b2a3c Reduce type info data size in IR 2018-01-28 15:43:58 +00:00
gingerBill b66e7bed45 Improve min-dep for Type Info 2018-01-28 15:37:15 +00:00
gingerBill e919482aa8 Add ir_emit_store_union_variant to reduce alloca use 2018-01-28 15:09:07 +00:00
gingerBill dce45e7d58 Add ODIN_DEBUG 2018-01-28 14:42:22 +00:00
gingerBill 1a0877e965 Fix minimum dependency generation for foreign entities 2018-01-28 14:39:18 +00:00
gingerBill 0361a18551 Remove old math constants 2018-01-28 11:59:28 +00:00
gingerBill 83d90f1463 Extra check for type_info cycle checking 2018-01-28 09:51:52 +00:00
gingerBill f661ae9d09 Fix issue with proc group cycles #176 2018-01-28 09:19:23 +00:00
gingerBill bee4cb57f2 Fix printf bug #177 2018-01-28 09:13:29 +00:00
gingerBill 53b670b889 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-01-28 08:59:31 +00:00
gingerBill e2600a3e44 Fix #178 2018-01-28 08:59:10 +00:00
gingerBill 25101b2ae0 Merge pull request #175 from ThisDrunkDane/windows.odin-adds
More file handling functions
2018-01-25 14:02:32 +00:00
Mikkel Hjortshoej 4e7867fcc1 More file handling functions 2018-01-25 00:00:34 +01:00
gingerBill 101ee64165 Merge pull request #174 from ThisDrunkDane/windows.odin-adds
Added stuff to windows.odin
2018-01-24 09:41:09 +00:00
Mikkel Hjortshoej 4c3e65791e added stuff to windows.odin 2018-01-24 07:26:29 +01:00
gingerBill a9c8031b61 Fix sync_windows.odin 2018-01-21 21:21:57 +00:00
gingerBill afb3033913 Change thread.odin to use a rawptr rather than any 2018-01-21 21:19:03 +00:00
gingerBill 2ad26640a2 Revert back to gb_memmove 2018-01-21 19:30:05 +00:00
gingerBill 2c0b08145f Fix nested defer blocks 2018-01-21 19:26:55 +00:00
gingerBill aa9c9eda9e Fix boolean casting 2018-01-21 18:41:21 +00:00
gingerBill 1353d61894 Minor parsing change 2018-01-21 16:45:29 +00:00
gingerBill 88ba6d8015 enum #export 2018-01-21 14:30:48 +00:00
gingerBill 8b288a2072 Reimplement opt stage 2018-01-20 16:16:59 +00:00
gingerBill 4e90644527 Remove timing for llvm-opt 2018-01-20 16:15:05 +00:00
gingerBill 6651b65373 Remove need for opt 2018-01-20 16:13:36 +00:00
gingerBill 705352099f Remove #endif 2018-01-20 16:10:26 +00:00
gingerBill 2e28c9d793 Cache type size/align; Improve speed of ir_print.cpp 2018-01-20 15:12:44 +00:00
gingerBill 2fe660a1d7 Fix empty union IR bug 2018-01-19 17:11:28 +00:00
gingerBill b03ce0e9b4 Modify implicit semicolon rules 2018-01-18 17:28:07 +00:00
gingerBill 386f5f596d Change to HeapAlloc et al on Windows 2018-01-18 13:11:51 +00:00
gingerBill add53228b2 -no-bounds-check 2018-01-18 12:22:27 +00:00
gingerBill d90008cc52 Add basic debug information needed for stepping over code 2018-01-18 12:12:18 +00:00
gingerBill dbf8f9ab38 Add extra comments for clarity 2018-01-17 21:22:45 +00:00
gingerBill 81a99cf67b Debug fix target triple and procedure positioning 2018-01-17 20:57:54 +00:00
gingerBill 876af6fb02 Modify boolean conversion in IR 2018-01-17 19:27:13 +00:00
gingerBill b3734a5f77 Add math/rand.odin 2018-01-17 19:09:22 +00:00
gingerBill 419ab6f00c Named return value act as variables; Code reorganization 2018-01-17 19:07:38 +00:00
gingerBill 5558b55e9f Fix ir_emit_store for booleans 2018-01-17 14:06:06 +00:00
gingerBill 4b14d608f4 Update sys/windows.odin to use Bool :: b32; rather than i32 2018-01-17 14:02:19 +00:00
gingerBill 9428d86f2b Specific sized booleans: b8, b16, b32, b64 2018-01-17 14:00:49 +00:00
gingerBill ddebf0daf2 Merge branch 'master' of https://github.com/odin-lang/Odin 2018-01-17 13:16:59 +00:00
gingerBill 3a44c62ecf Remove old "macro" parsing code 2018-01-17 13:16:43 +00:00
gingerBill 184efd4f49 Update demo for using in 2018-01-13 22:42:05 +00:00
gingerBill 6b3c4cc379 Remove u128 and i128 2018-01-13 22:26:37 +00:00
gingerBill 0b137e087c Fix mem.odin #173 2018-01-12 11:44:09 +00:00
gingerBill 37790c13a0 Fix issue #170 2018-01-10 21:17:09 +00:00
gingerBill 82057f08ce Fix issue #172 2018-01-10 21:13:20 +00:00
gingerBill 1553421e1a Fix typo in error 2018-01-01 22:15:43 +00:00
gingerBill f3ea109e6f Fix min/max for floats 2018-01-01 11:41:32 +00:00
gingerBill 90dbfe7660 Fix issue #167 regarding abs, min, and, max for floats 2017-12-27 20:35:50 +00:00
gingerBill 125bad3154 Fix 'llvm bool' emit store 2017-12-23 09:46:28 +00:00
gingerBill 30c83d6c81 Fix map internals 2017-12-23 09:30:40 +00:00
gingerBill 4f12c118a5 Fix Type info bug for 'llvm bool' 2017-12-23 09:06:49 +00:00
gingerBill 423775d50e Merge branch 'master' of https://github.com/odin-lang/Odin 2017-12-22 18:14:50 +00:00
gingerBill 860a5c3e86 "Fix" LLVM boolean bug (more like a bodge) 2017-12-22 18:14:35 +00:00
gingerBill 649e02f209 Add basic example to README.md 2017-12-22 11:29:33 +00:00
gingerBill b449305cc1 Fix free_map 2017-12-21 21:05:53 +00:00
gingerBill 49bee6bad0 Fix free_map 2017-12-21 21:01:28 +00:00
gingerBill ac277a1cce Revert map to be a value type and not a reference type
(Implement code for "const ref" parameters)
2017-12-21 20:59:23 +00:00
gingerBill a17310a83c Fix len, cap, comparison against nil for map 2017-12-18 20:43:02 +00:00
gingerBill b509946b13 Fix fallthrough within a nested block 2017-12-17 21:55:20 +00:00
gingerBill a69ea58388 map is internally backed by a pointer (i.e. a "reference type") 2017-12-17 19:25:35 +00:00
gingerBill 30530d058c Remove struct #ordered 2017-12-17 14:53:40 +00:00
gingerBill 436928d06a Fix "using in import" 2017-12-17 12:12:24 +00:00
gingerBill 32a502d14e using x in bar; 2017-12-17 11:44:26 +00:00
gingerBill 0d665c637f using in importation statements 2017-12-17 11:17:54 +00:00
gingerBill 1b6a14ac39 Fix lhs < rhs bug (#164) 2017-12-14 19:56:32 +00:00
gingerBill 367013f589 Change Map and PtrSet grow rate 2017-12-12 23:39:20 +00:00
gingerBill c980a30bad Merge branch 'checker-optimizations' into explicit-overloading
# Conflicts:
#	examples/demo.odin
2017-12-12 21:22:46 +00:00
gingerBill 78b459590c Print nil for nil procedures in fmt.odin 2017-12-12 21:21:55 +00:00
gingerBill 054e241033 Localize checker data 2017-12-12 20:23:36 +00:00
gingerBill f7e9649be4 Disable struct field reordering (for the time being) 2017-12-12 18:21:40 +00:00
gingerBill fd1f6ec75c Merge branch 'master' into explicit-overloading 2017-12-11 11:13:22 +00:00
gingerBill 6b0d7cb26c Fix issue #162 regarding empty unions 2017-12-11 11:08:02 +00:00
gingerBill 3aea08df78 Change how abs, min, max, and clamp are implemented for floats 2017-12-11 11:06:43 +00:00
gingerBill 3c6f90e552 Fix proc groups from import names 2017-12-10 11:35:11 +00:00
gingerBill 3703ca4df4 Explicit procedure group; Remove implicit procedure overloading 2017-12-09 18:11:36 +00:00
gingerBill 41b8281c73 Set type of a procedure grouping to nullptr 2017-12-06 11:13:00 +00:00
gingerBill acd1f83bd0 Fix procedure groupings 2017-12-06 11:11:53 +00:00
gingerBill ba8371104d Set procedure grouping type to t_invalid 2017-12-06 11:01:52 +00:00
gingerBill 991682e9fd Fix write_entire_file 2017-12-06 10:58:02 +00:00
gingerBill f0de994059 Make core library use procedure groupings rather than normal overloading 2017-12-04 22:01:51 +00:00
gingerBill ebb2a9812c Merge pull request #160 from thebirk/patch-1
Added skip for Entity_ProcedureGrouping
2017-12-04 15:07:09 +00:00
Aleksander Birkeland 265c05927f Added skip for Entity_ProcedureGrouping 2017-12-04 16:05:42 +01:00
gingerBill 05ad38ae2d Fix procedure grouping 2017-12-03 23:19:25 +00:00
gingerBill 596a2c8355 Procedure grouping foo :: proc[foo16, foo32]; 2017-12-03 23:03:40 +00:00
gingerBill 9f52b2c283 Update demo.odin 2017-12-03 22:28:54 +00:00
gingerBill 8035a407a6 Remove dead code 2017-12-03 20:59:48 +00:00
gingerBill 97760c3fa4 Fix union_tag_size; Fix constant array of array literal printing with scalar contents 2017-12-03 20:49:19 +00:00
gingerBill d75291097e &x.(type) 2017-11-30 23:09:21 +00:00
gingerBill db632b7e22 buffer_from_slice 2017-11-30 20:42:16 +00:00
gingerBill 1a75dfe075 Remove vector type (will be replaced by something else in the future) 2017-11-30 20:34:42 +00:00
gingerBill e00d88d82e Fix issue #157 2017-11-30 19:53:40 +00:00
gingerBill 04cce1826b Fix map IR bug 2017-11-28 23:46:01 +00:00
gingerBill cc28cda053 Fix issue #156 2017-11-28 22:49:34 +00:00
gingerBill cfabc0e61f Remove using in arrays; Remove _ non-exported struct fields
Start determining slow parts of the compiler
2017-11-28 22:12:33 +00:00
gingerBill 91b534d128 Fix transmute 2017-11-27 23:00:23 +00:00
gingerBill 3268f43340 Update ABI for basic types 2017-11-27 20:37:09 +00:00
gingerBill 05e374934d Change proc ABI for Odin specific types 2017-11-27 20:18:06 +00:00
gingerBill 3e1ff0ec67 Update fmt for runes; Add strings.contains_rune 2017-11-26 23:54:23 +00:00
gingerBill 65945dac09 Fix comparison against nil for slices 2017-11-26 22:49:31 +00:00
gingerBill 1608da2dc8 for key, val in some_map {}; for val, idx in some_array {} 2017-11-26 18:56:47 +00:00
gingerBill c340827381 Remove old slice procedures 2017-11-26 18:38:46 +00:00
gingerBill 74fa7ca25d New slice memory layout (ptr+len); byte 2017-11-26 18:36:46 +00:00
gingerBill 5a9223afda nil_allocator; Fix IR type checking assert; append_string 2017-11-26 15:25:45 +00:00
gingerBill febcd73323 Fix merge from essence cross compile #154 2017-11-26 11:11:29 +00:00
gingerBill df06236076 Merge pull request #154 from nakst/master
essence cross compile
2017-11-26 11:10:13 +00:00
Nakst b0d3fbba47 essence cross compile 2017-11-26 11:03:11 +00:00
gingerBill adb6c7637e Fix 'fallthrough' 2017-11-25 11:16:23 +00:00
gingerBill 425f83b17d Merge pull request #150 from zangent/master
Changed `string_has_extension` to `string_ends_with` and fix macOS target triple
2017-11-21 22:33:39 +00:00
gingerBill 976415ff9d Fix key lookup of pointer to map 2017-11-21 22:32:41 +00:00
Zachary Pierson 4d7fb3e8d6 Changed string_has_extension to string_ends_with.
Fixed macOS target triple.
2017-11-21 16:16:53 -06:00
gingerBill bcca3bf322 Remove target triple from windows 2017-11-19 16:55:24 +00:00
gingerBill 74aaa3408f Fix debug symbol generation 2017-11-19 16:45:12 +00:00
gingerBill 2a5beee88c Remove /SYMBOLS flag 2017-11-19 15:11:07 +00:00
gingerBill cec9f7abfe Add -debug command (still in development) 2017-11-19 15:06:56 +00:00
60 changed files with 6467 additions and 9238 deletions
+24
View File
@@ -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)
+2 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+60
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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));
}
+113
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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) {
+24
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+792 -749
View File
File diff suppressed because it is too large Load Diff
+105 -325
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+405
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+114 -100
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+532
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-275
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {