mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 11:11:37 -07:00
Compare commits
332 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2cca005056 | |||
| d27109640e | |||
| 1287e8c734 | |||
| 7a6ac3ea92 | |||
| 81fe93127d | |||
| aa5716d3f9 | |||
| f9c6f6856b | |||
| b9cc2606f2 | |||
| 5023313c03 | |||
| 3e0fd63682 | |||
| 1f643b5816 | |||
| 14adcb9db8 | |||
| 41a22bd83d | |||
| 648b83d6ea | |||
| 4e97b83312 | |||
| 07cd6cd670 | |||
| 3fae38a2f8 | |||
| 23054138c2 | |||
| 63f755554b | |||
| 2ac463f003 | |||
| 77227c2ff5 | |||
| 2afccd7fbd | |||
| 991181104b | |||
| 70aff9fbb2 | |||
| 2370884722 | |||
| c529b1b73a | |||
| acc29fbceb | |||
| 7cc5177078 | |||
| fc93ea7aa3 | |||
| 4c22982732 | |||
| fb935541c9 | |||
| 47023b2e6c | |||
| f4a390201c | |||
| d358ebd7e6 | |||
| 9711dd1381 | |||
| 4c328d83ba | |||
| 9911b132d2 | |||
| 534e5978d8 | |||
| c08bf1204f | |||
| 94d68c1f22 | |||
| 0ca379ed03 | |||
| 0ed2d8b127 | |||
| 3bee571e1f | |||
| 0b78544796 | |||
| 361f71deed | |||
| 61f39ae0a0 | |||
| 082324d7b9 | |||
| 5e99289d7a | |||
| e14a4e79ae | |||
| 39c85cafa2 | |||
| fa6be4ec58 | |||
| 25b8461bfb | |||
| ac43dd0777 | |||
| 963559676e | |||
| 20ce8c4c51 | |||
| 098c09835b | |||
| 4aa9d34b3d | |||
| 38d2a0ddb9 | |||
| 735bb147e2 | |||
| 7a511308ef | |||
| bc401fa392 | |||
| 96fbafe359 | |||
| e82b0ea4cd | |||
| 2160484b62 | |||
| f0ab58dfbb | |||
| c23b5825bb | |||
| f1872f495a | |||
| 9ed36445b9 | |||
| 5043c10d70 | |||
| e748d2f2af | |||
| ecde06e3a3 | |||
| 3505c1d790 | |||
| 150a72f75e | |||
| f96579824b | |||
| 2aa3cabd85 | |||
| 06d26df046 | |||
| 6e49b1cad7 | |||
| d928f425ec | |||
| ed3a9aed12 | |||
| aaccaa19bf | |||
| 35857d3103 | |||
| d47b0eeee7 | |||
| 287beaff35 | |||
| 8e9d1c7ebf | |||
| 53380632a1 | |||
| 984a95b8c7 | |||
| 72118fcc6a | |||
| 1b06f809de | |||
| 19fe508fb2 | |||
| aaaff9b66c | |||
| c660b43105 | |||
| 92b24fd02d | |||
| 886d0de040 | |||
| 16d797cb01 | |||
| bbf9678756 | |||
| d60c619c44 | |||
| e7abc05931 | |||
| 12dd912ce9 | |||
| 64a63b3879 | |||
| 93caf5b311 | |||
| aab2fa1af9 | |||
| 4cf176de0b | |||
| 735cfcd290 | |||
| 4aa4317c28 | |||
| d0ef6d2a9b | |||
| 434c84043d | |||
| 747116aeb0 | |||
| a182dc78f4 | |||
| 1a316c8a18 | |||
| 46e7fa52b3 | |||
| 52ea3748b4 | |||
| 0a2678973b | |||
| 04129c5bd5 | |||
| 6f363dcae3 | |||
| 8c4bd76280 | |||
| 92f385e7b5 | |||
| ac4e259e29 | |||
| 076b20a9a5 | |||
| 0b0230adce | |||
| e51915a529 | |||
| 187a475b84 | |||
| 39c0a619eb | |||
| 29f7eaad78 | |||
| 8f086a6957 | |||
| 8f512001b6 | |||
| 1d25522a3b | |||
| fdb538538a | |||
| 2feb1bf847 | |||
| 74bbb1167f | |||
| 515163864f | |||
| 1cdb975c91 | |||
| cd42d26eb3 | |||
| 8bc96652cd | |||
| 1631a2bac1 | |||
| 501635ca26 | |||
| edcd335b90 | |||
| 0cb9908f27 | |||
| 61858f5899 | |||
| c5911679d1 | |||
| 99d6a077fe | |||
| 8b680254ee | |||
| b873651da7 | |||
| b185d9e701 | |||
| b635622cac | |||
| b31d8b1ad0 | |||
| 2153cb7e0a | |||
| 15033eab28 | |||
| 8b4c530062 | |||
| 9ff9587b7b | |||
| d8acbda548 | |||
| 7e4a65114a | |||
| d9a2d29d00 | |||
| 27931249ce | |||
| 52318d0e0e | |||
| 8d673789be | |||
| 646c4c7458 | |||
| 2cc22d118d | |||
| 1182f41f99 | |||
| 098d1d2b5e | |||
| 31c85f0ec5 | |||
| 091d1f8c75 | |||
| 6c50e6ef34 | |||
| 67f48aca96 | |||
| fc64e787a3 | |||
| d13bed9a0a | |||
| 904c48b11a | |||
| 2ab5eb7213 | |||
| 5ce541e9ef | |||
| 0cf9c22033 | |||
| 38e06f13d6 | |||
| ccc94f6832 | |||
| 589820639c | |||
| 68b9260c9b | |||
| 49b2447113 | |||
| 89c50bbd82 | |||
| 2b3f3e11d3 | |||
| 4100cfec86 | |||
| cad3a50e4e | |||
| 4d9ee55468 | |||
| b72f009d87 | |||
| 2181e0fc27 | |||
| cd74cdfdaf | |||
| 49ab935ae9 | |||
| 6879c9d8df | |||
| 939bf4bb5d | |||
| 7861dfd667 | |||
| c5fc28de7d | |||
| 535d290293 | |||
| a0dd975686 | |||
| f48531efaf | |||
| c6a4116082 | |||
| aecd6b85e6 | |||
| 55439ef293 | |||
| d4cf103676 | |||
| 489fb087a4 | |||
| ff904ae174 | |||
| d8db5ec7b6 | |||
| 5d8b78cb88 | |||
| 9736402dfd | |||
| 0600054ad4 | |||
| b782fca75b | |||
| 0230b88078 | |||
| 55c9fb7c5c | |||
| 8201a9ce6e | |||
| 561a94cc50 | |||
| 0636887931 | |||
| 0c1b39d881 | |||
| 67ffae7e32 | |||
| 488a38a96d | |||
| 77e5854a16 | |||
| 2a42dab108 | |||
| 092d103d24 | |||
| 12b7df550f | |||
| 006bd2fe17 | |||
| d252768ac5 | |||
| dd7c2c0574 | |||
| c91898a888 | |||
| afa8eb2d6f | |||
| 1481015dc4 | |||
| 8cdedd4cd2 | |||
| 985e4eed60 | |||
| 9d0583e0d2 | |||
| 9aed26a234 | |||
| 3323d5c76c | |||
| 4b9afd787c | |||
| cedf01d094 | |||
| 4a71603a77 | |||
| aadc8477b9 | |||
| 9bf111bd3d | |||
| 8060da2132 | |||
| b495a302b0 | |||
| c39a360372 | |||
| f6d1724835 | |||
| 0f217c715e | |||
| c4033c215e | |||
| e914d551e7 | |||
| c6e4b8ed5c | |||
| ab398f3704 | |||
| 699aec331d | |||
| baea6a1da8 | |||
| d2375a79f2 | |||
| ba48093666 | |||
| d4b87f1672 | |||
| e4006eb583 | |||
| b934e4b564 | |||
| 28c97a9467 | |||
| 28fca190ee | |||
| 78116e0ea2 | |||
| 5a50afa1fd | |||
| cf77a0e2b4 | |||
| e2593a6883 | |||
| 00a44d1ddb | |||
| d8445fd9df | |||
| 304db907f5 | |||
| b09cdc0f25 | |||
| bd81c6f5b4 | |||
| 4051dd9522 | |||
| 360cb9eb9a | |||
| 241a939c29 | |||
| 2f9c5d2d0b | |||
| 99c812b02d | |||
| d82c2ce50f | |||
| 6c12156b1a | |||
| eec3b3009f | |||
| 4654b41c3e | |||
| b09ea17f0e | |||
| 99ebfc337e | |||
| e5f9458905 | |||
| ec0a9a5f8a | |||
| 47b924990f | |||
| 215bebb01a | |||
| 9fffa19c51 | |||
| b54f3d4ee9 | |||
| bcdcad5847 | |||
| 737b8e42e4 | |||
| c61e7c05da | |||
| a919828003 | |||
| 0bd33882b6 | |||
| e0e55a649c | |||
| f32d71eca0 | |||
| 5fb98609cd | |||
| 19633ece80 | |||
| fb04103352 | |||
| 9abf43b0d2 | |||
| 7f97274ecc | |||
| b2edab193f | |||
| 184563bbe1 | |||
| 73f25ed182 | |||
| 533f6a552c | |||
| 32ac319525 | |||
| 569397bd7e | |||
| 3535d16c3a | |||
| 7f4efa90c8 | |||
| bab3cd988e | |||
| feda213c0c | |||
| c6593e8cde | |||
| 4d8d3919c0 | |||
| 20dc8b222d | |||
| 55733171c1 | |||
| 988926b59d | |||
| d72f8da6d7 | |||
| 0b697b24bd | |||
| b2c75dc3a2 | |||
| b5b3f1fb42 | |||
| bd73834e19 | |||
| 7f43c24297 | |||
| 6ac2c5c6dc | |||
| 45b3ae31af | |||
| 66a20264ab | |||
| d2d243cca8 | |||
| d4194962b0 | |||
| ee8372145d | |||
| ccb736411b | |||
| e2e5641a45 | |||
| 7ca0b256eb | |||
| ca442defbb | |||
| b17ebeb6f6 | |||
| a8afcf1ca9 | |||
| 6545cc2d48 | |||
| 2a10c8fe5c | |||
| 7cd2d14b64 | |||
| fc5abfd68b | |||
| cb5c821989 | |||
| ab7652010b | |||
| 7990566f6b | |||
| b6baee5f77 | |||
| 24c3ec235a | |||
| 4c0e9f1f89 | |||
| 8ebb84ad1e | |||
| f0e77a309d | |||
| 7ab531bd21 | |||
| d7af6de9b9 |
@@ -58,8 +58,8 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM, botan and setup PATH
|
||||
run: |
|
||||
brew install llvm@11 botan
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
brew install llvm@13 botan
|
||||
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
|
||||
@@ -69,8 +69,8 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM and setup PATH
|
||||
run: |
|
||||
brew install llvm@11
|
||||
echo "/usr/local/opt/llvm@11/bin" >> $GITHUB_PATH
|
||||
brew install llvm@13
|
||||
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -80,6 +80,16 @@ set libs= ^
|
||||
Synchronization.lib ^
|
||||
bin\llvm\windows\LLVM-C.lib
|
||||
|
||||
rem DO NOT TOUCH!
|
||||
rem THIS TILDE STUFF IS FOR DEVELOPMENT ONLY!
|
||||
set tilde_backend=0
|
||||
if %tilde_backend% EQU 1 (
|
||||
set libs=%libs% src\tilde\tb.lib
|
||||
set compiler_defines=%compiler_defines% -DODIN_TILDE_BACKEND
|
||||
)
|
||||
rem DO NOT TOUCH!
|
||||
|
||||
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
@@ -104,4 +114,4 @@ if %release_mode% EQU 0 odin run examples/demo
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
:end_of_build
|
||||
:end_of_build
|
||||
+13
-31
@@ -118,9 +118,7 @@ reader_peek :: proc(b: ^Reader, n: int) -> (data: []byte, err: io.Error) {
|
||||
b.last_rune_size = -1
|
||||
|
||||
for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
|
||||
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
|
||||
return nil, fill_err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
if n > len(b.buf) {
|
||||
@@ -156,9 +154,7 @@ reader_discard :: proc(b: ^Reader, n: int) -> (discarded: int, err: io.Error) {
|
||||
for {
|
||||
skip := reader_buffered(b)
|
||||
if skip == 0 {
|
||||
if fill_err := _reader_read_new_chunk(b); fill_err != nil {
|
||||
return 0, fill_err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
skip = reader_buffered(b)
|
||||
}
|
||||
skip = min(skip, remaining)
|
||||
@@ -223,20 +219,18 @@ reader_read :: proc(b: ^Reader, p: []byte) -> (n: int, err: io.Error) {
|
||||
|
||||
// reader_read_byte reads and returns a single byte
|
||||
// If no byte is available, it return an error
|
||||
reader_read_byte :: proc(b: ^Reader) -> (byte, io.Error) {
|
||||
reader_read_byte :: proc(b: ^Reader) -> (c: byte, err: io.Error) {
|
||||
b.last_rune_size = -1
|
||||
for b.r == b.w {
|
||||
if b.err != nil {
|
||||
return 0, _reader_consume_err(b)
|
||||
}
|
||||
if err := _reader_read_new_chunk(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
c := b.buf[b.r]
|
||||
c = b.buf[b.r]
|
||||
b.r += 1
|
||||
b.last_byte = int(c)
|
||||
return c, nil
|
||||
return
|
||||
}
|
||||
|
||||
// reader_unread_byte unreads the last byte. Only the most recently read byte can be unread
|
||||
@@ -264,15 +258,12 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) {
|
||||
!utf8.full_rune(b.buf[b.r:b.w]) &&
|
||||
b.err == nil &&
|
||||
b.w-b.w < len(b.buf) {
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
b.last_rune_size = -1
|
||||
if b.r == b.w {
|
||||
err = _reader_consume_err(b)
|
||||
return
|
||||
return 0, 0, _reader_consume_err(b)
|
||||
}
|
||||
r, size = rune(b.buf[b.r]), 1
|
||||
if r >= utf8.RUNE_SELF {
|
||||
@@ -305,27 +296,20 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
return i64(n), err
|
||||
}
|
||||
|
||||
n, err = write_buf(b, w)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n = write_buf(b, w) or_return
|
||||
|
||||
m: i64
|
||||
if b.w-b.r < len(b.buf) {
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
for b.r < b.w {
|
||||
m, err = write_buf(b, w)
|
||||
n += m
|
||||
n += m // this needs to be done before returning
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
return
|
||||
}
|
||||
_reader_read_new_chunk(b) or_return
|
||||
}
|
||||
|
||||
if b.err == .EOF {
|
||||
@@ -403,9 +387,7 @@ reader_read_slice :: proc(b: ^Reader, delim: byte) -> (line: []byte, err: io.Err
|
||||
|
||||
s = b.w - b.r
|
||||
|
||||
if err = _reader_read_new_chunk(b); err != nil {
|
||||
break
|
||||
}
|
||||
_reader_read_new_chunk(b) or_break
|
||||
}
|
||||
|
||||
if i := len(line)-1; i >= 0 {
|
||||
|
||||
@@ -159,7 +159,7 @@ writer_write_rune :: proc(b: ^Writer, r: rune) -> (size: int, err: io.Error) {
|
||||
return
|
||||
}
|
||||
|
||||
// writer_write writes a string into the buffer
|
||||
// writer_write_string writes a string into the buffer
|
||||
// It returns the number of bytes written
|
||||
// If n < len(p), it will return an error explaining why the write is short
|
||||
writer_write_string :: proc(b: ^Writer, s: string) -> (int, io.Error) {
|
||||
|
||||
@@ -113,8 +113,11 @@ _buffer_grow :: proc(b: ^Buffer, n: int) -> int {
|
||||
if i, ok := _buffer_try_grow(b, n); ok {
|
||||
return i
|
||||
}
|
||||
|
||||
if b.buf == nil && n <= SMALL_BUFFER_SIZE {
|
||||
b.buf = make([dynamic]byte, n, SMALL_BUFFER_SIZE)
|
||||
// Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator
|
||||
reserve(&b.buf, SMALL_BUFFER_SIZE)
|
||||
resize(&b.buf, n)
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ advance_rune :: proc(t: ^Tokenizer) {
|
||||
}
|
||||
|
||||
advance_rune_n :: proc(t: ^Tokenizer, n: int) {
|
||||
for in 0..<n {
|
||||
for _ in 0..<n {
|
||||
advance_rune(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ foreign libc {
|
||||
// strictly conformant C implementation is 16 on the platforms we care about.
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
jmp_buf :: struct #align 16 { _: [4096]char, }
|
||||
jmp_buf :: struct #align(16) { _: [4096]char, }
|
||||
|
||||
@@ -18,7 +18,7 @@ foreign _ {
|
||||
// strictly conformant C implementation is 16 on the platforms we care about.
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
va_list :: struct #align 16 {
|
||||
va_list :: struct #align(16) {
|
||||
_: [4096]u8,
|
||||
}
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ when ODIN_OS == .Windows {
|
||||
clock_t :: distinct long
|
||||
time_t :: distinct i64
|
||||
|
||||
timespec :: struct #align 8 {
|
||||
timespec :: struct #align(8) {
|
||||
tv_sec: time_t,
|
||||
tv_nsec: long,
|
||||
}
|
||||
|
||||
tm :: struct #align 8 {
|
||||
tm :: struct #align(8) {
|
||||
tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ foreign libc {
|
||||
}
|
||||
|
||||
// Large enough and aligned enough for any wide-spread in-use libc.
|
||||
mbstate_t :: struct #align 16 { _: [32]char, }
|
||||
mbstate_t :: struct #align(16) { _: [32]char, }
|
||||
|
||||
// Odin does not have default argument promotion so the need for a separate type
|
||||
// here isn't necessary, though make it distinct just to be safe.
|
||||
|
||||
+17
-39
@@ -216,24 +216,16 @@ read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int
|
||||
// TODO: REMOVE ALL USE OF context.temp_allocator here
|
||||
// the is literally no need for it
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
_, e := io.read(z.input, b[:])
|
||||
if e == .None {
|
||||
return b, .None
|
||||
}
|
||||
|
||||
return []u8{}, e
|
||||
_ = io.read(z.input, b[:]) or_return
|
||||
return b, nil
|
||||
}
|
||||
|
||||
read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
|
||||
b, e := read_slice(z, size_of(T))
|
||||
if e == .None {
|
||||
return (^T)(&b[0])^, .None
|
||||
}
|
||||
|
||||
return T{}, e
|
||||
b := read_slice(z, size_of(T)) or_return
|
||||
return (^T)(&b[0])^, nil
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
@@ -250,12 +242,8 @@ read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8,
|
||||
|
||||
@(optimization_mode="speed")
|
||||
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
|
||||
b, e := read_slice_from_stream(z, 1)
|
||||
if e == .None {
|
||||
return b[0], .None
|
||||
}
|
||||
|
||||
return 0, e
|
||||
b := read_slice_from_stream(z, 1) or_return
|
||||
return b[0], nil
|
||||
}
|
||||
|
||||
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
|
||||
@@ -320,12 +308,9 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
size :: size_of(T)
|
||||
|
||||
// Get current position to read from.
|
||||
curr, e1 := z.input->impl_seek(0, .Current)
|
||||
if e1 != .None {
|
||||
return T{}, e1
|
||||
}
|
||||
r, e2 := io.to_reader_at(z.input)
|
||||
if !e2 {
|
||||
curr := z.input->impl_seek(0, .Current) or_return
|
||||
r, e1 := io.to_reader_at(z.input)
|
||||
if !e1 {
|
||||
return T{}, .Empty
|
||||
}
|
||||
when size <= 128 {
|
||||
@@ -333,8 +318,8 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
|
||||
} else {
|
||||
b := make([]u8, size, context.temp_allocator)
|
||||
}
|
||||
_, e3 := io.read_at(r, b[:], curr)
|
||||
if e3 != .None {
|
||||
_, e2 := io.read_at(r, b[:], curr)
|
||||
if e2 != .None {
|
||||
return T{}, .Empty
|
||||
}
|
||||
|
||||
@@ -347,16 +332,9 @@ peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input,
|
||||
size :: size_of(T)
|
||||
|
||||
// Get current position to return to.
|
||||
cur_pos, e1 := z.input->impl_seek(0, .Current)
|
||||
if e1 != .None {
|
||||
return T{}, e1
|
||||
}
|
||||
|
||||
cur_pos := z.input->impl_seek(0, .Current) or_return
|
||||
// Seek to offset.
|
||||
pos, e2 := z.input->impl_seek(offset, .Start)
|
||||
if e2 != .None {
|
||||
return T{}, e2
|
||||
}
|
||||
pos := z.input->impl_seek(offset, .Start) or_return
|
||||
|
||||
r, e3 := io.to_reader_at(z.input)
|
||||
if !e3 {
|
||||
@@ -465,7 +443,7 @@ peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width:
|
||||
if z.num_bits < u64(width) {
|
||||
refill_lsb(z)
|
||||
}
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
@@ -473,7 +451,7 @@ peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width:
|
||||
if z.num_bits < u64(width) {
|
||||
refill_lsb(z)
|
||||
}
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
|
||||
@@ -481,13 +459,13 @@ peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
|
||||
@(optimization_mode="speed")
|
||||
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
|
||||
assert(z.num_bits >= u64(width))
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
|
||||
assert(z.num_bits >= u64(width))
|
||||
return u32(z.code_buffer & ~(~u64(0) << width))
|
||||
return u32(z.code_buffer &~ (~u64(0) << width))
|
||||
}
|
||||
|
||||
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
|
||||
|
||||
@@ -335,10 +335,8 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
|
||||
|
||||
// fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size);
|
||||
|
||||
zlib_error := zlib.inflate_raw(z, expected_output_size=expected_output_size)
|
||||
if zlib_error != nil {
|
||||
return zlib_error
|
||||
}
|
||||
zlib.inflate_raw(z, expected_output_size=expected_output_size) or_return
|
||||
|
||||
/*
|
||||
Read CRC32 using the ctx bit reader because zlib may leave bytes in there.
|
||||
*/
|
||||
|
||||
@@ -147,15 +147,7 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
|
||||
Double until we reach the maximum allowed.
|
||||
*/
|
||||
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX)
|
||||
resize(buf, new_size)
|
||||
if len(buf) != new_size {
|
||||
/*
|
||||
Resize failed.
|
||||
*/
|
||||
return .Resize_Failed
|
||||
}
|
||||
|
||||
return nil
|
||||
return resize(buf, new_size)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -182,7 +174,7 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
|
||||
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
|
||||
/*
|
||||
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
|
||||
without having to worry about wrapping, so no need for a temp allocation to give to
|
||||
@@ -306,10 +298,10 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
||||
code := u16(compress.peek_bits_lsb(z,16))
|
||||
|
||||
k := int(z_bit_reverse(code, 16))
|
||||
s: u8
|
||||
|
||||
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
|
||||
if k < t.maxcode[s] {
|
||||
s: u8 = HUFFMAN_FAST_BITS+1
|
||||
for {
|
||||
#no_bounds_check if k < t.maxcode[s] {
|
||||
break
|
||||
}
|
||||
s += 1
|
||||
@@ -510,8 +502,8 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
/*
|
||||
Try to pre-allocate the output buffer.
|
||||
*/
|
||||
reserve(&z.output.buf, expected_output_size)
|
||||
resize (&z.output.buf, expected_output_size)
|
||||
reserve(&z.output.buf, expected_output_size) or_return
|
||||
resize (&z.output.buf, expected_output_size) or_return
|
||||
}
|
||||
|
||||
if len(z.output.buf) != expected_output_size {
|
||||
@@ -654,7 +646,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
}
|
||||
|
||||
if int(z.bytes_written) != len(z.output.buf) {
|
||||
resize(&z.output.buf, int(z.bytes_written))
|
||||
resize(&z.output.buf, int(z.bytes_written)) or_return
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -20,10 +20,10 @@ List :: struct {
|
||||
|
||||
|
||||
Node :: struct {
|
||||
next, prev: ^Node,
|
||||
prev, next: ^Node,
|
||||
}
|
||||
|
||||
push_front :: proc(list: ^List, node: ^Node) {
|
||||
push_front :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if list.head != nil {
|
||||
list.head.prev = node
|
||||
node.prev, node.next = nil, list.head
|
||||
@@ -34,7 +34,7 @@ push_front :: proc(list: ^List, node: ^Node) {
|
||||
}
|
||||
}
|
||||
|
||||
push_back :: proc(list: ^List, node: ^Node) {
|
||||
push_back :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if list.tail != nil {
|
||||
list.tail.next = node
|
||||
node.prev, node.next = list.tail, nil
|
||||
@@ -45,7 +45,7 @@ push_back :: proc(list: ^List, node: ^Node) {
|
||||
}
|
||||
}
|
||||
|
||||
remove :: proc(list: ^List, node: ^Node) {
|
||||
remove :: proc "contextless" (list: ^List, node: ^Node) {
|
||||
if node != nil {
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
@@ -83,12 +83,34 @@ remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
|
||||
}
|
||||
}
|
||||
|
||||
remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^Node) -> bool) {
|
||||
for node := list.head; node != nil; {
|
||||
next := node.next
|
||||
if to_erase(node) {
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
}
|
||||
if node.prev != nil {
|
||||
node.prev.next = node.next
|
||||
}
|
||||
if list.head == node {
|
||||
list.head = node.next
|
||||
}
|
||||
if list.tail == node {
|
||||
list.tail = node.prev
|
||||
}
|
||||
}
|
||||
node = next
|
||||
}
|
||||
}
|
||||
|
||||
is_empty :: proc(list: ^List) -> bool {
|
||||
|
||||
|
||||
is_empty :: proc "contextless" (list: ^List) -> bool {
|
||||
return list.head == nil
|
||||
}
|
||||
|
||||
pop_front :: proc(list: ^List) -> ^Node {
|
||||
pop_front :: proc "contextless" (list: ^List) -> ^Node {
|
||||
link := list.head
|
||||
if link == nil {
|
||||
return nil
|
||||
@@ -108,7 +130,7 @@ pop_front :: proc(list: ^List) -> ^Node {
|
||||
return link
|
||||
|
||||
}
|
||||
pop_back :: proc(list: ^List) -> ^Node {
|
||||
pop_back :: proc "contextless" (list: ^List) -> ^Node {
|
||||
link := list.tail
|
||||
if link == nil {
|
||||
return nil
|
||||
@@ -134,25 +156,25 @@ Iterator :: struct($T: typeid) {
|
||||
offset: uintptr,
|
||||
}
|
||||
|
||||
iterator_head :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
iterator_head :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Node {
|
||||
return {list.head, offset_of_by_string(T, field_name)}
|
||||
}
|
||||
|
||||
iterator_tail :: proc(list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
iterator_tail :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Node {
|
||||
return {list.tail, offset_of_by_string(T, field_name)}
|
||||
}
|
||||
|
||||
iterator_from_node :: proc(node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
iterator_from_node :: proc "contextless" (node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
|
||||
where intrinsics.type_has_field(T, field_name),
|
||||
intrinsics.type_field_type(T, field_name) == Node {
|
||||
return {node, offset_of_by_string(T, field_name)}
|
||||
}
|
||||
|
||||
iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
@@ -162,7 +184,7 @@ iterate_next :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
return (^T)(uintptr(node) - it.offset), true
|
||||
}
|
||||
|
||||
iterate_prev :: proc(it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
|
||||
node := it.curr
|
||||
if node == nil {
|
||||
return nil, false
|
||||
|
||||
@@ -56,7 +56,7 @@ space :: proc(q: $Q/Queue($T)) -> int {
|
||||
|
||||
// Reserve enough space for at least the specified capacity
|
||||
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error {
|
||||
if uint(capacity) > q.len {
|
||||
if capacity > space(q^) {
|
||||
return _grow(q, uint(capacity))
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -248,7 +248,7 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
|
||||
field_length += 1
|
||||
|
||||
case '\n', '\r':
|
||||
if !is_quoted { break read_loop }
|
||||
is_quoted or_break read_loop
|
||||
|
||||
case r.comma:
|
||||
field_length = 0
|
||||
|
||||
@@ -207,7 +207,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
case runtime.Type_Info_Relative_Pointer:
|
||||
return .Unsupported_Type
|
||||
|
||||
case runtime.Type_Info_Relative_Slice:
|
||||
case runtime.Type_Info_Relative_Multi_Pointer:
|
||||
return .Unsupported_Type
|
||||
|
||||
case runtime.Type_Info_Matrix:
|
||||
@@ -265,9 +265,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
|
||||
i := 0
|
||||
for bucket_index in 0..<map_cap {
|
||||
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
||||
continue
|
||||
}
|
||||
runtime.map_hash_is_valid(hs[bucket_index]) or_continue
|
||||
|
||||
opt_write_iteration(w, opt, i) or_return
|
||||
i += 1
|
||||
|
||||
@@ -284,8 +283,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
#partial switch info in ti.variant {
|
||||
case runtime.Type_Info_String:
|
||||
switch s in a {
|
||||
case string: name = s
|
||||
case cstring: name = string(s)
|
||||
case string: name = s
|
||||
case cstring: name = string(s)
|
||||
}
|
||||
opt_write_key(w, opt, name) or_return
|
||||
|
||||
@@ -404,7 +403,7 @@ opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err
|
||||
switch opt.spec {
|
||||
case .JSON, .JSON5:
|
||||
io.write_quoted_string(w, name) or_return
|
||||
io.write_string(w, ": ") or_return
|
||||
io.write_string(w, ": " if opt.pretty else ":") or_return
|
||||
|
||||
case .MJSON:
|
||||
if opt.mjson_keys_use_quotes {
|
||||
@@ -412,11 +411,11 @@ opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err
|
||||
} else {
|
||||
io.write_string(w, name) or_return
|
||||
}
|
||||
|
||||
|
||||
if opt.mjson_keys_use_equal_sign {
|
||||
io.write_string(w, " = ") or_return
|
||||
io.write_string(w, " = " if opt.pretty else "=") or_return
|
||||
} else {
|
||||
io.write_string(w, ": ") or_return
|
||||
io.write_string(w, ": " if opt.pretty else ":") or_return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +445,7 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int)
|
||||
switch opt.spec {
|
||||
case .JSON, .JSON5:
|
||||
if iteration > 0 {
|
||||
io.write_string(w, ", ") or_return
|
||||
io.write_byte(w, ',') or_return
|
||||
|
||||
if opt.pretty {
|
||||
io.write_byte(w, '\n') or_return
|
||||
@@ -462,7 +461,7 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int)
|
||||
io.write_byte(w, '\n') or_return
|
||||
} else {
|
||||
// comma separation necessary for non pretty output!
|
||||
io.write_string(w, ", ") or_return
|
||||
io.write_byte(w, ',') or_return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
r, w := utf8.decode_rune_in_string(s)
|
||||
r, w := utf8.decode_rune_in_string(s[i:])
|
||||
if r == utf8.RUNE_ERROR && w == 1 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string
|
||||
/*
|
||||
Skip commments. They have no name.
|
||||
*/
|
||||
if child.kind != .Element { continue }
|
||||
if child.kind != .Element { continue }
|
||||
|
||||
/*
|
||||
If the ident matches and it's the nth such child, return it.
|
||||
*/
|
||||
if child.ident == ident {
|
||||
if count == nth { return child_id, true }
|
||||
if count == nth { return child_id, true }
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ Floating-point, complex numbers, and quaternions:
|
||||
%F synonym for %f
|
||||
%h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd)
|
||||
%H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD)
|
||||
%m number of bytes in the best unit of measurement, e.g. 123.45mib
|
||||
%M number of bytes in the best unit of measurement, e.g. 123.45MiB
|
||||
String and slice of bytes
|
||||
%s the uninterpreted bytes of the string or slice
|
||||
%q a double-quoted string safely escaped with Odin syntax
|
||||
@@ -85,6 +87,7 @@ Other flags:
|
||||
add leading 0z for dozenal (%#z)
|
||||
add leading 0x or 0X for hexadecimal (%#x or %#X)
|
||||
remove leading 0x for %p (%#p)
|
||||
add a space between bytes and the unit of measurement (%#m or %#M)
|
||||
' ' (space) leave a space for elided sign in numbers (% d)
|
||||
0 pad with leading zeros rather than spaces
|
||||
|
||||
|
||||
+96
-50
@@ -152,9 +152,9 @@ aprintln :: proc(args: ..any, sep := " ") -> string {
|
||||
//
|
||||
// Returns: A formatted string. The returned string must be freed accordingly.
|
||||
//
|
||||
aprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator) -> string {
|
||||
str: strings.Builder
|
||||
strings.builder_init(&str)
|
||||
strings.builder_init(&str, allocator)
|
||||
sbprintf(&str, fmt, ..args)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
@@ -327,7 +327,7 @@ ctprintf :: proc(format: string, args: ..any) -> cstring {
|
||||
// Returns: A formatted string
|
||||
//
|
||||
sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||
wprint(strings.to_writer(buf), ..args, sep=sep)
|
||||
wprint(strings.to_writer(buf), ..args, sep=sep, flush=true)
|
||||
return strings.to_string(buf^)
|
||||
}
|
||||
// Formats and writes to a strings.Builder buffer using the default print settings
|
||||
@@ -340,7 +340,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||
// Returns: The resulting formatted string
|
||||
//
|
||||
sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||
wprintln(strings.to_writer(buf), ..args, sep=sep)
|
||||
wprintln(strings.to_writer(buf), ..args, sep=sep, flush=true)
|
||||
return strings.to_string(buf^)
|
||||
}
|
||||
// Formats and writes to a strings.Builder buffer according to the specified format string
|
||||
@@ -353,7 +353,7 @@ sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||
// Returns: The resulting formatted string
|
||||
//
|
||||
sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
|
||||
wprintf(strings.to_writer(buf), fmt, ..args)
|
||||
wprintf(strings.to_writer(buf), fmt, ..args, flush=true)
|
||||
return strings.to_string(buf^)
|
||||
}
|
||||
// Formats and writes to an io.Writer using the default print settings
|
||||
@@ -365,7 +365,7 @@ sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
|
||||
//
|
||||
// Returns: The number of bytes written
|
||||
//
|
||||
wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int {
|
||||
fi: Info
|
||||
fi.writer = w
|
||||
|
||||
@@ -391,7 +391,9 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
|
||||
fmt_value(&fi, args[i], 'v')
|
||||
}
|
||||
io.flush(auto_cast w)
|
||||
if flush {
|
||||
io.flush(w)
|
||||
}
|
||||
|
||||
return fi.n
|
||||
}
|
||||
@@ -404,7 +406,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
//
|
||||
// Returns: The number of bytes written
|
||||
//
|
||||
wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int {
|
||||
fi: Info
|
||||
fi.writer = w
|
||||
|
||||
@@ -416,7 +418,9 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
fmt_value(&fi, args[i], 'v')
|
||||
}
|
||||
io.write_byte(fi.writer, '\n', &fi.n)
|
||||
io.flush(auto_cast w)
|
||||
if flush {
|
||||
io.flush(w)
|
||||
}
|
||||
return fi.n
|
||||
}
|
||||
// Formats and writes to an io.Writer according to the specified format string
|
||||
@@ -428,7 +432,7 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
//
|
||||
// Returns: The number of bytes written
|
||||
//
|
||||
wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
|
||||
wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true) -> int {
|
||||
fi: Info
|
||||
arg_index: int = 0
|
||||
end := len(fmt)
|
||||
@@ -698,8 +702,9 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
|
||||
}
|
||||
io.write_string(fi.writer, ")", &fi.n)
|
||||
}
|
||||
|
||||
io.flush(auto_cast w)
|
||||
if flush {
|
||||
io.flush(w)
|
||||
}
|
||||
|
||||
return fi.n
|
||||
}
|
||||
@@ -711,9 +716,11 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
|
||||
//
|
||||
// Returns: The number of bytes written and an io.Error if encountered
|
||||
//
|
||||
wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) {
|
||||
wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info, flush := true) -> (int, io.Error) {
|
||||
n, err := reflect.write_type(w, info)
|
||||
io.flush(auto_cast w)
|
||||
if flush {
|
||||
io.flush(w)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
// Writes a typeid value to an io.Writer
|
||||
@@ -724,9 +731,11 @@ wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) {
|
||||
//
|
||||
// Returns: The number of bytes written and an io.Error if encountered
|
||||
//
|
||||
wprint_typeid :: proc(w: io.Writer, id: typeid) -> (int, io.Error) {
|
||||
wprint_typeid :: proc(w: io.Writer, id: typeid, flush := true) -> (int, io.Error) {
|
||||
n, err := reflect.write_type(w, type_info_of(id))
|
||||
io.flush(auto_cast w)
|
||||
if flush {
|
||||
io.flush(w)
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
// Parses an integer from a given string starting at a specified offset
|
||||
@@ -746,9 +755,8 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok:
|
||||
new_offset = offset
|
||||
for new_offset < len(s) {
|
||||
c := s[new_offset]
|
||||
if !is_digit(c) {
|
||||
break
|
||||
}
|
||||
is_digit(c) or_break
|
||||
|
||||
new_offset += 1
|
||||
|
||||
result *= 10
|
||||
@@ -1039,6 +1047,65 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
|
||||
fi.zero = false
|
||||
_pad(fi, s)
|
||||
}
|
||||
// Units of measurements:
|
||||
__MEMORY_LOWER := " b kib mib gib tib pib eib"
|
||||
__MEMORY_UPPER := " B KiB MiB GiB TiB PiB EiB"
|
||||
// Formats an integer value as bytes with the best representation.
|
||||
//
|
||||
// Inputs:
|
||||
// - fi: A pointer to an Info structure
|
||||
// - u: The integer value to format
|
||||
// - is_signed: A boolean indicating if the integer is signed
|
||||
// - bit_size: The bit size of the integer
|
||||
// - digits: A string containing the digits for formatting
|
||||
//
|
||||
_fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: string) {
|
||||
abs, neg := strconv.is_integer_negative(u, is_signed, bit_size)
|
||||
|
||||
// Default to a precision of 2, but if less than a kb, 0
|
||||
prec := fi.prec if (fi.prec_set || abs < mem.Kilobyte) else 2
|
||||
|
||||
div, off, unit_len := 1, 0, 1
|
||||
for n := abs; n >= mem.Kilobyte; n /= mem.Kilobyte {
|
||||
div *= mem.Kilobyte
|
||||
off += 4
|
||||
|
||||
// First iteration is slightly different because you go from
|
||||
// units of length 1 to units of length 2.
|
||||
if unit_len == 1 {
|
||||
off = 2
|
||||
unit_len = 3
|
||||
}
|
||||
}
|
||||
|
||||
// If hash, we add a space between the value and the suffix.
|
||||
if fi.hash {
|
||||
unit_len += 1
|
||||
} else {
|
||||
off += 1
|
||||
}
|
||||
|
||||
amt := f64(abs) / f64(div)
|
||||
if neg {
|
||||
amt = -amt
|
||||
}
|
||||
|
||||
buf: [256]byte
|
||||
str := strconv.append_float(buf[:], amt, 'f', prec, 64)
|
||||
|
||||
// Add the unit at the end.
|
||||
copy(buf[len(str):], units[off:off+unit_len])
|
||||
str = string(buf[:len(str)+unit_len])
|
||||
|
||||
if !fi.plus {
|
||||
// Strip sign from "+<value>" but not "+Inf".
|
||||
if str[0] == '+' && str[1] != 'I' {
|
||||
str = str[1:]
|
||||
}
|
||||
}
|
||||
|
||||
_pad(fi, str)
|
||||
}
|
||||
// Hex Values:
|
||||
__DIGITS_LOWER := "0123456789abcdefx"
|
||||
__DIGITS_UPPER := "0123456789ABCDEFX"
|
||||
@@ -1087,6 +1154,8 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) {
|
||||
io.write_string(fi.writer, "U+", &fi.n)
|
||||
_fmt_int(fi, u, 16, false, bit_size, __DIGITS_UPPER)
|
||||
}
|
||||
case 'm': _fmt_memory(fi, u, is_signed, bit_size, __MEMORY_LOWER)
|
||||
case 'M': _fmt_memory(fi, u, is_signed, bit_size, __MEMORY_UPPER)
|
||||
|
||||
case:
|
||||
fmt_bad_verb(fi, verb)
|
||||
@@ -1565,7 +1634,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
||||
// - fi: A pointer to the Info structure where the indents will be written.
|
||||
//
|
||||
fmt_write_indent :: proc(fi: ^Info) {
|
||||
for in 0..<fi.indent {
|
||||
for _ in 0..<fi.indent {
|
||||
io.write_byte(fi.writer, '\t', &fi.n)
|
||||
}
|
||||
}
|
||||
@@ -1720,7 +1789,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St
|
||||
}
|
||||
defer {
|
||||
if hash {
|
||||
for in 0..<indent { io.write_byte(fi.writer, '\t', &fi.n) }
|
||||
for _ in 0..<indent { io.write_byte(fi.writer, '\t', &fi.n) }
|
||||
}
|
||||
io.write_byte(fi.writer, ']' if is_soa else '}', &fi.n)
|
||||
}
|
||||
@@ -1956,7 +2025,7 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
|
||||
for x := i; x >= 10; x /= 10 {
|
||||
n -= 1
|
||||
}
|
||||
for in 0..<n {
|
||||
for _ in 0..<n {
|
||||
io.write_byte(fi.writer, '0', &fi.n)
|
||||
}
|
||||
io.write_i64(fi.writer, i, 10, &fi.n)
|
||||
@@ -1989,7 +2058,7 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
|
||||
v := v
|
||||
w := len(buf)
|
||||
print := false
|
||||
for in 0..<prec {
|
||||
for _ in 0..<prec {
|
||||
digit := v % 10
|
||||
print = print || digit != 0
|
||||
if print {
|
||||
@@ -2485,9 +2554,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
|
||||
j := 0
|
||||
for bucket_index in 0..<map_cap {
|
||||
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
||||
continue
|
||||
}
|
||||
runtime.map_hash_is_valid(hs[bucket_index]) or_continue
|
||||
|
||||
if j > 0 {
|
||||
io.write_string(fi.writer, ", ", &fi.n)
|
||||
@@ -2535,32 +2602,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
|
||||
fmt_value(fi, absolute_ptr, verb)
|
||||
|
||||
case runtime.Type_Info_Relative_Slice:
|
||||
case runtime.Type_Info_Relative_Multi_Pointer:
|
||||
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id)
|
||||
absolute_ptr := any{ptr, info.pointer.id}
|
||||
|
||||
if verb == 'p' {
|
||||
fmt_pointer(fi, ptr, 'p')
|
||||
} else if ptr == nil {
|
||||
io.write_string(fi.writer, "[]", &fi.n)
|
||||
} else {
|
||||
len_ptr := uintptr(v.data) + uintptr(info.base_integer.size)
|
||||
len_any := any{rawptr(len_ptr), info.base_integer.id}
|
||||
len, _ := reflect.as_int(len_any)
|
||||
slice_type := reflect.type_info_base(info.slice).variant.(runtime.Type_Info_Slice)
|
||||
|
||||
fi.record_level += 1
|
||||
defer fi.record_level -= 1
|
||||
|
||||
io.write_byte(fi.writer, '[', &fi.n)
|
||||
defer io.write_byte(fi.writer, ']', &fi.n)
|
||||
|
||||
for i in 0..<len {
|
||||
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
|
||||
|
||||
data := uintptr(ptr) + uintptr(i*slice_type.elem_size)
|
||||
fmt_arg(fi, any{rawptr(data), slice_type.elem.id}, verb)
|
||||
}
|
||||
}
|
||||
fmt_value(fi, absolute_ptr, verb)
|
||||
|
||||
case runtime.Type_Info_Matrix:
|
||||
fmt_matrix(fi, v, verb, info)
|
||||
|
||||
@@ -32,15 +32,15 @@ stderr := io.Writer{
|
||||
}
|
||||
|
||||
// print formats using the default print settings and writes to stdout
|
||||
print :: proc(args: ..any, sep := " ") -> int { return wprint(w=stdout, args=args, sep=sep) }
|
||||
print :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) }
|
||||
// println formats using the default print settings and writes to stdout
|
||||
println :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stdout, args=args, sep=sep) }
|
||||
println :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) }
|
||||
// printf formats according to the specififed format string and writes to stdout
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return wprintf(stdout, fmt, ..args) }
|
||||
printf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) }
|
||||
|
||||
// eprint formats using the default print settings and writes to stderr
|
||||
eprint :: proc(args: ..any, sep := " ") -> int { return wprint(w=stderr, args=args, sep=sep) }
|
||||
eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) }
|
||||
// eprintln formats using the default print settings and writes to stderr
|
||||
eprintln :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stderr, args=args, sep=sep) }
|
||||
eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) }
|
||||
// eprintf formats according to the specififed format string and writes to stderr
|
||||
eprintf :: proc(fmt: string, args: ..any) -> int { return wprintf(stderr, fmt, ..args) }
|
||||
eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) }
|
||||
|
||||
+16
-16
@@ -7,18 +7,18 @@ import "core:io"
|
||||
import "core:bufio"
|
||||
|
||||
// fprint formats using the default print settings and writes to fd
|
||||
fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
|
||||
fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int {
|
||||
buf: [1024]byte
|
||||
b: bufio.Writer
|
||||
defer bufio.writer_flush(&b)
|
||||
|
||||
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
|
||||
w := bufio.writer_to_writer(&b)
|
||||
return wprint(w, ..args, sep=sep)
|
||||
return wprint(w, ..args, sep=sep, flush=flush)
|
||||
}
|
||||
|
||||
// fprintln formats using the default print settings and writes to fd
|
||||
fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
|
||||
fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int {
|
||||
buf: [1024]byte
|
||||
b: bufio.Writer
|
||||
defer bufio.writer_flush(&b)
|
||||
@@ -26,10 +26,10 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
|
||||
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
|
||||
|
||||
w := bufio.writer_to_writer(&b)
|
||||
return wprintln(w, ..args, sep=sep)
|
||||
return wprintln(w, ..args, sep=sep, flush=flush)
|
||||
}
|
||||
// fprintf formats according to the specified format string and writes to fd
|
||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int {
|
||||
buf: [1024]byte
|
||||
b: bufio.Writer
|
||||
defer bufio.writer_flush(&b)
|
||||
@@ -37,9 +37,9 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
|
||||
|
||||
w := bufio.writer_to_writer(&b)
|
||||
return wprintf(w, fmt, ..args)
|
||||
return wprintf(w, fmt, ..args, flush=flush)
|
||||
}
|
||||
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) -> (n: int, err: io.Error) {
|
||||
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) {
|
||||
buf: [1024]byte
|
||||
b: bufio.Writer
|
||||
defer bufio.writer_flush(&b)
|
||||
@@ -47,9 +47,9 @@ fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) -> (n: int, err: io
|
||||
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
|
||||
|
||||
w := bufio.writer_to_writer(&b)
|
||||
return wprint_type(w, info)
|
||||
return wprint_type(w, info, flush=flush)
|
||||
}
|
||||
fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
|
||||
fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: io.Error) {
|
||||
buf: [1024]byte
|
||||
b: bufio.Writer
|
||||
defer bufio.writer_flush(&b)
|
||||
@@ -57,19 +57,19 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
|
||||
bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:])
|
||||
|
||||
w := bufio.writer_to_writer(&b)
|
||||
return wprint_typeid(w, id)
|
||||
return wprint_typeid(w, id, flush=flush)
|
||||
}
|
||||
|
||||
// print formats using the default print settings and writes to os.stdout
|
||||
print :: proc(args: ..any, sep := " ") -> int { return fprint(os.stdout, ..args, sep=sep) }
|
||||
print :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) }
|
||||
// println formats using the default print settings and writes to os.stdout
|
||||
println :: proc(args: ..any, sep := " ") -> int { return fprintln(os.stdout, ..args, sep=sep) }
|
||||
println :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) }
|
||||
// printf formats according to the specified format string and writes to os.stdout
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
|
||||
printf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) }
|
||||
|
||||
// eprint formats using the default print settings and writes to os.stderr
|
||||
eprint :: proc(args: ..any, sep := " ") -> int { return fprint(os.stderr, ..args, sep=sep) }
|
||||
eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) }
|
||||
// eprintln formats using the default print settings and writes to os.stderr
|
||||
eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(os.stderr, ..args, sep=sep) }
|
||||
eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) }
|
||||
// eprintf formats according to the specified format string and writes to os.stderr
|
||||
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }
|
||||
eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) }
|
||||
|
||||
@@ -299,7 +299,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
||||
if length := int(data & 63) + 1; (length * img.channels) > len(pixels) {
|
||||
return img, .Corrupt
|
||||
} else {
|
||||
#no_bounds_check for in 0..<length {
|
||||
#no_bounds_check for _ in 0..<length {
|
||||
copy(pixels, pix[:img.channels])
|
||||
pixels = pixels[img.channels:]
|
||||
}
|
||||
|
||||
@@ -215,10 +215,10 @@ simd_shr_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T
|
||||
simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_bit_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_neg :: proc(a: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
|
||||
+2
-2
@@ -39,12 +39,12 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (
|
||||
}
|
||||
|
||||
write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [32]byte
|
||||
buf: [39]byte
|
||||
s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [32]byte
|
||||
buf: [40]byte
|
||||
s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
|
||||
@@ -22,43 +22,43 @@ package math_big
|
||||
/*
|
||||
2's complement `and`, returns `dest = a & b;`
|
||||
*/
|
||||
int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
int_bit_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_and(dest, a, b)
|
||||
}
|
||||
and :: proc { int_and, }
|
||||
bit_and :: proc { int_bit_and, }
|
||||
|
||||
/*
|
||||
2's complement `or`, returns `dest = a | b;`
|
||||
*/
|
||||
int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
int_bit_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_or(dest, a, b)
|
||||
}
|
||||
or :: proc { int_or, }
|
||||
bit_or :: proc { int_bit_or, }
|
||||
|
||||
/*
|
||||
2's complement `xor`, returns `dest = a ^ b;`
|
||||
*/
|
||||
int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
int_bit_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
assert_if_nil(dest, a, b)
|
||||
context.allocator = allocator
|
||||
|
||||
internal_clear_if_uninitialized(a, b) or_return
|
||||
return #force_inline internal_int_xor(dest, a, b)
|
||||
}
|
||||
xor :: proc { int_xor, }
|
||||
bit_xor :: proc { int_bit_xor, }
|
||||
|
||||
/*
|
||||
dest = ~src
|
||||
*/
|
||||
int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
int_bit_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||
/*
|
||||
Check that `src` and `dest` are usable.
|
||||
*/
|
||||
@@ -68,7 +68,7 @@ int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err:
|
||||
internal_clear_if_uninitialized(dest, src) or_return
|
||||
return #force_inline internal_int_complement(dest, src)
|
||||
}
|
||||
complement :: proc { int_complement, }
|
||||
bit_complement :: proc { int_bit_complement, }
|
||||
|
||||
/*
|
||||
quotient, remainder := numerator >> bits;
|
||||
|
||||
@@ -1163,7 +1163,7 @@ internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, all
|
||||
|
||||
/*
|
||||
If we didn't pass the sieve and step == MP_MAX then skip test */
|
||||
if (y && (step >= ((1 << _DIGIT_BITS) - kstep))) { continue }
|
||||
if y && (step >= ((1 << _DIGIT_BITS) - kstep)) { continue }
|
||||
|
||||
if internal_int_is_prime(a, trials) or_return { break }
|
||||
}
|
||||
@@ -1214,7 +1214,6 @@ internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags :=
|
||||
trials = number_of_rabin_miller_trials(size_in_bits)
|
||||
}
|
||||
|
||||
res: bool
|
||||
RANDOM_PRIME_ITERATIONS_USED = 0
|
||||
|
||||
for {
|
||||
@@ -1251,9 +1250,8 @@ internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags :=
|
||||
/*
|
||||
Is it prime?
|
||||
*/
|
||||
res = internal_int_is_prime(a, trials) or_return
|
||||
|
||||
if (!res) {
|
||||
res := internal_int_is_prime(a, trials) or_return
|
||||
if !res {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1267,9 +1265,11 @@ internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags :=
|
||||
/*
|
||||
Is it prime?
|
||||
*/
|
||||
res = internal_int_is_prime(a, trials) or_return
|
||||
res = internal_int_is_prime(a, trials) or_return
|
||||
}
|
||||
if res {
|
||||
break
|
||||
}
|
||||
if res { break }
|
||||
}
|
||||
|
||||
if .Safe in flags {
|
||||
|
||||
@@ -1089,7 +1089,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
|
||||
Step 3. for i from n down to (t + 1).
|
||||
*/
|
||||
#no_bounds_check for i := n; i >= (t + 1); i -= 1 {
|
||||
if (i > x.used) { continue }
|
||||
if i > x.used { continue }
|
||||
|
||||
/*
|
||||
step 3.1 if xi == yt then set q{i-t-1} to b-1, otherwise set q{i-t-1} to (xi*b + x{i-1})/yt
|
||||
|
||||
@@ -29,13 +29,13 @@ Fixed52_12 :: distinct Fixed(i64, 12)
|
||||
|
||||
|
||||
init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) {
|
||||
i, f := math.modf(val)
|
||||
i, f := math.modf(math.abs(val))
|
||||
x.i = Backing(f * (1<<Fraction_Width))
|
||||
x.i &= 1<<Fraction_Width - 1
|
||||
x.i |= Backing(i) << Fraction_Width
|
||||
if val < 0 do x.i *= -1
|
||||
}
|
||||
|
||||
|
||||
init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) {
|
||||
i, f := math.modf(val)
|
||||
x.i = fraction
|
||||
@@ -44,9 +44,11 @@ init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fracti
|
||||
}
|
||||
|
||||
to_f64 :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> f64 {
|
||||
res := f64(x.i >> Fraction_Width)
|
||||
res += f64(x.i & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width)
|
||||
return res
|
||||
sign := -1.0 if x.i < 0 else 1.0
|
||||
num := math.abs(x.i)
|
||||
res := f64(num >> Fraction_Width)
|
||||
res += f64(num & (1<<Fraction_Width-1)) / f64(1<<Fraction_Width)
|
||||
return res * sign
|
||||
}
|
||||
|
||||
|
||||
|
||||
+60
-40
@@ -1,9 +1,11 @@
|
||||
|
||||
/*
|
||||
Package core:math/rand implements various random number generators
|
||||
*/
|
||||
package rand
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:math"
|
||||
import "core:mem"
|
||||
|
||||
Rand :: struct {
|
||||
@@ -70,6 +72,7 @@ create :: proc(seed: u64) -> (res: Rand) {
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialises a random number generator.
|
||||
|
||||
@@ -95,9 +98,9 @@ Possible Output:
|
||||
init :: proc(r: ^Rand, seed: u64) {
|
||||
r.state = 0
|
||||
r.inc = (seed << 1) | 1
|
||||
_random(r)
|
||||
_random_u64(r)
|
||||
r.state += seed
|
||||
_random(r)
|
||||
_random_u64(r)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -107,7 +110,7 @@ On `linux` refer to the `getrandom` syscall.
|
||||
On `darwin` refer to `getentropy`.
|
||||
On `windows` refer to `BCryptGenRandom`.
|
||||
|
||||
All other platforms wi
|
||||
All other platforms are not supported
|
||||
|
||||
Inputs:
|
||||
- r: The random number generator to use the system random number generator
|
||||
@@ -139,11 +142,9 @@ init_as_system :: proc(r: ^Rand) {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_random :: proc(r: ^Rand) -> u32 {
|
||||
_random_u64 :: proc(r: ^Rand) -> u64 {
|
||||
r := r
|
||||
if r == nil {
|
||||
// NOTE(bill, 2020-09-07): Do this so that people can
|
||||
// enforce the global random state if necessary with `nil`
|
||||
r = &global_rand
|
||||
}
|
||||
when #defined(_system_random) {
|
||||
@@ -152,11 +153,12 @@ _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))
|
||||
xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081
|
||||
rot := (old_state >> 59)
|
||||
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63))
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -187,7 +189,7 @@ Possible Output:
|
||||
|
||||
*/
|
||||
@(require_results)
|
||||
uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return _random(r) }
|
||||
uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(r)) }
|
||||
|
||||
/*
|
||||
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
@@ -217,11 +219,7 @@ Possible Output:
|
||||
|
||||
*/
|
||||
@(require_results)
|
||||
uint64 :: proc(r: ^Rand = nil) -> (val: u64) {
|
||||
a := u64(_random(r))
|
||||
b := u64(_random(r))
|
||||
return (a<<32) | b
|
||||
}
|
||||
uint64 :: proc(r: ^Rand = nil) -> (val: u64) { return _random_u64(r) }
|
||||
|
||||
/*
|
||||
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
@@ -252,11 +250,9 @@ Possible Output:
|
||||
*/
|
||||
@(require_results)
|
||||
uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
|
||||
a := u128(_random(r))
|
||||
b := u128(_random(r))
|
||||
c := u128(_random(r))
|
||||
d := u128(_random(r))
|
||||
return (a<<96) | (b<<64) | (c<<32) | d
|
||||
a := u128(_random_u64(r))
|
||||
b := u128(_random_u64(r))
|
||||
return (a<<64) | b
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -288,6 +284,7 @@ Possible Output:
|
||||
|
||||
*/
|
||||
@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) }
|
||||
|
||||
/*
|
||||
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
||||
@@ -317,6 +314,7 @@ Possible Output:
|
||||
|
||||
*/
|
||||
@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) }
|
||||
|
||||
/*
|
||||
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
The sign bit will always be set to 0, thus all generated numbers will be positive.
|
||||
@@ -348,14 +346,14 @@ Possible Output:
|
||||
@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
|
||||
|
||||
/*
|
||||
Generates a random 31 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random 31 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- n: The upper bound of the generated number, this value is exclusive
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random 31 bit value in the range `(0, n]`
|
||||
- val: A random 31 bit value in the range `[0, n)`
|
||||
|
||||
WARNING: Panics if n is less than 0
|
||||
|
||||
@@ -392,15 +390,16 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
|
||||
}
|
||||
return v % n
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random 63 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random 63 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- n: The upper bound of the generated number, this value is exclusive
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random 63 bit value in the range `(0, n]`
|
||||
- val: A random 63 bit value in the range `[0, n)`
|
||||
|
||||
WARNING: Panics if n is less than 0
|
||||
|
||||
@@ -437,15 +436,16 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
|
||||
}
|
||||
return v % n
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random 127 bit value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random 127 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- n: The upper bound of the generated number, this value is exclusive
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random 127 bit value in the range `(0, n]`
|
||||
- val: A random 127 bit value in the range `[0, n)`
|
||||
|
||||
WARNING: Panics if n is less than 0
|
||||
|
||||
@@ -482,15 +482,16 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
|
||||
}
|
||||
return v % n
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random integer value in the range `(0, n]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random integer value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- n: The upper bound of the generated number, this value is exclusive
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random integer value in the range `(0, n]`
|
||||
- val: A random integer value in the range `[0, n)`
|
||||
|
||||
WARNING: Panics if n is less than 0
|
||||
|
||||
@@ -525,13 +526,13 @@ int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random double floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random double floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random double floating point value in the range `(0, 1]`
|
||||
- val: A random double floating point value in the range `[0, 1)`
|
||||
|
||||
Example:
|
||||
import "core:math/rand"
|
||||
@@ -554,13 +555,13 @@ Possible Output:
|
||||
@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
|
||||
|
||||
/*
|
||||
Generates a random single floating point value in the range `(0, 1]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random single floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random single floating point value in the range `(0, 1]`
|
||||
- val: A random single floating point value in the range `[0, 1)`
|
||||
|
||||
Example:
|
||||
import "core:math/rand"
|
||||
@@ -580,10 +581,12 @@ Possible Output:
|
||||
0.511
|
||||
|
||||
*/
|
||||
@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(float64(r)) }
|
||||
@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(int31_max(1<<24, r)) / (1 << 24) }
|
||||
|
||||
/*
|
||||
Generates a random double floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random double floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
WARNING: Panics if `high < low`
|
||||
|
||||
Inputs:
|
||||
- low: The lower bounds of the value, this value is inclusive
|
||||
@@ -591,7 +594,7 @@ Inputs:
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random double floating point value in the range `(low, high]`
|
||||
- val: A random double floating point value in the range [low, high)
|
||||
|
||||
Example:
|
||||
import "core:math/rand"
|
||||
@@ -611,9 +614,17 @@ Possible Output:
|
||||
673.130
|
||||
|
||||
*/
|
||||
@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) { return (high-low)*float64(r) + low }
|
||||
@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) {
|
||||
assert(low <= high, "low must be lower than or equal to high")
|
||||
val = (high-low)*float64(r) + low
|
||||
if val >= high {
|
||||
val = max(low, high * (1 - math.F64_EPSILON))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Generates a random single floating point value in the range `(low, high]` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Generates a random single floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
|
||||
Inputs:
|
||||
- low: The lower bounds of the value, this value is inclusive
|
||||
@@ -621,7 +632,9 @@ Inputs:
|
||||
- r: The random number generator to use, or nil for the global generator
|
||||
|
||||
Returns:
|
||||
- val: A random single floating point value in the range `(low, high]`
|
||||
- val: A random single floating point value in the range [low, high)
|
||||
|
||||
WARNING: Panics if `high < low`
|
||||
|
||||
Example:
|
||||
import "core:math/rand"
|
||||
@@ -641,10 +654,18 @@ Possible Output:
|
||||
673.130
|
||||
|
||||
*/
|
||||
@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) { return (high-low)*float32(r) + low }
|
||||
@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) {
|
||||
assert(low <= high, "low must be lower than or equal to high")
|
||||
val = (high-low)*float32(r) + low
|
||||
if val >= high {
|
||||
val = max(low, high * (1 - math.F32_EPSILON))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
|
||||
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
|
||||
|
||||
Inputs:
|
||||
- p: The byte slice to fill
|
||||
@@ -797,7 +818,6 @@ Example:
|
||||
fmt.println(rand.choice(data[:]))
|
||||
}
|
||||
|
||||
|
||||
Possible Output:
|
||||
|
||||
3
|
||||
|
||||
@@ -3,10 +3,10 @@ package rand
|
||||
import "core:sys/darwin"
|
||||
|
||||
@(require_results)
|
||||
_system_random :: proc() -> u32 {
|
||||
_system_random :: proc() -> u64 {
|
||||
for {
|
||||
value: u32
|
||||
ret := darwin.syscall_getentropy(([^]u8)(&value), 4)
|
||||
value: u64
|
||||
ret := darwin.syscall_getentropy(([^]u8)(&value), size_of(value))
|
||||
if ret < 0 {
|
||||
switch ret {
|
||||
case -4: // EINTR
|
||||
|
||||
@@ -3,10 +3,10 @@ package rand
|
||||
import "core:sys/unix"
|
||||
|
||||
@(require_results)
|
||||
_system_random :: proc() -> u32 {
|
||||
_system_random :: proc() -> u64 {
|
||||
for {
|
||||
value: u32
|
||||
ret := unix.sys_getrandom(([^]u8)(&value), 4, 0)
|
||||
value: u64
|
||||
ret := unix.sys_getrandom(([^]u8)(&value), size_of(value), 0)
|
||||
if ret < 0 {
|
||||
switch ret {
|
||||
case -4: // EINTR
|
||||
|
||||
@@ -3,9 +3,9 @@ package rand
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
@(require_results)
|
||||
_system_random :: proc() -> u32 {
|
||||
value: u32
|
||||
status := win32.BCryptGenRandom(nil, ([^]u8)(&value), 4, win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
|
||||
_system_random :: proc() -> u64 {
|
||||
value: u64
|
||||
status := win32.BCryptGenRandom(nil, ([^]u8)(&value), size_of(value), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)
|
||||
if status < 0 {
|
||||
panic("BCryptGenRandom failed")
|
||||
}
|
||||
|
||||
@@ -749,6 +749,7 @@ dynamic_pool_alloc_bytes :: proc(p: ^Dynamic_Pool, bytes: int) -> ([]byte, Alloc
|
||||
n := bytes
|
||||
extra := p.alignment - (n % p.alignment)
|
||||
n += extra
|
||||
if n > p.block_size do return nil, .Invalid_Argument
|
||||
if n >= p.out_band_size {
|
||||
assert(p.block_allocator.procedure != nil)
|
||||
memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ main :: proc() {
|
||||
_main()
|
||||
|
||||
for _, leak in track.allocation_map {
|
||||
fmt.printf("%v leaked %v bytes\n", leak.location, leak.size)
|
||||
fmt.printf("%v leaked %m\n", leak.location, leak.size)
|
||||
}
|
||||
for bad_free in track.bad_free_array {
|
||||
fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
|
||||
|
||||
@@ -8,6 +8,8 @@ Kilobyte :: runtime.Kilobyte
|
||||
Megabyte :: runtime.Megabyte
|
||||
Gigabyte :: runtime.Gigabyte
|
||||
Terabyte :: runtime.Terabyte
|
||||
Petabyte :: runtime.Petabyte
|
||||
Exabyte :: runtime.Exabyte
|
||||
|
||||
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
||||
return runtime.memset(data, i32(value), len)
|
||||
|
||||
@@ -133,7 +133,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
||||
return
|
||||
}
|
||||
|
||||
// Resets the memory of a Static or Buffer arena to a specific `pos`ition (offset) and zeroes the previously used memory.
|
||||
// Resets the memory of a Static or Buffer arena to a specific `position` (offset) and zeroes the previously used memory.
|
||||
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package mem_virtual
|
||||
|
||||
import "core:mem"
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
_ :: runtime
|
||||
|
||||
DEFAULT_PAGE_SIZE := uint(4096)
|
||||
|
||||
@@ -59,16 +61,22 @@ Memory_Block_Flag :: enum u32 {
|
||||
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
|
||||
|
||||
|
||||
@(private="file", require_results)
|
||||
align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint {
|
||||
result := size + align-1
|
||||
return result - result%align
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
align_formula :: proc "contextless" (size, align: uint) -> uint {
|
||||
result := size + align-1
|
||||
return result - result%align
|
||||
}
|
||||
|
||||
page_size := DEFAULT_PAGE_SIZE
|
||||
assert(mem.is_power_of_two(uintptr(page_size)))
|
||||
|
||||
committed := committed
|
||||
reserved := reserved
|
||||
|
||||
committed = align_formula(committed, page_size)
|
||||
reserved = align_formula(reserved, page_size)
|
||||
committed = clamp(committed, 0, reserved)
|
||||
|
||||
total_size := uint(reserved + size_of(Platform_Memory_Block))
|
||||
@@ -77,7 +85,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
|
||||
do_protection := false
|
||||
if .Overflow_Protection in flags { // overflow protection
|
||||
rounded_size := align_formula(uint(reserved), page_size)
|
||||
rounded_size := reserved
|
||||
total_size = uint(rounded_size + 2*page_size)
|
||||
base_offset = uintptr(page_size + rounded_size - uint(reserved))
|
||||
protect_offset = uintptr(page_size + rounded_size)
|
||||
@@ -86,14 +94,14 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
|
||||
pmblock := platform_memory_alloc(0, total_size) or_return
|
||||
|
||||
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset)
|
||||
pmblock.block.base = ([^]byte)(pmblock)[base_offset:]
|
||||
platform_memory_commit(pmblock, uint(base_offset) + committed) or_return
|
||||
|
||||
// Should be zeroed
|
||||
assert(pmblock.block.used == 0)
|
||||
assert(pmblock.block.prev == nil)
|
||||
if do_protection {
|
||||
protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access)
|
||||
protect(([^]byte)(pmblock)[protect_offset:], page_size, Protect_No_Access)
|
||||
}
|
||||
|
||||
pmblock.block.committed = committed
|
||||
@@ -119,7 +127,13 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint)
|
||||
if block.committed - block.used < size {
|
||||
pmblock := (^Platform_Memory_Block)(block)
|
||||
base_offset := uint(uintptr(pmblock.block.base) - uintptr(pmblock))
|
||||
platform_total_commit := base_offset + block.used + size
|
||||
|
||||
// NOTE(bill): [Heuristic] grow the commit size larger than needed
|
||||
// TODO(bill): determine a better heuristic for this behaviour
|
||||
extra_size := max(size, block.committed>>1)
|
||||
platform_total_commit := base_offset + block.used + extra_size
|
||||
platform_total_commit = align_formula(platform_total_commit, DEFAULT_PAGE_SIZE)
|
||||
platform_total_commit = min(platform_total_commit, pmblock.reserved)
|
||||
|
||||
assert(pmblock.committed <= pmblock.reserved)
|
||||
assert(pmblock.committed < platform_total_commit)
|
||||
@@ -128,8 +142,9 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint)
|
||||
|
||||
pmblock.committed = platform_total_commit
|
||||
block.committed = pmblock.committed - base_offset
|
||||
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
if block == nil {
|
||||
|
||||
+3
-3
@@ -471,7 +471,7 @@ join_port :: proc(address_or_host: string, port: int, allocator := context.alloc
|
||||
// hostname
|
||||
fmt.sbprintf(&b, "%v:%v", addr_or_host, port)
|
||||
} else {
|
||||
switch in addr {
|
||||
switch _ in addr {
|
||||
case IP4_Address:
|
||||
fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port)
|
||||
case IP6_Address:
|
||||
@@ -587,7 +587,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
|
||||
}
|
||||
|
||||
// Returns a temporarily-allocated string representation of the endpoint.
|
||||
// If there's a port, uses the `[address]:port` format.
|
||||
// If there's a port, uses the `ip4address:port` or `[ip6address]:port` format, respectively.
|
||||
endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string {
|
||||
if ep.port == 0 {
|
||||
return address_to_string(ep.address, allocator)
|
||||
@@ -606,7 +606,7 @@ to_string :: proc{address_to_string, endpoint_to_string}
|
||||
|
||||
|
||||
family_from_address :: proc(addr: Address) -> Address_Family {
|
||||
switch in addr {
|
||||
switch _ in addr {
|
||||
case IP4_Address: return .IP4
|
||||
case IP6_Address: return .IP6
|
||||
case:
|
||||
|
||||
+20
-32
@@ -96,7 +96,7 @@ resolve :: proc(hostname_and_maybe_port: string) -> (ep4, ep6: Endpoint, err: Ne
|
||||
switch t in target {
|
||||
case Endpoint:
|
||||
// NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it.
|
||||
switch in t.address {
|
||||
switch _ in t.address {
|
||||
case IP4_Address: ep4 = t
|
||||
case IP6_Address: ep6 = t
|
||||
case: unreachable()
|
||||
@@ -122,7 +122,7 @@ resolve_ip4 :: proc(hostname_and_maybe_port: string) -> (ep4: Endpoint, err: Net
|
||||
switch t in target {
|
||||
case Endpoint:
|
||||
// NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it.
|
||||
switch in t.address {
|
||||
switch _ in t.address {
|
||||
case IP4_Address:
|
||||
return t, nil
|
||||
case IP6_Address:
|
||||
@@ -149,7 +149,7 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net
|
||||
switch t in target {
|
||||
case Endpoint:
|
||||
// NOTE(tetra): The hostname was actually an IP address; nothing to resolve, so just return it.
|
||||
switch in t.address {
|
||||
switch _ in t.address {
|
||||
case IP4_Address:
|
||||
err = .Unable_To_Resolve
|
||||
return
|
||||
@@ -247,23 +247,19 @@ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type
|
||||
}
|
||||
defer close(conn)
|
||||
|
||||
_, send_err := send(conn, dns_packet[:], name_server)
|
||||
if send_err != nil {
|
||||
continue
|
||||
}
|
||||
_ = send(conn, dns_packet[:], name_server) or_continue
|
||||
|
||||
set_err := set_option(conn, .Receive_Timeout, time.Second * 1)
|
||||
if set_err != nil {
|
||||
if set_option(conn, .Receive_Timeout, time.Second * 1) != nil {
|
||||
return nil, .Connection_Error
|
||||
}
|
||||
|
||||
recv_sz, _, recv_err := recv_udp(conn, dns_response_buf[:])
|
||||
if recv_err == UDP_Recv_Error.Timeout {
|
||||
continue
|
||||
} else if recv_err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// recv_sz, _, recv_err := recv_udp(conn, dns_response_buf[:])
|
||||
// if recv_err == UDP_Recv_Error.Timeout {
|
||||
// continue
|
||||
// } else if recv_err != nil {
|
||||
// continue
|
||||
// }
|
||||
recv_sz, _ := recv_udp(conn, dns_response_buf[:]) or_continue
|
||||
if recv_sz == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -429,11 +425,9 @@ load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (
|
||||
}
|
||||
|
||||
for hostname in splits[1:] {
|
||||
if len(hostname) == 0 {
|
||||
continue
|
||||
if len(hostname) != 0 {
|
||||
append(&_hosts, DNS_Host_Entry{hostname, addr})
|
||||
}
|
||||
|
||||
append(&_hosts, DNS_Host_Entry{hostname, addr})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,11 +827,9 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
|
||||
}
|
||||
|
||||
rec := parse_record(response, &cur_idx, filter) or_return
|
||||
if rec == nil {
|
||||
continue
|
||||
if rec != nil {
|
||||
append(&_records, rec)
|
||||
}
|
||||
|
||||
append(&_records, rec)
|
||||
}
|
||||
|
||||
for _ in 0..<authority_count {
|
||||
@@ -846,11 +838,9 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
|
||||
}
|
||||
|
||||
rec := parse_record(response, &cur_idx, filter) or_return
|
||||
if rec == nil {
|
||||
continue
|
||||
if rec != nil {
|
||||
append(&_records, rec)
|
||||
}
|
||||
|
||||
append(&_records, rec)
|
||||
}
|
||||
|
||||
for _ in 0..<additional_count {
|
||||
@@ -859,11 +849,9 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
|
||||
}
|
||||
|
||||
rec := parse_record(response, &cur_idx, filter) or_return
|
||||
if rec == nil {
|
||||
continue
|
||||
if rec != nil {
|
||||
append(&_records, rec)
|
||||
}
|
||||
|
||||
append(&_records, rec)
|
||||
}
|
||||
|
||||
return _records[:], true
|
||||
|
||||
@@ -45,15 +45,22 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
|
||||
|
||||
count := 0
|
||||
for r := rec; r != nil; r = r.pNext {
|
||||
if r.wType != u16(type) do continue // NOTE(tetra): Should never happen, but...
|
||||
if r.wType != u16(type) {
|
||||
// NOTE(tetra): Should never happen, but...
|
||||
continue
|
||||
}
|
||||
count += 1
|
||||
}
|
||||
|
||||
recs := make([dynamic]DNS_Record, 0, count)
|
||||
if recs == nil do return nil, .System_Error // return no results if OOM.
|
||||
if recs == nil {
|
||||
return nil, .System_Error // return no results if OOM.
|
||||
}
|
||||
|
||||
for r := rec; r != nil; r = r.pNext {
|
||||
if r.wType != u16(type) do continue // NOTE(tetra): Should never happen, but...
|
||||
if r.wType != u16(type) {
|
||||
continue // NOTE(tetra): Should never happen, but...
|
||||
}
|
||||
|
||||
base_record := DNS_Record_Base{
|
||||
record_name = strings.clone(string(r.pName)),
|
||||
|
||||
@@ -109,12 +109,12 @@ TCP_Recv_Error :: enum c.int {
|
||||
}
|
||||
|
||||
UDP_Recv_Error :: enum c.int {
|
||||
None = 0,
|
||||
Truncated = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated.
|
||||
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
|
||||
Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor.
|
||||
Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory.
|
||||
Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7).
|
||||
None = 0,
|
||||
Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
|
||||
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
|
||||
Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor.
|
||||
Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory.
|
||||
Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7).
|
||||
|
||||
// The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
|
||||
// NOTE: No, really. Presumably this means something different for nonblocking sockets...
|
||||
@@ -122,11 +122,9 @@ UDP_Recv_Error :: enum c.int {
|
||||
Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't.
|
||||
}
|
||||
|
||||
// TODO
|
||||
TCP_Send_Error :: enum c.int {
|
||||
None = 0,
|
||||
|
||||
// TODO: merge with other errors?
|
||||
Aborted = c.int(os.ECONNABORTED),
|
||||
Connection_Closed = c.int(os.ECONNRESET),
|
||||
Not_Connected = c.int(os.ENOTCONN),
|
||||
@@ -151,7 +149,7 @@ TCP_Send_Error :: enum c.int {
|
||||
// TODO
|
||||
UDP_Send_Error :: enum c.int {
|
||||
None = 0,
|
||||
Truncated = c.int(os.EMSGSIZE), // The message is too big. No data was sent.
|
||||
Message_Too_Long = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent.
|
||||
|
||||
// TODO: not sure what the exact circumstances for this is yet
|
||||
Network_Unreachable = c.int(os.ENETUNREACH),
|
||||
|
||||
@@ -105,9 +105,7 @@ TCP_Recv_Error :: enum c.int {
|
||||
UDP_Recv_Error :: enum c.int {
|
||||
None = 0,
|
||||
|
||||
// The buffer is too small to fit the entire message, and the message was truncated.
|
||||
// When this happens, the rest of message is lost.
|
||||
Buffer_Too_Small = c.int(os.EMSGSIZE),
|
||||
Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
|
||||
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
|
||||
Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor.
|
||||
Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory.
|
||||
@@ -119,10 +117,8 @@ UDP_Recv_Error :: enum c.int {
|
||||
Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't.
|
||||
}
|
||||
|
||||
// TODO
|
||||
TCP_Send_Error :: enum c.int {
|
||||
None = 0,
|
||||
// TODO(tetra): merge with other errors?
|
||||
Aborted = c.int(os.ECONNABORTED),
|
||||
Connection_Closed = c.int(os.ECONNRESET),
|
||||
Not_Connected = c.int(os.ENOTCONN),
|
||||
@@ -135,16 +131,16 @@ TCP_Send_Error :: enum c.int {
|
||||
// doesn't fit in the send queue.
|
||||
No_Buffer_Space_Available = c.int(os.ENOBUFS),
|
||||
Offline = c.int(os.ENETDOWN),
|
||||
Host_Unreachable = c.int(os.EHOSTUNREACH), // A signal occurred before any data was transmitted. See signal(7).
|
||||
Interrupted = c.int(os.EINTR), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
|
||||
Timeout = c.int(os.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets...
|
||||
Host_Unreachable = c.int(os.EHOSTUNREACH),
|
||||
Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7).
|
||||
Timeout = c.int(os.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
|
||||
Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
|
||||
}
|
||||
|
||||
// TODO
|
||||
UDP_Send_Error :: enum c.int {
|
||||
None = 0,
|
||||
Message_Too_Long = c.int(os.EMSGSIZE), // The message is too big. No data was sent.
|
||||
Message_Too_Long = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent.
|
||||
|
||||
// TODO: not sure what the exact circumstances for this is yet
|
||||
Network_Unreachable = c.int(os.ENETUNREACH),
|
||||
|
||||
@@ -92,8 +92,6 @@ TCP_Recv_Error :: enum c.int {
|
||||
Not_Socket = win.WSAENOTSOCK,
|
||||
Shutdown = win.WSAESHUTDOWN,
|
||||
Would_Block = win.WSAEWOULDBLOCK,
|
||||
|
||||
// TODO: not functionally different from Reset; merge?
|
||||
Aborted = win.WSAECONNABORTED,
|
||||
Timeout = win.WSAETIMEDOUT,
|
||||
|
||||
@@ -107,11 +105,8 @@ TCP_Recv_Error :: enum c.int {
|
||||
UDP_Recv_Error :: enum c.int {
|
||||
None = 0,
|
||||
Network_Subsystem_Failure = win.WSAENETDOWN,
|
||||
|
||||
// TODO: not functionally different from Reset; merge?
|
||||
// UDP packets are limited in size, and the length of the incoming message exceeded it.
|
||||
Aborted = win.WSAECONNABORTED,
|
||||
Truncated = win.WSAEMSGSIZE,
|
||||
Aborted = win.WSAECONNABORTED,
|
||||
Buffer_Too_Small = win.WSAEMSGSIZE, // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
|
||||
Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
|
||||
Shutdown = win.WSAESHUTDOWN,
|
||||
Broadcast_Disabled = win.WSAEACCES, // A broadcast address was specified, but the .Broadcast socket option isn't set.
|
||||
@@ -133,7 +128,6 @@ UDP_Recv_Error :: enum c.int {
|
||||
TCP_Send_Error :: enum c.int {
|
||||
None = 0,
|
||||
|
||||
// TODO: not functionally different from Reset; merge?
|
||||
Aborted = win.WSAECONNABORTED,
|
||||
Not_Connected = win.WSAENOTCONN,
|
||||
Shutdown = win.WSAESHUTDOWN,
|
||||
@@ -159,10 +153,9 @@ UDP_Send_Error :: enum c.int {
|
||||
None = 0,
|
||||
Network_Subsystem_Failure = win.WSAENETDOWN,
|
||||
|
||||
// TODO: not functionally different from Reset; merge?
|
||||
Aborted = win.WSAECONNABORTED, // UDP packets are limited in size, and len(buf) exceeded it.
|
||||
Message_Too_Long = win.WSAEMSGSIZE, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
|
||||
Remote_Not_Listening = win.WSAECONNRESET,
|
||||
Aborted = win.WSAECONNABORTED,
|
||||
Message_Too_Long = win.WSAEMSGSIZE, // The message is larger than the maximum UDP packet size.
|
||||
Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data.
|
||||
Shutdown = win.WSAESHUTDOWN, // A broadcast address was specified, but the .Broadcast socket option isn't set.
|
||||
Broadcast_Disabled = win.WSAEACCES,
|
||||
Bad_Buffer = win.WSAEFAULT, // Connection is broken due to keepalive activity detecting a failure during the operation.
|
||||
|
||||
+39
-5
@@ -284,6 +284,13 @@ Or_Return_Expr :: struct {
|
||||
token: tokenizer.Token,
|
||||
}
|
||||
|
||||
Or_Branch_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
token: tokenizer.Token,
|
||||
label: ^Expr,
|
||||
}
|
||||
|
||||
Type_Assertion :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
@@ -419,6 +426,7 @@ Range_Stmt :: struct {
|
||||
in_pos: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
body: ^Stmt,
|
||||
reverse: bool,
|
||||
}
|
||||
|
||||
Inline_Range_Stmt :: struct {
|
||||
@@ -543,8 +551,8 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
|
||||
return
|
||||
}
|
||||
for {
|
||||
e, ok := val.derived.(^Paren_Expr)
|
||||
if !ok || e.expr == nil {
|
||||
e := val.derived.(^Paren_Expr) or_break
|
||||
if e.expr == nil {
|
||||
break
|
||||
}
|
||||
val = e.expr
|
||||
@@ -552,6 +560,29 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
|
||||
return
|
||||
}
|
||||
|
||||
strip_or_return_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
|
||||
val = expr
|
||||
if expr == nil {
|
||||
return
|
||||
}
|
||||
for {
|
||||
inner: ^Expr
|
||||
#partial switch e in val.derived {
|
||||
case ^Or_Return_Expr:
|
||||
inner = e.expr
|
||||
case ^Or_Branch_Expr:
|
||||
inner = e.expr
|
||||
case ^Paren_Expr:
|
||||
inner = e.expr
|
||||
}
|
||||
if inner == nil {
|
||||
break
|
||||
}
|
||||
val = inner
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Field_Flags :: distinct bit_set[Field_Flag]
|
||||
|
||||
Field_Flag :: enum {
|
||||
@@ -562,7 +593,7 @@ Field_Flag :: enum {
|
||||
Using,
|
||||
No_Alias,
|
||||
C_Vararg,
|
||||
Auto_Cast,
|
||||
Const,
|
||||
Any_Int,
|
||||
Subtype,
|
||||
By_Ptr,
|
||||
@@ -581,7 +612,7 @@ field_flag_strings := [Field_Flag]string{
|
||||
.Using = "using",
|
||||
.No_Alias = "#no_alias",
|
||||
.C_Vararg = "#c_vararg",
|
||||
.Auto_Cast = "auto_cast",
|
||||
.Const = "#const",
|
||||
.Any_Int = "#any_int",
|
||||
.Subtype = "#subtype",
|
||||
.By_Ptr = "#by_ptr",
|
||||
@@ -595,6 +626,7 @@ field_flag_strings := [Field_Flag]string{
|
||||
field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{
|
||||
{"no_alias", .No_Alias},
|
||||
{"c_vararg", .C_Vararg},
|
||||
{"const", .Const},
|
||||
{"any_int", .Any_Int},
|
||||
{"subtype", .Subtype},
|
||||
{"by_ptr", .By_Ptr},
|
||||
@@ -615,7 +647,7 @@ Field_Flags_Signature :: Field_Flags{
|
||||
.Using,
|
||||
.No_Alias,
|
||||
.C_Vararg,
|
||||
.Auto_Cast,
|
||||
.Const,
|
||||
.Any_Int,
|
||||
.By_Ptr,
|
||||
.Default_Parameters,
|
||||
@@ -837,6 +869,7 @@ Any_Node :: union {
|
||||
^Ternary_When_Expr,
|
||||
^Or_Else_Expr,
|
||||
^Or_Return_Expr,
|
||||
^Or_Branch_Expr,
|
||||
^Type_Assertion,
|
||||
^Type_Cast,
|
||||
^Auto_Cast,
|
||||
@@ -920,6 +953,7 @@ Any_Expr :: union {
|
||||
^Ternary_When_Expr,
|
||||
^Or_Else_Expr,
|
||||
^Or_Return_Expr,
|
||||
^Or_Branch_Expr,
|
||||
^Type_Assertion,
|
||||
^Type_Cast,
|
||||
^Auto_Cast,
|
||||
|
||||
@@ -77,7 +77,7 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
||||
align = elem.align
|
||||
}
|
||||
|
||||
#partial switch in node.derived {
|
||||
#partial switch _ in node.derived {
|
||||
case ^Package, ^File:
|
||||
panic("Cannot clone this node type")
|
||||
}
|
||||
@@ -147,8 +147,8 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
||||
r.expr = clone(r.expr)
|
||||
r.index = clone(r.index)
|
||||
case ^Matrix_Index_Expr:
|
||||
r.expr = clone(r.expr)
|
||||
r.row_index = clone(r.row_index)
|
||||
r.expr = clone(r.expr)
|
||||
r.row_index = clone(r.row_index)
|
||||
r.column_index = clone(r.column_index)
|
||||
case ^Deref_Expr:
|
||||
r.expr = clone(r.expr)
|
||||
@@ -175,6 +175,9 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
||||
r.y = clone(r.y)
|
||||
case ^Or_Return_Expr:
|
||||
r.expr = clone(r.expr)
|
||||
case ^Or_Branch_Expr:
|
||||
r.expr = clone(r.expr)
|
||||
r.label = clone(r.label)
|
||||
case ^Type_Assertion:
|
||||
r.expr = clone(r.expr)
|
||||
r.type = clone(r.type)
|
||||
|
||||
@@ -146,6 +146,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
||||
walk(v, n.y)
|
||||
case ^Or_Return_Expr:
|
||||
walk(v, n.expr)
|
||||
case ^Or_Branch_Expr:
|
||||
walk(v, n.expr)
|
||||
if n.label != nil {
|
||||
walk(v, n.label)
|
||||
}
|
||||
case ^Type_Assertion:
|
||||
walk(v, n.expr)
|
||||
if n.type != nil {
|
||||
|
||||
@@ -162,31 +162,31 @@ Attribute :: struct {
|
||||
}
|
||||
|
||||
Type_Kind :: enum u32le {
|
||||
Invalid = 0,
|
||||
Basic = 1,
|
||||
Named = 2,
|
||||
Generic = 3,
|
||||
Pointer = 4,
|
||||
Array = 5,
|
||||
Enumerated_Array = 6,
|
||||
Slice = 7,
|
||||
Dynamic_Array = 8,
|
||||
Map = 9,
|
||||
Struct = 10,
|
||||
Union = 11,
|
||||
Enum = 12,
|
||||
Tuple = 13,
|
||||
Proc = 14,
|
||||
Bit_Set = 15,
|
||||
Simd_Vector = 16,
|
||||
SOA_Struct_Fixed = 17,
|
||||
SOA_Struct_Slice = 18,
|
||||
SOA_Struct_Dynamic = 19,
|
||||
Relative_Pointer = 20,
|
||||
Relative_Slice = 21,
|
||||
Multi_Pointer = 22,
|
||||
Matrix = 23,
|
||||
Soa_Pointer = 24,
|
||||
Invalid = 0,
|
||||
Basic = 1,
|
||||
Named = 2,
|
||||
Generic = 3,
|
||||
Pointer = 4,
|
||||
Array = 5,
|
||||
Enumerated_Array = 6,
|
||||
Slice = 7,
|
||||
Dynamic_Array = 8,
|
||||
Map = 9,
|
||||
Struct = 10,
|
||||
Union = 11,
|
||||
Enum = 12,
|
||||
Tuple = 13,
|
||||
Proc = 14,
|
||||
Bit_Set = 15,
|
||||
Simd_Vector = 16,
|
||||
SOA_Struct_Fixed = 17,
|
||||
SOA_Struct_Slice = 18,
|
||||
SOA_Struct_Dynamic = 19,
|
||||
Relative_Pointer = 20,
|
||||
Relative_Multi_Pointer = 21,
|
||||
Multi_Pointer = 22,
|
||||
Matrix = 23,
|
||||
Soa_Pointer = 24,
|
||||
}
|
||||
|
||||
Type_Elems_Cap :: 4
|
||||
|
||||
@@ -420,7 +420,7 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token {
|
||||
if allow_token(p, .Close_Brace) {
|
||||
return token
|
||||
}
|
||||
if allow_token(p, .Semicolon) {
|
||||
if allow_token(p, .Semicolon) && !tokenizer.is_newline(token) {
|
||||
str := tokenizer.token_to_string(token)
|
||||
error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str)
|
||||
}
|
||||
@@ -1053,9 +1053,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
|
||||
}
|
||||
append(&elems, elem)
|
||||
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
}
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
p.expr_level -= 1
|
||||
close = expect_token_after(p, close_kind, "attribute")
|
||||
@@ -1091,7 +1089,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
|
||||
|
||||
parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
decl := parse_stmt(p)
|
||||
#partial switch in decl.derived_stmt {
|
||||
#partial switch _ in decl.derived_stmt {
|
||||
case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl:
|
||||
// Ignore
|
||||
return nil
|
||||
@@ -1174,9 +1172,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
|
||||
path := expect_token(p, .String)
|
||||
append(&fullpaths, path.text)
|
||||
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
}
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
expect_token(p, .Close_Brace)
|
||||
} else {
|
||||
@@ -1431,6 +1427,18 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
return es
|
||||
case "unroll":
|
||||
return parse_unrolled_for_loop(p, tag)
|
||||
case "reverse":
|
||||
stmt := parse_for_stmt(p)
|
||||
|
||||
if range, is_range := stmt.derived.(^ast.Range_Stmt); is_range {
|
||||
if range.reverse {
|
||||
error(p, range.pos, "#reverse already applied to a 'for in' statement")
|
||||
}
|
||||
range.reverse = true
|
||||
} else {
|
||||
error(p, range.pos, "#reverse can only be applied to a 'for in' statement")
|
||||
}
|
||||
return stmt
|
||||
case "include":
|
||||
error(p, tag.pos, "#include is not a valid import declaration kind. Did you meant 'import'?")
|
||||
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag))
|
||||
@@ -1654,9 +1662,6 @@ is_token_field_prefix :: proc(p: ^Parser) -> ast.Field_Flag {
|
||||
case .Using:
|
||||
advance_token(p)
|
||||
return .Using
|
||||
case .Auto_Cast:
|
||||
advance_token(p)
|
||||
return .Auto_Cast
|
||||
case .Hash:
|
||||
tok: tokenizer.Token
|
||||
advance_token(p)
|
||||
@@ -1836,7 +1841,9 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
||||
return true
|
||||
}
|
||||
if allow_token(p, .Semicolon) {
|
||||
error(p, tok.pos, "expected a comma, got a semicolon")
|
||||
if !tokenizer.is_newline(tok) {
|
||||
error(p, tok.pos, "expected a comma, got a semicolon")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -1950,9 +1957,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
||||
|
||||
eaf := Expr_And_Flags{param, prefix_flags}
|
||||
append(&list, eaf)
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
}
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
|
||||
if p.curr_tok.kind != .Colon {
|
||||
@@ -2000,10 +2005,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
||||
names = parse_ident_list(p, allow_poly_names)
|
||||
|
||||
total_name_count += len(names)
|
||||
ok := handle_field(p, &seen_ellipsis, &fields, docs, names, allowed_flags, set_flags)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
handle_field(p, &seen_ellipsis, &fields, docs, names, allowed_flags, set_flags) or_break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2139,7 +2141,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
|
||||
}
|
||||
}
|
||||
|
||||
#partial switch e in ast.unparen_expr(expr).derived_expr {
|
||||
#partial switch e in ast.strip_or_return_expr(expr).derived_expr {
|
||||
case ^ast.Proc_Lit:
|
||||
if e.inlining != .None && e.inlining != pi {
|
||||
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal")
|
||||
@@ -2350,9 +2352,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
elem := parse_expr(p, false)
|
||||
append(&args, elem)
|
||||
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
}
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
|
||||
close := expect_token(p, .Close_Brace)
|
||||
@@ -2685,9 +2685,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
if _, ok := type.derived.(^ast.Bad_Expr); !ok {
|
||||
append(&variants, type)
|
||||
}
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
}
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
|
||||
close := expect_closing_brace_of_field_list(p)
|
||||
@@ -2905,9 +2903,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
|
||||
|
||||
append(&elems, elem)
|
||||
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
}
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
|
||||
return elems[:]
|
||||
@@ -2941,9 +2937,9 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
|
||||
p.expr_level += 1
|
||||
open := expect_token(p, .Open_Paren)
|
||||
|
||||
seen_ellipsis := false
|
||||
for p.curr_tok.kind != .Close_Paren &&
|
||||
p.curr_tok.kind != .EOF &&
|
||||
ellipsis.pos.line == 0 {
|
||||
p.curr_tok.kind != .EOF {
|
||||
|
||||
if p.curr_tok.kind == .Comma {
|
||||
error(p, p.curr_tok.pos, "expected an expression not ,")
|
||||
@@ -2972,13 +2968,17 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
|
||||
fv.value = value
|
||||
|
||||
arg = fv
|
||||
} else if seen_ellipsis {
|
||||
error(p, arg.pos, "Positional arguments are not allowed after '..'")
|
||||
}
|
||||
|
||||
append(&args, arg)
|
||||
|
||||
if !allow_token(p, .Comma) {
|
||||
break
|
||||
if ellipsis.pos.line != 0 {
|
||||
seen_ellipsis = true
|
||||
}
|
||||
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
|
||||
close := expect_token_after(p, .Close_Paren, "argument list")
|
||||
@@ -3173,6 +3173,23 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
||||
|
||||
operand = oe
|
||||
|
||||
case .Or_Break, .Or_Continue:
|
||||
token := advance_token(p)
|
||||
label: ^ast.Ident
|
||||
|
||||
end := end_pos(token)
|
||||
if p.curr_tok.kind == .Ident {
|
||||
end = end_pos(p.curr_tok)
|
||||
label = parse_ident(p)
|
||||
}
|
||||
|
||||
oe := ast.new(ast.Or_Branch_Expr, operand.pos, end)
|
||||
oe.expr = operand
|
||||
oe.token = token
|
||||
oe.label = label
|
||||
|
||||
operand = oe
|
||||
|
||||
case .Open_Brace:
|
||||
if !is_lhs && is_literal_type(operand) && p.expr_level >= 0 {
|
||||
operand = parse_literal_value(p, operand)
|
||||
|
||||
@@ -972,6 +972,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
||||
case ^ast.Or_Return_Expr:
|
||||
visit_expr(p, v.expr)
|
||||
push_generic_token(p, v.token.kind, 1)
|
||||
case ^ast.Or_Branch_Expr:
|
||||
visit_expr(p, v.expr)
|
||||
push_generic_token(p, v.token.kind, 1)
|
||||
if v.label != nil {
|
||||
visit_expr(p, v.label)
|
||||
}
|
||||
|
||||
case ^ast.Selector_Call_Expr:
|
||||
visit_expr(p, v.call.expr)
|
||||
push_generic_token(p, .Open_Paren, 1)
|
||||
|
||||
@@ -147,6 +147,8 @@ Token_Kind :: enum u32 {
|
||||
Context, // context
|
||||
Or_Else, // or_else
|
||||
Or_Return, // or_return
|
||||
Or_Break, // or_break
|
||||
Or_Continue, // or_continue
|
||||
Asm, // asm
|
||||
Inline, // inline
|
||||
No_Inline, // no_inline
|
||||
@@ -278,6 +280,8 @@ tokens := [Token_Kind.COUNT]string {
|
||||
"context",
|
||||
"or_else",
|
||||
"or_return",
|
||||
"or_break",
|
||||
"or_continue",
|
||||
"asm",
|
||||
"inline",
|
||||
"no_inline",
|
||||
|
||||
@@ -124,7 +124,7 @@ Allocation_Header :: struct #raw_union {
|
||||
requested: u64,
|
||||
}
|
||||
|
||||
Region_Header :: struct #align 16 {
|
||||
Region_Header :: struct #align(16) {
|
||||
next_region: ^Region, // points to next region in global_heap (linked list)
|
||||
local_addr: ^^Region, // tracks region ownership via address of _local_region
|
||||
reset_addr: ^^Region, // tracks old local addr for reset
|
||||
|
||||
@@ -441,7 +441,7 @@ pollfd :: struct {
|
||||
sigset_t :: distinct u64
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
||||
@(link_name="__errno_location") __errno_location :: proc() -> ^c.int ---
|
||||
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int ---
|
||||
@@ -488,7 +488,7 @@ _get_errno :: proc(res: int) -> Errno {
|
||||
|
||||
// get errno from libc
|
||||
get_last_error :: proc "contextless" () -> int {
|
||||
return __errno_location()^
|
||||
return int(__errno_location()^)
|
||||
}
|
||||
|
||||
personality :: proc(persona: u64) -> (Errno) {
|
||||
|
||||
@@ -99,9 +99,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
|
||||
case ']':
|
||||
in_range = false
|
||||
case '*':
|
||||
if !in_range {
|
||||
break scan_loop
|
||||
}
|
||||
in_range or_break scan_loop
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,9 +392,8 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
|
||||
for ti < tl && target[ti] != SEPARATOR {
|
||||
ti += 1
|
||||
}
|
||||
if !strings.equal_fold(target[t0:ti], base[b0:bi]) {
|
||||
break
|
||||
}
|
||||
strings.equal_fold(target[t0:ti], base[b0:bi]) or_break
|
||||
|
||||
if bi < bl {
|
||||
bi += 1
|
||||
}
|
||||
@@ -416,7 +415,7 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
|
||||
}
|
||||
buf := make([]byte, size)
|
||||
n := copy(buf, "..")
|
||||
for in 0..<seps {
|
||||
for _ in 0..<seps {
|
||||
buf[n] = SEPARATOR
|
||||
copy(buf[n+1:], "..")
|
||||
n += 3
|
||||
|
||||
@@ -93,10 +93,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
|
||||
case ']':
|
||||
in_range = false
|
||||
case '*':
|
||||
if !in_range {
|
||||
break scan_loop
|
||||
}
|
||||
|
||||
in_range or_break scan_loop
|
||||
}
|
||||
}
|
||||
return star, pattern[:i], pattern[i:]
|
||||
|
||||
+59
-60
@@ -8,35 +8,35 @@ _ :: intrinsics
|
||||
|
||||
Type_Info :: runtime.Type_Info
|
||||
|
||||
Type_Info_Named :: runtime.Type_Info_Named
|
||||
Type_Info_Integer :: runtime.Type_Info_Integer
|
||||
Type_Info_Rune :: runtime.Type_Info_Rune
|
||||
Type_Info_Float :: runtime.Type_Info_Float
|
||||
Type_Info_Complex :: runtime.Type_Info_Complex
|
||||
Type_Info_Quaternion :: runtime.Type_Info_Quaternion
|
||||
Type_Info_String :: runtime.Type_Info_String
|
||||
Type_Info_Boolean :: runtime.Type_Info_Boolean
|
||||
Type_Info_Any :: runtime.Type_Info_Any
|
||||
Type_Info_Type_Id :: runtime.Type_Info_Type_Id
|
||||
Type_Info_Pointer :: runtime.Type_Info_Pointer
|
||||
Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer
|
||||
Type_Info_Procedure :: runtime.Type_Info_Procedure
|
||||
Type_Info_Array :: runtime.Type_Info_Array
|
||||
Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array
|
||||
Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array
|
||||
Type_Info_Slice :: runtime.Type_Info_Slice
|
||||
Type_Info_Parameters :: runtime.Type_Info_Parameters
|
||||
Type_Info_Tuple :: runtime.Type_Info_Parameters
|
||||
Type_Info_Struct :: runtime.Type_Info_Struct
|
||||
Type_Info_Union :: runtime.Type_Info_Union
|
||||
Type_Info_Enum :: runtime.Type_Info_Enum
|
||||
Type_Info_Map :: runtime.Type_Info_Map
|
||||
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
||||
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
|
||||
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
|
||||
Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice
|
||||
Type_Info_Matrix :: runtime.Type_Info_Matrix
|
||||
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
||||
Type_Info_Named :: runtime.Type_Info_Named
|
||||
Type_Info_Integer :: runtime.Type_Info_Integer
|
||||
Type_Info_Rune :: runtime.Type_Info_Rune
|
||||
Type_Info_Float :: runtime.Type_Info_Float
|
||||
Type_Info_Complex :: runtime.Type_Info_Complex
|
||||
Type_Info_Quaternion :: runtime.Type_Info_Quaternion
|
||||
Type_Info_String :: runtime.Type_Info_String
|
||||
Type_Info_Boolean :: runtime.Type_Info_Boolean
|
||||
Type_Info_Any :: runtime.Type_Info_Any
|
||||
Type_Info_Type_Id :: runtime.Type_Info_Type_Id
|
||||
Type_Info_Pointer :: runtime.Type_Info_Pointer
|
||||
Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer
|
||||
Type_Info_Procedure :: runtime.Type_Info_Procedure
|
||||
Type_Info_Array :: runtime.Type_Info_Array
|
||||
Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array
|
||||
Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array
|
||||
Type_Info_Slice :: runtime.Type_Info_Slice
|
||||
Type_Info_Parameters :: runtime.Type_Info_Parameters
|
||||
Type_Info_Tuple :: runtime.Type_Info_Parameters
|
||||
Type_Info_Struct :: runtime.Type_Info_Struct
|
||||
Type_Info_Union :: runtime.Type_Info_Union
|
||||
Type_Info_Enum :: runtime.Type_Info_Enum
|
||||
Type_Info_Map :: runtime.Type_Info_Map
|
||||
Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set
|
||||
Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
|
||||
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
|
||||
Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer
|
||||
Type_Info_Matrix :: runtime.Type_Info_Matrix
|
||||
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
|
||||
|
||||
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
|
||||
|
||||
@@ -69,7 +69,7 @@ Type_Kind :: enum {
|
||||
Bit_Set,
|
||||
Simd_Vector,
|
||||
Relative_Pointer,
|
||||
Relative_Slice,
|
||||
Relative_Multi_Pointer,
|
||||
Matrix,
|
||||
Soa_Pointer,
|
||||
}
|
||||
@@ -80,34 +80,34 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
ti := type_info_of(T)
|
||||
if ti != nil {
|
||||
switch _ in ti.variant {
|
||||
case Type_Info_Named: return .Named
|
||||
case Type_Info_Integer: return .Integer
|
||||
case Type_Info_Rune: return .Rune
|
||||
case Type_Info_Float: return .Float
|
||||
case Type_Info_Complex: return .Complex
|
||||
case Type_Info_Quaternion: return .Quaternion
|
||||
case Type_Info_String: return .String
|
||||
case Type_Info_Boolean: return .Boolean
|
||||
case Type_Info_Any: return .Any
|
||||
case Type_Info_Type_Id: return .Type_Id
|
||||
case Type_Info_Pointer: return .Pointer
|
||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||
case Type_Info_Procedure: return .Procedure
|
||||
case Type_Info_Array: return .Array
|
||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||
case Type_Info_Slice: return .Slice
|
||||
case Type_Info_Parameters: return .Tuple
|
||||
case Type_Info_Struct: return .Struct
|
||||
case Type_Info_Union: return .Union
|
||||
case Type_Info_Enum: return .Enum
|
||||
case Type_Info_Map: return .Map
|
||||
case Type_Info_Bit_Set: return .Bit_Set
|
||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||
case Type_Info_Relative_Pointer: return .Relative_Pointer
|
||||
case Type_Info_Relative_Slice: return .Relative_Slice
|
||||
case Type_Info_Matrix: return .Matrix
|
||||
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||
case Type_Info_Named: return .Named
|
||||
case Type_Info_Integer: return .Integer
|
||||
case Type_Info_Rune: return .Rune
|
||||
case Type_Info_Float: return .Float
|
||||
case Type_Info_Complex: return .Complex
|
||||
case Type_Info_Quaternion: return .Quaternion
|
||||
case Type_Info_String: return .String
|
||||
case Type_Info_Boolean: return .Boolean
|
||||
case Type_Info_Any: return .Any
|
||||
case Type_Info_Type_Id: return .Type_Id
|
||||
case Type_Info_Pointer: return .Pointer
|
||||
case Type_Info_Multi_Pointer: return .Multi_Pointer
|
||||
case Type_Info_Procedure: return .Procedure
|
||||
case Type_Info_Array: return .Array
|
||||
case Type_Info_Enumerated_Array: return .Enumerated_Array
|
||||
case Type_Info_Dynamic_Array: return .Dynamic_Array
|
||||
case Type_Info_Slice: return .Slice
|
||||
case Type_Info_Parameters: return .Tuple
|
||||
case Type_Info_Struct: return .Struct
|
||||
case Type_Info_Union: return .Union
|
||||
case Type_Info_Enum: return .Enum
|
||||
case Type_Info_Map: return .Map
|
||||
case Type_Info_Bit_Set: return .Bit_Set
|
||||
case Type_Info_Simd_Vector: return .Simd_Vector
|
||||
case Type_Info_Relative_Pointer: return .Relative_Pointer
|
||||
case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer
|
||||
case Type_Info_Matrix: return .Matrix
|
||||
case Type_Info_Soa_Pointer: return .Soa_Pointer
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1457,8 +1457,6 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
return equal(va, vb, including_indirect_array_recursion, recursion_level+1)
|
||||
case Type_Info_Map:
|
||||
return false
|
||||
case Type_Info_Relative_Slice:
|
||||
return false
|
||||
case
|
||||
Type_Info_Boolean,
|
||||
Type_Info_Integer,
|
||||
@@ -1474,6 +1472,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
|
||||
Type_Info_Enum,
|
||||
Type_Info_Simd_Vector,
|
||||
Type_Info_Relative_Pointer,
|
||||
Type_Info_Relative_Multi_Pointer,
|
||||
Type_Info_Soa_Pointer,
|
||||
Type_Info_Matrix:
|
||||
return runtime.memory_compare(a.data, b.data, t.size) == 0
|
||||
|
||||
+11
-12
@@ -165,9 +165,9 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
y := b.variant.(Type_Info_Relative_Pointer) or_return
|
||||
return x.base_integer == y.base_integer && x.pointer == y.pointer
|
||||
|
||||
case Type_Info_Relative_Slice:
|
||||
y := b.variant.(Type_Info_Relative_Slice) or_return
|
||||
return x.base_integer == y.base_integer && x.slice == y.slice
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
y := b.variant.(Type_Info_Relative_Multi_Pointer) or_return
|
||||
return x.base_integer == y.base_integer && x.pointer == y.pointer
|
||||
|
||||
case Type_Info_Matrix:
|
||||
y := b.variant.(Type_Info_Matrix) or_return
|
||||
@@ -383,9 +383,9 @@ is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
||||
is_relative_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Multi_Pointer)
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -395,7 +395,6 @@ is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
||||
|
||||
|
||||
|
||||
|
||||
write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) {
|
||||
return write_type_writer(strings.to_writer(buf), type_info_of(id))
|
||||
}
|
||||
@@ -581,9 +580,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
|
||||
if info.is_packed { io.write_string(w, "#packed ", &n) or_return }
|
||||
if info.is_raw_union { io.write_string(w, "#raw_union ", &n) or_return }
|
||||
if info.custom_align {
|
||||
io.write_string(w, "#align ", &n) or_return
|
||||
io.write_string(w, "#align(", &n) or_return
|
||||
io.write_i64(w, i64(ti.align), 10, &n) or_return
|
||||
io.write_byte(w, ' ', &n) or_return
|
||||
io.write_string(w, ") ", &n) or_return
|
||||
}
|
||||
io.write_byte(w, '{', &n) or_return
|
||||
for name, i in info.names {
|
||||
@@ -599,9 +598,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
|
||||
if info.no_nil { io.write_string(w, "#no_nil ", &n) or_return }
|
||||
if info.shared_nil { io.write_string(w, "#shared_nil ", &n) or_return }
|
||||
if info.custom_align {
|
||||
io.write_string(w, "#align ", &n) or_return
|
||||
io.write_string(w, "#align(", &n) or_return
|
||||
io.write_i64(w, i64(ti.align), 10, &n) or_return
|
||||
io.write_byte(w, ' ', &n) or_return
|
||||
io.write_string(w, ") ", &n) or_return
|
||||
}
|
||||
io.write_byte(w, '{', &n) or_return
|
||||
for variant, i in info.variants {
|
||||
@@ -652,11 +651,11 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
|
||||
io.write_string(w, ") ", &n) or_return
|
||||
write_type(w, info.pointer, &n) or_return
|
||||
|
||||
case Type_Info_Relative_Slice:
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
io.write_string(w, "#relative(", &n) or_return
|
||||
write_type(w, info.base_integer, &n) or_return
|
||||
io.write_string(w, ") ", &n) or_return
|
||||
write_type(w, info.slice, &n) or_return
|
||||
write_type(w, info.pointer, &n) or_return
|
||||
|
||||
case Type_Info_Matrix:
|
||||
io.write_string(w, "matrix[", &n) or_return
|
||||
|
||||
+32
-6
@@ -162,11 +162,11 @@ Type_Info_Simd_Vector :: struct {
|
||||
count: int,
|
||||
}
|
||||
Type_Info_Relative_Pointer :: struct {
|
||||
pointer: ^Type_Info,
|
||||
pointer: ^Type_Info, // ^T
|
||||
base_integer: ^Type_Info,
|
||||
}
|
||||
Type_Info_Relative_Slice :: struct {
|
||||
slice: ^Type_Info,
|
||||
Type_Info_Relative_Multi_Pointer :: struct {
|
||||
pointer: ^Type_Info, // [^]T
|
||||
base_integer: ^Type_Info,
|
||||
}
|
||||
Type_Info_Matrix :: struct {
|
||||
@@ -219,7 +219,7 @@ Type_Info :: struct {
|
||||
Type_Info_Bit_Set,
|
||||
Type_Info_Simd_Vector,
|
||||
Type_Info_Relative_Pointer,
|
||||
Type_Info_Relative_Slice,
|
||||
Type_Info_Relative_Multi_Pointer,
|
||||
Type_Info_Matrix,
|
||||
Type_Info_Soa_Pointer,
|
||||
},
|
||||
@@ -252,12 +252,13 @@ Typeid_Kind :: enum u8 {
|
||||
Bit_Set,
|
||||
Simd_Vector,
|
||||
Relative_Pointer,
|
||||
Relative_Slice,
|
||||
Relative_Multi_Pointer,
|
||||
Matrix,
|
||||
Soa_Pointer,
|
||||
}
|
||||
#assert(len(Typeid_Kind) < 32)
|
||||
|
||||
// Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
||||
// Typeid_Bit_Field :: bit_field #align(align_of(uintptr)) {
|
||||
// index: 8*size_of(uintptr) - 8,
|
||||
// kind: 5, // Typeid_Kind
|
||||
// named: 1,
|
||||
@@ -337,6 +338,8 @@ Kilobyte :: 1024 * Byte
|
||||
Megabyte :: 1024 * Kilobyte
|
||||
Gigabyte :: 1024 * Megabyte
|
||||
Terabyte :: 1024 * Gigabyte
|
||||
Petabyte :: 1024 * Terabyte
|
||||
Exabyte :: 1024 * Petabyte
|
||||
|
||||
// Logging stuff
|
||||
|
||||
@@ -499,6 +502,29 @@ Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
|
||||
Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
||||
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Platform_Subtarget_Type :: enum int {
|
||||
Default,
|
||||
iOS,
|
||||
}
|
||||
*/
|
||||
Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Sanitizer_Flag :: enum u32 {
|
||||
Address = 0,
|
||||
Memory = 1,
|
||||
Thread = 2,
|
||||
}
|
||||
Odin_Sanitizer_Flags :: distinct bitset[Odin_Sanitizer_Flag; u32]
|
||||
|
||||
ODIN_SANITIZER_FLAGS // is a constant
|
||||
*/
|
||||
Odin_Sanitizer_Flags :: type_of(ODIN_SANITIZER_FLAGS)
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Init Startup Procedures //
|
||||
/////////////////////////////
|
||||
|
||||
@@ -601,14 +601,15 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
|
||||
|
||||
@builtin
|
||||
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||
if len(args) == 0 {
|
||||
new_size := index + len(arg)
|
||||
if len(arg) == 0 {
|
||||
ok = true
|
||||
} else if index+len(args) < len(array) {
|
||||
copy(array[index:], args)
|
||||
} else if new_size < len(array) {
|
||||
copy(array[index:], arg)
|
||||
ok = true
|
||||
} else {
|
||||
resize(array, index+1+len(args), loc) or_return
|
||||
copy(array[index:], args)
|
||||
resize(array, new_size, loc) or_return
|
||||
copy(array[index:], arg)
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
//+build !js
|
||||
package runtime
|
||||
|
||||
// TODO(bill): reimplement these procedures in the os_specific stuff
|
||||
import "core:os"
|
||||
|
||||
when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||
_ :: os
|
||||
|
||||
// mem.nil_allocator reimplementation
|
||||
default_allocator_proc :: nil_allocator_proc
|
||||
default_allocator :: nil_allocator
|
||||
} else {
|
||||
// TODO(bill): reimplement these procedures in the os_specific stuff
|
||||
import "core:os"
|
||||
|
||||
default_allocator_proc :: os.heap_allocator_proc
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ MAP_CACHE_LINE_SIZE :: 1 << MAP_CACHE_LINE_LOG2
|
||||
//
|
||||
// In the optimal case, len(Map_Cell(T){}.data) = 1 so the cell array can be treated
|
||||
// as a regular array of T, which is the case for hashes.
|
||||
Map_Cell :: struct($T: typeid) #align MAP_CACHE_LINE_SIZE {
|
||||
Map_Cell :: struct($T: typeid) #align(MAP_CACHE_LINE_SIZE) {
|
||||
data: [MAP_CACHE_LINE_SIZE / size_of(T) when 0 < size_of(T) && size_of(T) < MAP_CACHE_LINE_SIZE else 1]T,
|
||||
}
|
||||
|
||||
|
||||
+68
-13
@@ -11,7 +11,10 @@ RUNTIME_LINKAGE :: "strong" when (
|
||||
ODIN_BUILD_MODE == .Dynamic ||
|
||||
!ODIN_NO_CRT) &&
|
||||
!IS_WASM) else "internal"
|
||||
RUNTIME_REQUIRE :: true
|
||||
RUNTIME_REQUIRE :: !ODIN_TILDE
|
||||
|
||||
@(private)
|
||||
__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16
|
||||
|
||||
|
||||
@(private)
|
||||
@@ -218,10 +221,18 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
case n == 0: return true
|
||||
case x == y: return true
|
||||
}
|
||||
|
||||
a, b := ([^]byte)(x), ([^]byte)(y)
|
||||
length := uint(n)
|
||||
|
||||
for i := uint(0); i < length; i += 1 {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
/*
|
||||
|
||||
when size_of(uint) == 8 {
|
||||
if word_length := length >> 3; word_length != 0 {
|
||||
for _ in 0..<word_length {
|
||||
@@ -276,6 +287,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
|
||||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
|
||||
@@ -401,6 +413,48 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
}
|
||||
|
||||
|
||||
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
|
||||
x := ([^]byte)(lhs)
|
||||
y := ([^]byte)(rhs)
|
||||
if x == y {
|
||||
return true
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return false
|
||||
}
|
||||
xn := cstring_len(lhs)
|
||||
yn := cstring_len(rhs)
|
||||
if xn != yn {
|
||||
return false
|
||||
}
|
||||
return #force_inline memory_equal(x, y, xn)
|
||||
}
|
||||
|
||||
cstring_cmp :: proc "contextless" (lhs, rhs: cstring) -> int {
|
||||
x := ([^]byte)(lhs)
|
||||
y := ([^]byte)(rhs)
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return -1 if x == nil else +1
|
||||
}
|
||||
xn := cstring_len(lhs)
|
||||
yn := cstring_len(rhs)
|
||||
ret := memory_compare(x, y, min(xn, yn))
|
||||
if ret == 0 && xn != yn {
|
||||
return -1 if xn < yn else +1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
cstring_ne :: #force_inline proc "contextless" (a, b: cstring) -> bool { return !cstring_eq(a, b) }
|
||||
cstring_lt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) < 0 }
|
||||
cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) > 0 }
|
||||
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
|
||||
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
|
||||
|
||||
|
||||
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
|
||||
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }
|
||||
|
||||
@@ -746,7 +800,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
}
|
||||
|
||||
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
truncsfhf2 :: proc "c" (value: f32) -> __float16 {
|
||||
v: struct #raw_union { i: u32, f: f32 }
|
||||
i, s, e, m: i32
|
||||
|
||||
@@ -760,7 +814,7 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
|
||||
if e <= 0 {
|
||||
if e < -10 {
|
||||
return u16(s)
|
||||
return transmute(__float16)u16(s)
|
||||
}
|
||||
m = (m | 0x00800000) >> u32(1 - e)
|
||||
|
||||
@@ -768,14 +822,14 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
m += 0x00002000
|
||||
}
|
||||
|
||||
return u16(s | (m >> 13))
|
||||
return transmute(__float16)u16(s | (m >> 13))
|
||||
} else if e == 0xff - (127 - 15) {
|
||||
if m == 0 {
|
||||
return u16(s | 0x7c00) /* NOTE(bill): infinity */
|
||||
return transmute(__float16)u16(s | 0x7c00) /* NOTE(bill): infinity */
|
||||
} else {
|
||||
/* NOTE(bill): NAN */
|
||||
m >>= 13
|
||||
return u16(s | 0x7c00 | m | i32(m == 0))
|
||||
return transmute(__float16)u16(s | 0x7c00 | m | i32(m == 0))
|
||||
}
|
||||
} else {
|
||||
if m & 0x00001000 != 0 {
|
||||
@@ -795,23 +849,24 @@ truncsfhf2 :: proc "c" (value: f32) -> u16 {
|
||||
intrinsics.volatile_store(&f, g)
|
||||
}
|
||||
|
||||
return u16(s | 0x7c00)
|
||||
return transmute(__float16)u16(s | 0x7c00)
|
||||
}
|
||||
|
||||
return u16(s | (e << 10) | (m >> 13))
|
||||
return transmute(__float16)u16(s | (e << 10) | (m >> 13))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__truncdfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
truncdfhf2 :: proc "c" (value: f64) -> u16 {
|
||||
truncdfhf2 :: proc "c" (value: f64) -> __float16 {
|
||||
return truncsfhf2(f32(value))
|
||||
}
|
||||
|
||||
@(link_name="__gnu_h2f_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
|
||||
gnu_h2f_ieee :: proc "c" (value_: __float16) -> f32 {
|
||||
fp32 :: struct #raw_union { u: u32, f: f32 }
|
||||
|
||||
value := transmute(u16)value_
|
||||
v: fp32
|
||||
magic, inf_or_nan: fp32
|
||||
magic.u = u32((254 - 15) << 23)
|
||||
@@ -828,12 +883,12 @@ gnu_h2f_ieee :: proc "c" (value: u16) -> f32 {
|
||||
|
||||
|
||||
@(link_name="__gnu_f2h_ieee", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
gnu_f2h_ieee :: proc "c" (value: f32) -> u16 {
|
||||
gnu_f2h_ieee :: proc "c" (value: f32) -> __float16 {
|
||||
return truncsfhf2(value)
|
||||
}
|
||||
|
||||
@(link_name="__extendhfsf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||
extendhfsf2 :: proc "c" (value: u16) -> f32 {
|
||||
extendhfsf2 :: proc "c" (value: __float16) -> f32 {
|
||||
return gnu_h2f_ieee(value)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
//+private
|
||||
//+build windows
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
foreign import kernel32 "system:Kernel32.lib"
|
||||
|
||||
@(private="file")
|
||||
@@ -102,12 +99,12 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
|
||||
|
||||
allocated_mem: rawptr
|
||||
if old_ptr != nil {
|
||||
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^
|
||||
original_old_ptr := ([^]rawptr)(old_ptr)[-1]
|
||||
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
|
||||
} else {
|
||||
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
|
||||
}
|
||||
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
|
||||
aligned_mem := ([^]u8)(allocated_mem)[size_of(rawptr):]
|
||||
|
||||
ptr := uintptr(aligned_mem)
|
||||
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
|
||||
@@ -116,10 +113,10 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
||||
aligned_mem = rawptr(aligned_ptr)
|
||||
intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
|
||||
aligned_mem = ([^]byte)(aligned_ptr)
|
||||
([^]rawptr)(aligned_mem)[-1] = allocated_mem
|
||||
|
||||
return byte_slice(aligned_mem, size), nil
|
||||
return aligned_mem[:size], nil
|
||||
}
|
||||
|
||||
_windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory := true) -> ([]byte, Allocator_Error) {
|
||||
@@ -129,7 +126,7 @@ _windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory
|
||||
|
||||
_windows_default_free :: proc "contextless" (ptr: rawptr) {
|
||||
if ptr != nil {
|
||||
heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^)
|
||||
heap_free(([^]rawptr)(ptr)[-1])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -8,6 +8,11 @@ _INTEGER_DIGITS_VAR := _INTEGER_DIGITS
|
||||
when !ODIN_NO_RTTI {
|
||||
print_any_single :: proc "contextless" (arg: any) {
|
||||
x := arg
|
||||
if x.data == nil {
|
||||
print_string("nil")
|
||||
return
|
||||
}
|
||||
|
||||
if loc, ok := x.(Source_Code_Location); ok {
|
||||
print_caller_location(loc)
|
||||
return
|
||||
@@ -48,6 +53,7 @@ when !ODIN_NO_RTTI {
|
||||
case int: print_int(v)
|
||||
case uint: print_uint(v)
|
||||
case uintptr: print_uintptr(v)
|
||||
case rawptr: print_uintptr(uintptr(v))
|
||||
|
||||
case bool: print_string("true" if v else "false")
|
||||
case b8: print_string("true" if v else "false")
|
||||
@@ -58,7 +64,7 @@ when !ODIN_NO_RTTI {
|
||||
case:
|
||||
ti := type_info_of(x.id)
|
||||
#partial switch v in ti.variant {
|
||||
case Type_Info_Pointer:
|
||||
case Type_Info_Pointer, Type_Info_Multi_Pointer:
|
||||
print_uintptr((^uintptr)(x.data)^)
|
||||
return
|
||||
}
|
||||
@@ -67,7 +73,9 @@ when !ODIN_NO_RTTI {
|
||||
}
|
||||
}
|
||||
println_any :: proc "contextless" (args: ..any) {
|
||||
context = default_context()
|
||||
loop: for arg, i in args {
|
||||
assert(arg.id != nil)
|
||||
if i != 0 {
|
||||
print_string(" ")
|
||||
}
|
||||
@@ -390,9 +398,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
if info.is_packed { print_string("#packed ") }
|
||||
if info.is_raw_union { print_string("#raw_union ") }
|
||||
if info.custom_align {
|
||||
print_string("#align ")
|
||||
print_string("#align(")
|
||||
print_u64(u64(ti.align))
|
||||
print_byte(' ')
|
||||
print_string(") ")
|
||||
}
|
||||
print_byte('{')
|
||||
for name, i in info.names {
|
||||
@@ -406,8 +414,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
case Type_Info_Union:
|
||||
print_string("union ")
|
||||
if info.custom_align {
|
||||
print_string("#align ")
|
||||
print_string("#align(")
|
||||
print_u64(u64(ti.align))
|
||||
print_string(") ")
|
||||
}
|
||||
if info.no_nil {
|
||||
print_string("#no_nil ")
|
||||
@@ -463,11 +472,11 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
print_string(") ")
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Relative_Slice:
|
||||
case Type_Info_Relative_Multi_Pointer:
|
||||
print_string("#relative(")
|
||||
print_type(info.base_integer)
|
||||
print_string(") ")
|
||||
print_type(info.slice)
|
||||
print_type(info.pointer)
|
||||
|
||||
case Type_Info_Matrix:
|
||||
print_string("matrix[")
|
||||
|
||||
@@ -31,7 +31,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
if ptr != nil && len != 0 {
|
||||
b := byte(val)
|
||||
p := ([^]byte)(ptr)
|
||||
for i in 0..<len {
|
||||
for i := 0; i < len; i += 1 {
|
||||
p[i] = b
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
if ptr != nil && len != 0 {
|
||||
b := byte(val)
|
||||
p := ([^]byte)(ptr)
|
||||
for i in 0..<len {
|
||||
for i := 0; i < len; i += 1 {
|
||||
p[i] = b
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -77,10 +77,10 @@ shr_masked :: intrinsics.simd_shr_masked
|
||||
add_sat :: intrinsics.simd_add_sat
|
||||
sub_sat :: intrinsics.simd_sub_sat
|
||||
|
||||
and :: intrinsics.simd_and
|
||||
or :: intrinsics.simd_or
|
||||
xor :: intrinsics.simd_xor
|
||||
and_not :: intrinsics.simd_and_not
|
||||
bit_and :: intrinsics.simd_bit_and
|
||||
bit_or :: intrinsics.simd_bit_or
|
||||
bit_xor :: intrinsics.simd_bit_xor
|
||||
bit_and_not :: intrinsics.simd_bit_and_not
|
||||
|
||||
neg :: intrinsics.simd_neg
|
||||
|
||||
|
||||
+1
-1
@@ -259,7 +259,7 @@ _quick_sort :: proc(it: Interface, a, b, max_depth: int) {
|
||||
|
||||
a, b, max_depth := a, b, max_depth
|
||||
|
||||
if b-a > 12 { // only use shell sort for lengths <= 12
|
||||
for b-a > 12 { // only use shell sort for lengths <= 12
|
||||
if max_depth == 0 {
|
||||
heap_sort(it, a, b)
|
||||
return
|
||||
|
||||
+12
-12
@@ -35,8 +35,8 @@ Returns:
|
||||
- res: The new Builder
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
builder_make_none :: proc(allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return Builder{buf=make([dynamic]byte, allocator) or_return }, nil
|
||||
builder_make_none :: proc(allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return Builder{buf=make([dynamic]byte, allocator, loc) or_return }, nil
|
||||
}
|
||||
/*
|
||||
Produces a Builder with a specified length and cap of max(16,len) byte buffer
|
||||
@@ -51,8 +51,8 @@ Returns:
|
||||
- res: The new Builder
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
builder_make_len :: proc(len: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return Builder{buf=make([dynamic]byte, len, allocator) or_return }, nil
|
||||
builder_make_len :: proc(len: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return Builder{buf=make([dynamic]byte, len, allocator, loc) or_return }, nil
|
||||
}
|
||||
/*
|
||||
Produces a Builder with a specified length and cap
|
||||
@@ -68,8 +68,8 @@ Returns:
|
||||
- res: The new Builder
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return Builder{buf=make([dynamic]byte, len, cap, allocator) or_return }, nil
|
||||
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
return Builder{buf=make([dynamic]byte, len, cap, allocator, loc) or_return }, nil
|
||||
}
|
||||
/*
|
||||
Produces a String Builder
|
||||
@@ -116,8 +116,8 @@ Returns:
|
||||
- res: A pointer to the initialized Builder
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, allocator) or_return
|
||||
builder_init_none :: proc(b: ^Builder, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, allocator, loc) or_return
|
||||
return b, nil
|
||||
}
|
||||
/*
|
||||
@@ -135,8 +135,8 @@ Returns:
|
||||
- res: A pointer to the initialized Builder
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, len, allocator) or_return
|
||||
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, len, allocator, loc) or_return
|
||||
return b, nil
|
||||
}
|
||||
/*
|
||||
@@ -153,8 +153,8 @@ Returns:
|
||||
- res: A pointer to the initialized Builder
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, len, cap, allocator) or_return
|
||||
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator, loc := #caller_location) -> (res: ^Builder, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
b.buf = make([dynamic]byte, len, cap, allocator, loc) or_return
|
||||
return b, nil
|
||||
}
|
||||
// Overload simple `builder_init_*` with or without len / ap parameters
|
||||
|
||||
@@ -34,9 +34,9 @@ Inputs:
|
||||
Returns:
|
||||
- err: An allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) -> (err: mem.Allocator_Error) {
|
||||
intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator, loc := #caller_location) -> (err: mem.Allocator_Error) {
|
||||
m.allocator = allocator
|
||||
m.entries = make(map[string]^Intern_Entry, 16, map_allocator) or_return
|
||||
m.entries = make(map[string]^Intern_Entry, 16, map_allocator, loc) or_return
|
||||
return nil
|
||||
}
|
||||
/*
|
||||
|
||||
+23
-23
@@ -595,7 +595,7 @@ Output:
|
||||
a...b...c
|
||||
|
||||
*/
|
||||
join :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
if len(a) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
@@ -605,7 +605,7 @@ join :: proc(a: []string, sep: string, allocator := context.allocator) -> (res:
|
||||
n += len(s)
|
||||
}
|
||||
|
||||
b := make([]byte, n, allocator) or_return
|
||||
b := make([]byte, n, allocator, loc) or_return
|
||||
i := copy(b, a[0])
|
||||
for s in a[1:] {
|
||||
i += copy(b[i:], sep)
|
||||
@@ -659,7 +659,7 @@ Output:
|
||||
abc
|
||||
|
||||
*/
|
||||
concatenate :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
if len(a) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
@@ -668,7 +668,7 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> (res: string
|
||||
for s in a {
|
||||
n += len(s)
|
||||
}
|
||||
b := make([]byte, n, allocator) or_return
|
||||
b := make([]byte, n, allocator, loc) or_return
|
||||
i := 0
|
||||
for s in a {
|
||||
i += copy(b[i:], s)
|
||||
@@ -724,7 +724,7 @@ Output:
|
||||
example
|
||||
|
||||
*/
|
||||
cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
s := s; rune_length := rune_length
|
||||
context.allocator = allocator
|
||||
|
||||
@@ -752,7 +752,7 @@ cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator :
|
||||
// But we do know it's bounded by the number of runes * 4 bytes,
|
||||
// and can be no more than the size of the input string.
|
||||
bytes_needed := min(rune_length * 4, len(s))
|
||||
buf := make([]u8, bytes_needed) or_return
|
||||
buf := make([]u8, bytes_needed, allocator, loc) or_return
|
||||
|
||||
byte_offset := 0
|
||||
for i := 0; i < rune_count; i += 1 {
|
||||
@@ -796,7 +796,7 @@ Returns:
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
@private
|
||||
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) {
|
||||
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) {
|
||||
s, n := s_, n_
|
||||
|
||||
if n == 0 {
|
||||
@@ -809,7 +809,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
|
||||
n = l
|
||||
}
|
||||
|
||||
res := make([]string, n, allocator) or_return
|
||||
res := make([]string, n, allocator, loc) or_return
|
||||
for i := 0; i < n-1; i += 1 {
|
||||
_, w := utf8.decode_rune_in_string(s)
|
||||
res[i] = s[:w]
|
||||
@@ -825,7 +825,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
|
||||
n = count(s, sep) + 1
|
||||
}
|
||||
|
||||
res = make([]string, n, allocator) or_return
|
||||
res = make([]string, n, allocator, loc) or_return
|
||||
|
||||
n -= 1
|
||||
|
||||
@@ -1965,14 +1965,14 @@ Output:
|
||||
abcabc
|
||||
|
||||
*/
|
||||
repeat :: proc(s: string, count: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
if count < 0 {
|
||||
panic("strings: negative repeat count")
|
||||
} else if count > 0 && (len(s)*count)/count != len(s) {
|
||||
panic("strings: repeat count will cause an overflow")
|
||||
}
|
||||
|
||||
b := make([]byte, len(s)*count, allocator) or_return
|
||||
b := make([]byte, len(s)*count, allocator, loc) or_return
|
||||
i := copy(b, s)
|
||||
for i < len(b) { // 2^N trick to reduce the need to copy
|
||||
copy(b[i:], b[:i])
|
||||
@@ -2052,7 +2052,7 @@ Output:
|
||||
zzzz true
|
||||
|
||||
*/
|
||||
replace :: proc(s, old, new: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) {
|
||||
replace :: proc(s, old, new: string, n: int, allocator := context.allocator, loc := #caller_location) -> (output: string, was_allocation: bool) {
|
||||
if old == new || n == 0 {
|
||||
was_allocation = false
|
||||
output = s
|
||||
@@ -2068,7 +2068,7 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) ->
|
||||
}
|
||||
|
||||
|
||||
t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator)
|
||||
t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator, loc)
|
||||
was_allocation = true
|
||||
|
||||
w := 0
|
||||
@@ -2637,7 +2637,7 @@ Output:
|
||||
["testing", "this", "out", "nice", "done", "last"]
|
||||
|
||||
*/
|
||||
split_multi :: proc(s: string, substrs: []string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
|
||||
split_multi :: proc(s: string, substrs: []string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
|
||||
if s == "" || len(substrs) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -2660,7 +2660,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
|
||||
it = it[i+w:]
|
||||
}
|
||||
|
||||
results := make([dynamic]string, 0, n, allocator) or_return
|
||||
results := make([dynamic]string, 0, n, allocator, loc) or_return
|
||||
{
|
||||
it := s
|
||||
for len(it) > 0 {
|
||||
@@ -2825,10 +2825,10 @@ Output:
|
||||
abcxyz zyxcba
|
||||
|
||||
*/
|
||||
reverse :: proc(s: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
reverse :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
str := s
|
||||
n := len(str)
|
||||
buf := make([]byte, n) or_return
|
||||
buf := make([]byte, n, allocator, loc) or_return
|
||||
i := n
|
||||
|
||||
for len(str) > 0 {
|
||||
@@ -3107,7 +3107,7 @@ Returns:
|
||||
- res: A slice of substrings of the input string, or an empty slice if the input string only contains white space
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
fields :: proc(s: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
|
||||
fields :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
|
||||
n := 0
|
||||
was_space := 1
|
||||
set_bits := u8(0)
|
||||
@@ -3129,7 +3129,7 @@ fields :: proc(s: string, allocator := context.allocator) -> (res: []string, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
a := make([]string, n, allocator) or_return
|
||||
a := make([]string, n, allocator, loc) or_return
|
||||
na := 0
|
||||
field_start := 0
|
||||
i := 0
|
||||
@@ -3171,8 +3171,8 @@ Returns:
|
||||
- res: A slice of substrings of the input string, or an empty slice if all code points in the input string satisfy the predicate or if the input string is empty
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
|
||||
substrings := make([dynamic]string, 0, 32, allocator) or_return
|
||||
fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.allocator, loc := #caller_location) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error #no_bounds_check {
|
||||
substrings := make([dynamic]string, 0, 32, allocator, loc) or_return
|
||||
|
||||
start, end := -1, -1
|
||||
for r, offset in s {
|
||||
@@ -3252,7 +3252,7 @@ Returns:
|
||||
|
||||
NOTE: This implementation is a single-row-version of the Wagner–Fischer algorithm, based on C code by Martin Ettl.
|
||||
*/
|
||||
levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> (res: int, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc := #caller_location) -> (res: int, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
LEVENSHTEIN_DEFAULT_COSTS: []int : {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
@@ -3275,7 +3275,7 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator) -> (r
|
||||
costs: []int
|
||||
|
||||
if n + 1 > len(LEVENSHTEIN_DEFAULT_COSTS) {
|
||||
costs = make([]int, n + 1, allocator) or_return
|
||||
costs = make([]int, n + 1, allocator, loc) or_return
|
||||
for k in 0..=n {
|
||||
costs[k] = k
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ wait :: proc{
|
||||
atomic_cond_wait,
|
||||
atomic_sema_wait,
|
||||
futex_wait,
|
||||
wait_group_wait,
|
||||
}
|
||||
|
||||
wait_with_timeout :: proc{
|
||||
@@ -96,6 +97,7 @@ wait_with_timeout :: proc{
|
||||
atomic_cond_wait_with_timeout,
|
||||
atomic_sema_wait_with_timeout,
|
||||
futex_wait_with_timeout,
|
||||
wait_group_wait_with_timeout,
|
||||
}
|
||||
|
||||
post :: proc{
|
||||
|
||||
@@ -17,42 +17,42 @@ PTHREAD_RWLOCKATTR_SIZE :: 16
|
||||
|
||||
pthread_t :: distinct u64
|
||||
|
||||
pthread_attr_t :: struct #align 16 {
|
||||
pthread_attr_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_ATTR_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_cond_t :: struct #align 16 {
|
||||
pthread_cond_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_COND_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_condattr_t :: struct #align 16 {
|
||||
pthread_condattr_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_CONDATTR_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_mutex_t :: struct #align 16 {
|
||||
pthread_mutex_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_MUTEX_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_mutexattr_t :: struct #align 16 {
|
||||
pthread_mutexattr_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_MUTEXATTR_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_once_t :: struct #align 16 {
|
||||
pthread_once_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_ONCE_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_rwlock_t :: struct #align 16 {
|
||||
pthread_rwlock_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_RWLOCK_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_rwlockattr_t :: struct #align 16 {
|
||||
pthread_rwlockattr_t :: struct #align(16) {
|
||||
sig: c.long,
|
||||
_: [PTHREAD_RWLOCKATTR_SIZE] c.char,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ package unix
|
||||
import "core:c"
|
||||
|
||||
pthread_t :: distinct u64
|
||||
// pthread_t :: struct #align 16 { x: u64 }
|
||||
// pthread_t :: struct #align(16) { x: u64 }
|
||||
|
||||
PTHREAD_COND_T_SIZE :: 8
|
||||
|
||||
@@ -27,32 +27,32 @@ when size_of(int) == 8 {
|
||||
PTHREAD_BARRIER_T_SIZE :: 20
|
||||
}
|
||||
|
||||
pthread_cond_t :: struct #align 16 {
|
||||
pthread_cond_t :: struct #align(16) {
|
||||
_: [PTHREAD_COND_T_SIZE] c.char,
|
||||
}
|
||||
pthread_mutex_t :: struct #align 16 {
|
||||
pthread_mutex_t :: struct #align(16) {
|
||||
_: [PTHREAD_MUTEX_T_SIZE] c.char,
|
||||
}
|
||||
pthread_rwlock_t :: struct #align 16 {
|
||||
pthread_rwlock_t :: struct #align(16) {
|
||||
_: [PTHREAD_RWLOCK_T_SIZE] c.char,
|
||||
}
|
||||
pthread_barrier_t :: struct #align 16 {
|
||||
pthread_barrier_t :: struct #align(16) {
|
||||
_: [PTHREAD_BARRIER_T_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_attr_t :: struct #align 16 {
|
||||
pthread_attr_t :: struct #align(16) {
|
||||
_: [PTHREAD_ATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_condattr_t :: struct #align 16 {
|
||||
pthread_condattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_CONDATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_mutexattr_t :: struct #align 16 {
|
||||
pthread_mutexattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_rwlockattr_t :: struct #align 16 {
|
||||
pthread_rwlockattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_barrierattr_t :: struct #align 16 {
|
||||
pthread_barrierattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import "core:c"
|
||||
// And at the time of writing there is a bug with putting it
|
||||
// as the only field in a struct.
|
||||
pthread_t :: distinct u64
|
||||
// pthread_t :: struct #align 16 { x: u64 };
|
||||
// pthread_t :: struct #align(16) { x: u64 };
|
||||
|
||||
// NOTE(tetra): Got all the size constants from pthreadtypes-arch.h on my
|
||||
// Linux machine.
|
||||
@@ -34,32 +34,32 @@ when size_of(int) == 8 {
|
||||
PTHREAD_BARRIER_T_SIZE :: 20
|
||||
}
|
||||
|
||||
pthread_cond_t :: struct #align 16 {
|
||||
pthread_cond_t :: struct #align(16) {
|
||||
_: [PTHREAD_COND_T_SIZE] c.char,
|
||||
}
|
||||
pthread_mutex_t :: struct #align 16 {
|
||||
pthread_mutex_t :: struct #align(16) {
|
||||
_: [PTHREAD_MUTEX_T_SIZE] c.char,
|
||||
}
|
||||
pthread_rwlock_t :: struct #align 16 {
|
||||
pthread_rwlock_t :: struct #align(16) {
|
||||
_: [PTHREAD_RWLOCK_T_SIZE] c.char,
|
||||
}
|
||||
pthread_barrier_t :: struct #align 16 {
|
||||
pthread_barrier_t :: struct #align(16) {
|
||||
_: [PTHREAD_BARRIER_T_SIZE] c.char,
|
||||
}
|
||||
|
||||
pthread_attr_t :: struct #align 16 {
|
||||
pthread_attr_t :: struct #align(16) {
|
||||
_: [PTHREAD_ATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_condattr_t :: struct #align 16 {
|
||||
pthread_condattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_CONDATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_mutexattr_t :: struct #align 16 {
|
||||
pthread_mutexattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_rwlockattr_t :: struct #align 16 {
|
||||
pthread_rwlockattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
|
||||
}
|
||||
pthread_barrierattr_t :: struct #align 16 {
|
||||
pthread_barrierattr_t :: struct #align(16) {
|
||||
_: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ sched_param :: struct {
|
||||
sched_priority: c.int,
|
||||
}
|
||||
|
||||
sem_t :: struct #align 16 {
|
||||
sem_t :: struct #align(16) {
|
||||
_: [SEM_T_SIZE] c.char,
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,21 @@ foreign kernel32 {
|
||||
SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL ---
|
||||
GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL ---
|
||||
TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL ---
|
||||
SuspendThread :: proc(hThread: HANDLE) -> DWORD ---
|
||||
|
||||
GetProcessAffinityMask :: proc(
|
||||
hProcess: HANDLE,
|
||||
lpProcessAffinityMask: PDWORD_PTR,
|
||||
lpSystemAffinityMask: PDWORD_PTR,
|
||||
) -> BOOL ---
|
||||
SetProcessAffinityMask :: proc(
|
||||
hProcess: HANDLE,
|
||||
dwProcessAffinityMask: DWORD_PTR,
|
||||
) -> BOOL ---
|
||||
SetThreadAffinityMask :: proc(
|
||||
hThread: HANDLE,
|
||||
dwThreadAffinityMask: DWORD_PTR,
|
||||
) -> DWORD_PTR ---
|
||||
|
||||
CreateSemaphoreW :: proc(attributes: LPSECURITY_ATTRIBUTES, initial_count, maximum_count: LONG, name: LPCWSTR) -> HANDLE ---
|
||||
ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: LONG, previous_count: ^LONG) -> BOOL ---
|
||||
@@ -389,9 +404,9 @@ foreign kernel32 {
|
||||
|
||||
CreatePipe :: proc(hReadPipe, hWritePipe: ^HANDLE, lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD) -> BOOL ---
|
||||
|
||||
ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED,) -> BOOL ---
|
||||
DisconnectNamedPipe :: proc(hNamedPipe: HANDLE,) -> BOOL ---
|
||||
WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD,) -> BOOL ---
|
||||
ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL ---
|
||||
DisconnectNamedPipe :: proc(hNamedPipe: HANDLE) -> BOOL ---
|
||||
WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL ---
|
||||
|
||||
SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL ---
|
||||
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
|
||||
@@ -886,7 +901,7 @@ WIN32_MEMORY_REGION_INFORMATION_u_s :: struct {
|
||||
Bitfield: ULONG,
|
||||
}
|
||||
WIN32_MEMORY_REGION_INFORMATION_u_s_Bitfield :: distinct ULONG
|
||||
/*bit_field #align align_of(ULONG) {
|
||||
/*bit_field #align(align_of(ULONG)) {
|
||||
Private : 1-0,
|
||||
MappedDataFile : 2-1,
|
||||
MappedImage : 3-2,
|
||||
|
||||
@@ -1709,6 +1709,12 @@ MONITORINFO :: struct {
|
||||
}
|
||||
LPMONITORINFO :: ^MONITORINFO
|
||||
|
||||
CCHDEVICENAME :: 32
|
||||
MONITORINFOEXW :: struct {
|
||||
using _: MONITORINFO,
|
||||
szDevice: [CCHDEVICENAME]WCHAR,
|
||||
}
|
||||
|
||||
// SetWindowsHook() codes
|
||||
WH_MIN :: -1
|
||||
WH_MSGFILTER :: -1
|
||||
@@ -2469,9 +2475,9 @@ OVERLAPPED :: struct {
|
||||
}
|
||||
|
||||
OVERLAPPED_ENTRY :: struct {
|
||||
lpCompletionKey: c_ulong,
|
||||
lpCompletionKey: ULONG_PTR,
|
||||
lpOverlapped: ^OVERLAPPED,
|
||||
Internal: c_ulong,
|
||||
Internal: ULONG_PTR,
|
||||
dwNumberOfBytesTransferred: DWORD,
|
||||
}
|
||||
|
||||
|
||||
@@ -228,6 +228,9 @@ foreign user32 {
|
||||
SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
|
||||
CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
|
||||
GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
|
||||
|
||||
GetSystemMenu :: proc(hWnd: HWND, bRevert: BOOL) -> HMENU ---
|
||||
EnableMenuItem :: proc(hMenu: HMENU, uIDEnableItem: UINT, uEnable: UINT) -> BOOL ---
|
||||
}
|
||||
|
||||
CreateWindowW :: #force_inline proc "stdcall" (
|
||||
|
||||
@@ -50,7 +50,7 @@ Example Load:
|
||||
bytes: u32
|
||||
guid_accept_ex := WSAID_ACCEPTEX
|
||||
rc := WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_accept_ex, size_of(guid_accept_ex),
|
||||
fn_acceptex, size_of(fn_acceptex), &bytes, nil, nil,)
|
||||
fn_acceptex, size_of(fn_acceptex), &bytes, nil, nil)
|
||||
assert(rc != windows.SOCKET_ERROR)
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -30,9 +30,12 @@ TS_XML_Options := xml.Options{
|
||||
parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, pluralizer: proc(int) -> int = nil, allocator := context.allocator) -> (translation: ^Translation, err: Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
get_str :: proc(val: xml.Value) -> (str: string, err: Error) {
|
||||
get_str :: proc(val: xml.Value, intern: ^strings.Intern) -> (str: string, err: Error) {
|
||||
v, ok := val.(string)
|
||||
if ok {
|
||||
if intern != nil {
|
||||
v, _ = strings.intern_get(intern, v)
|
||||
}
|
||||
return v, .None
|
||||
}
|
||||
return "", .Bad_Str
|
||||
@@ -79,8 +82,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
|
||||
|
||||
section_name, _ := strings.intern_get(&translation.intern, "")
|
||||
if !options.merge_sections {
|
||||
value_text := get_str(ts.elements[section_name_id].value[0]) or_return
|
||||
section_name, _ = strings.intern_get(&translation.intern, value_text)
|
||||
section_name = get_str(ts.elements[section_name_id].value[0], &translation.intern) or_return
|
||||
}
|
||||
|
||||
if section_name not_in translation.k_v {
|
||||
@@ -91,10 +93,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
|
||||
// Find messages in section.
|
||||
nth: int
|
||||
for {
|
||||
message_id, message_found := xml.find_child_by_ident(ts, child_id, "message", nth)
|
||||
if !message_found {
|
||||
break
|
||||
}
|
||||
message_id := xml.find_child_by_ident(ts, child_id, "message", nth) or_break
|
||||
|
||||
numerus_tag, _ := xml.find_attribute_val_by_key(ts, message_id, "numerus")
|
||||
has_plurals := numerus_tag == "yes"
|
||||
@@ -111,13 +110,11 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
|
||||
return translation, .TS_File_Expected_Translation
|
||||
}
|
||||
|
||||
source := get_str(ts.elements[source_id].value[0]) or_return
|
||||
source, _ = strings.intern_get(&translation.intern, source)
|
||||
source := get_str(ts.elements[source_id].value[0], &translation.intern) or_return
|
||||
|
||||
xlat := ""
|
||||
if !has_plurals {
|
||||
xlat = get_str(ts.elements[translation_id].value[0]) or_return
|
||||
xlat, _ = strings.intern_get(&translation.intern, xlat)
|
||||
xlat = get_str(ts.elements[translation_id].value[0], &translation.intern) or_return
|
||||
}
|
||||
|
||||
if source in section {
|
||||
@@ -131,10 +128,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
|
||||
|
||||
num_plurals: int
|
||||
for {
|
||||
numerus_id, numerus_found := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals)
|
||||
if !numerus_found {
|
||||
break
|
||||
}
|
||||
numerus_id := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) or_break
|
||||
num_plurals += 1
|
||||
}
|
||||
|
||||
@@ -145,12 +139,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
|
||||
|
||||
num_plurals = 0
|
||||
for {
|
||||
numerus_id, numerus_found := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals)
|
||||
if !numerus_found {
|
||||
break
|
||||
}
|
||||
numerus := get_str(ts.elements[numerus_id].value[0]) or_return
|
||||
numerus, _ = strings.intern_get(&translation.intern, numerus)
|
||||
numerus_id := xml.find_child_by_ident(ts, translation_id, "numerusform", num_plurals) or_break
|
||||
numerus := get_str(ts.elements[numerus_id].value[0], &translation.intern) or_return
|
||||
section[source][num_plurals] = numerus
|
||||
|
||||
num_plurals += 1
|
||||
|
||||
@@ -775,10 +775,9 @@ gsub_with :: proc(
|
||||
haystack := haystack
|
||||
|
||||
for {
|
||||
length, err := find_aux(haystack, pattern, 0, false, &captures)
|
||||
|
||||
length := find_aux(haystack, pattern, 0, false, &captures) or_break
|
||||
// done
|
||||
if length == 0 || err != .OK {
|
||||
if length == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ peek :: proc(s: ^Scanner, n := 0) -> (ch: rune) {
|
||||
ch = s.ch
|
||||
if n > 0 {
|
||||
prev_s := s^
|
||||
for in 0..<n {
|
||||
for _ in 0..<n {
|
||||
next(s)
|
||||
}
|
||||
ch = s.ch
|
||||
@@ -214,7 +214,7 @@ peek :: proc(s: ^Scanner, n := 0) -> (ch: rune) {
|
||||
peek_token :: proc(s: ^Scanner, n := 0) -> (tok: rune) {
|
||||
assert(n >= 0)
|
||||
prev_s := s^
|
||||
for in 0..<n {
|
||||
for _ in 0..<n {
|
||||
tok = scan(s)
|
||||
}
|
||||
tok = scan(s)
|
||||
|
||||
@@ -10,7 +10,7 @@ CAS :: intrinsics.atomic_compare_exchange_strong
|
||||
|
||||
// NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t.
|
||||
// Also see core/sys/darwin/mach_darwin.odin/semaphore_t.
|
||||
Thread_Os_Specific :: struct #align 16 {
|
||||
Thread_Os_Specific :: struct #align(16) {
|
||||
unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux.
|
||||
cond: sync.Cond,
|
||||
mutex: sync.Mutex,
|
||||
|
||||
@@ -86,44 +86,40 @@ generate_encoding_entity_table :: proc() {
|
||||
|
||||
nth := 0
|
||||
for {
|
||||
character_entity, entity_ok := xml.find_child_by_ident(char, "entity", nth)
|
||||
if !entity_ok { break }
|
||||
|
||||
nth += 1
|
||||
if name, name_ok := xml.find_attribute_val_by_key(character_entity, "id"); name_ok {
|
||||
|
||||
if len(name) == 0 {
|
||||
/*
|
||||
Invalid name. Skip.
|
||||
*/
|
||||
continue
|
||||
}
|
||||
|
||||
if name == "\"\"" {
|
||||
printf("%#v\n", char)
|
||||
printf("%#v\n", character_entity)
|
||||
}
|
||||
|
||||
if len(name) > max_name_length { longest_name = name }
|
||||
if len(name) < min_name_length { shortest_name = name }
|
||||
|
||||
min_name_length = min(min_name_length, len(name))
|
||||
max_name_length = max(max_name_length, len(name))
|
||||
|
||||
e := Entity{
|
||||
name = name,
|
||||
codepoint = rune(codepoint),
|
||||
description = description,
|
||||
}
|
||||
|
||||
if _, seen := entity_map[name]; seen {
|
||||
continue
|
||||
}
|
||||
|
||||
entity_map[name] = e
|
||||
append(&names, name)
|
||||
count += 1
|
||||
character_entity := xml.find_child_by_ident(char, "entity", nth) or_break
|
||||
nth += 1
|
||||
name := xml.find_attribute_val_by_key(character_entity, "id") or_continue
|
||||
if len(name) == 0 {
|
||||
/*
|
||||
Invalid name. Skip.
|
||||
*/
|
||||
continue
|
||||
}
|
||||
|
||||
if name == "\"\"" {
|
||||
printf("%#v\n", char)
|
||||
printf("%#v\n", character_entity)
|
||||
}
|
||||
|
||||
if len(name) > max_name_length { longest_name = name }
|
||||
if len(name) < min_name_length { shortest_name = name }
|
||||
|
||||
min_name_length = min(min_name_length, len(name))
|
||||
max_name_length = max(max_name_length, len(name))
|
||||
|
||||
e := Entity{
|
||||
name = name,
|
||||
codepoint = rune(codepoint),
|
||||
description = description,
|
||||
}
|
||||
|
||||
if name in entity_map {
|
||||
continue
|
||||
}
|
||||
|
||||
entity_map[name] = e
|
||||
append(&names, name)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+176
-83
@@ -459,6 +459,27 @@ named_proc_return_parameters :: proc() {
|
||||
fmt.println("foo2 =", foo2()) // 567 321
|
||||
}
|
||||
|
||||
variadic_procedures :: proc() {
|
||||
fmt.println("\n# variadic procedures")
|
||||
sum :: proc(nums: ..int, init_value:= 0) -> (result: int) {
|
||||
result = init_value
|
||||
for n in nums {
|
||||
result += n
|
||||
}
|
||||
return
|
||||
}
|
||||
fmt.println("sum(()) =", sum())
|
||||
fmt.println("sum(1, 2) =", sum(1, 2))
|
||||
fmt.println("sum(1, 2, 3, 4, 5) =", sum(1, 2, 3, 4, 5))
|
||||
fmt.println("sum(1, 2, 3, 4, 5, init_value = 5) =", sum(1, 2, 3, 4, 5, init_value = 5))
|
||||
|
||||
// pass a slice as varargs
|
||||
odds := []int{1, 3, 5}
|
||||
fmt.println("odds =", odds)
|
||||
fmt.println("sum(..odds) =", sum(..odds))
|
||||
fmt.println("sum(..odds, init_value = 5) =", sum(..odds, init_value = 5))
|
||||
}
|
||||
|
||||
|
||||
explicit_procedure_overloading :: proc() {
|
||||
fmt.println("\n# explicit procedure overloading")
|
||||
@@ -539,7 +560,7 @@ struct_type :: proc() {
|
||||
{
|
||||
// Structs can tagged with different memory layout and alignment requirements:
|
||||
|
||||
a :: struct #align 4 {} // align to 4 bytes
|
||||
a :: struct #align(4) {} // align to 4 bytes
|
||||
b :: struct #packed {} // remove padding between fields
|
||||
c :: struct #raw_union {} // all fields share the same offset (0). This is the same as C's union
|
||||
}
|
||||
@@ -1134,7 +1155,7 @@ threading_example :: proc() {
|
||||
threads := make([dynamic]^thread.Thread, 0, len(prefix_table))
|
||||
defer delete(threads)
|
||||
|
||||
for in prefix_table {
|
||||
for _ in prefix_table {
|
||||
if t := thread.create(worker_proc); t != nil {
|
||||
t.init_context = context
|
||||
t.user_index = len(threads)
|
||||
@@ -1333,13 +1354,13 @@ partial_switch :: proc() {
|
||||
{ // union
|
||||
Foo :: union {int, bool}
|
||||
f: Foo = 123
|
||||
switch in f {
|
||||
switch _ in f {
|
||||
case int: fmt.println("int")
|
||||
case bool: fmt.println("bool")
|
||||
case:
|
||||
}
|
||||
|
||||
#partial switch in f {
|
||||
#partial switch _ in f {
|
||||
case bool: fmt.println("bool")
|
||||
}
|
||||
}
|
||||
@@ -1765,19 +1786,7 @@ range_statements_with_multiple_return_values :: proc() {
|
||||
data[i] = i32(i*i)
|
||||
}
|
||||
|
||||
{
|
||||
it := make_my_iterator(data)
|
||||
for val in my_iterator(&it) {
|
||||
fmt.println(val)
|
||||
}
|
||||
}
|
||||
{
|
||||
it := make_my_iterator(data)
|
||||
for val, idx in my_iterator(&it) {
|
||||
fmt.println(val, idx)
|
||||
}
|
||||
}
|
||||
{
|
||||
{ // Manual Style
|
||||
it := make_my_iterator(data)
|
||||
for {
|
||||
val, _, cond := my_iterator(&it)
|
||||
@@ -1787,6 +1796,25 @@ range_statements_with_multiple_return_values :: proc() {
|
||||
fmt.println(val)
|
||||
}
|
||||
}
|
||||
{ // or_break
|
||||
it := make_my_iterator(data)
|
||||
loop: for {
|
||||
val, _ := my_iterator(&it) or_break loop
|
||||
fmt.println(val)
|
||||
}
|
||||
}
|
||||
{ // first value
|
||||
it := make_my_iterator(data)
|
||||
for val in my_iterator(&it) {
|
||||
fmt.println(val)
|
||||
}
|
||||
}
|
||||
{ // first and second value
|
||||
it := make_my_iterator(data)
|
||||
for val, idx in my_iterator(&it) {
|
||||
fmt.println(val, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2024,12 +2052,11 @@ relative_data_types :: proc() {
|
||||
fmt.println(ptr^)
|
||||
|
||||
arr := [3]int{1, 2, 3}
|
||||
s := arr[:]
|
||||
rel_slice: #relative(i16) []int
|
||||
rel_slice = s
|
||||
fmt.println(rel_slice)
|
||||
fmt.println(rel_slice[:])
|
||||
fmt.println(rel_slice[1])
|
||||
multi_ptr: #relative(i16) [^]int
|
||||
multi_ptr = &arr[0]
|
||||
fmt.println(multi_ptr)
|
||||
fmt.println(multi_ptr[:3])
|
||||
fmt.println(multi_ptr[1])
|
||||
}
|
||||
|
||||
or_else_operator :: proc() {
|
||||
@@ -2052,7 +2079,7 @@ or_else_operator :: proc() {
|
||||
// have optional ok semantics
|
||||
v: union{int, f64}
|
||||
i: int
|
||||
i = v.(int) or_else 123
|
||||
i = v.(int) or_else 123
|
||||
i = v.? or_else 123 // Type inference magic
|
||||
assert(i == 123)
|
||||
|
||||
@@ -2158,6 +2185,70 @@ or_return_operator :: proc() {
|
||||
foo_2()
|
||||
}
|
||||
|
||||
|
||||
or_break_and_or_continue_operators :: proc() {
|
||||
fmt.println("\n#'or_break' and 'or_continue'")
|
||||
// The concept of 'or_break' and 'or_continue' is very similar to that of 'or_return'.
|
||||
// The difference is that unlike 'or_return', the value does not get returned from
|
||||
// the current procedure but rather discarded if it is 'false' or not 'nil', and then
|
||||
// the specified branch (i.e. break or_continue).
|
||||
// The or branch expression can be labelled if a specific statement needs to be used.
|
||||
|
||||
Error :: enum {
|
||||
None,
|
||||
Something_Bad,
|
||||
Something_Worse,
|
||||
The_Worst,
|
||||
Your_Mum,
|
||||
}
|
||||
|
||||
caller_1 :: proc() -> Error {
|
||||
return .Something_Bad
|
||||
}
|
||||
|
||||
caller_2 :: proc() -> (int, Error) {
|
||||
return 123, .Something_Worse
|
||||
}
|
||||
caller_3 :: proc() -> (int, int, Error) {
|
||||
return 123, 345, .None
|
||||
}
|
||||
|
||||
for { // common approach
|
||||
err := caller_1()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
for { // or_break approach
|
||||
caller_1() or_break
|
||||
}
|
||||
|
||||
for { // or_break approach with multiple values
|
||||
n := caller_2() or_break
|
||||
_ = n
|
||||
}
|
||||
|
||||
loop: for { // or_break approach with named label
|
||||
n := caller_2() or_break loop
|
||||
_ = n
|
||||
}
|
||||
|
||||
for { // or_continue
|
||||
x, y := caller_3() or_continue
|
||||
_, _ = x, y
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
continue_loop: for { // or_continue with named label
|
||||
x, y := caller_3() or_continue continue_loop
|
||||
_, _ = x, y
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
arbitrary_precision_mathematics :: proc() {
|
||||
fmt.println("\n# core:math/big")
|
||||
|
||||
@@ -2238,98 +2329,98 @@ matrix_type :: proc() {
|
||||
fmt.println("\n# matrix type")
|
||||
// A matrix is a mathematical type built into Odin. It is a regular array of numbers,
|
||||
// arranged in rows and columns
|
||||
|
||||
|
||||
{
|
||||
// The following represents a matrix that has 2 rows and 3 columns
|
||||
m: matrix[2, 3]f32
|
||||
|
||||
|
||||
m = matrix[2, 3]f32{
|
||||
1, 9, -13,
|
||||
20, 5, -6,
|
||||
}
|
||||
|
||||
|
||||
// Element types of integers, float, and complex numbers are supported by matrices.
|
||||
// There is no support for booleans, quaternions, or any compound type.
|
||||
|
||||
|
||||
// Indexing a matrix can be used with the matrix indexing syntax
|
||||
// This mirrors othe type usages: type on the left, usage on the right
|
||||
|
||||
|
||||
elem := m[1, 2] // row 1, column 2
|
||||
assert(elem == -6)
|
||||
|
||||
|
||||
|
||||
|
||||
// Scalars act as if they are scaled identity matrices
|
||||
// and can be assigned to matrices as them
|
||||
b := matrix[2, 2]f32{}
|
||||
f := f32(3)
|
||||
b = f
|
||||
|
||||
|
||||
fmt.println("b", b)
|
||||
fmt.println("b == f", b == f)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
{ // Matrices support multiplication between matrices
|
||||
a := matrix[2, 3]f32{
|
||||
2, 3, 1,
|
||||
4, 5, 0,
|
||||
}
|
||||
|
||||
|
||||
b := matrix[3, 2]f32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
5, 6,
|
||||
}
|
||||
|
||||
|
||||
fmt.println("a", a)
|
||||
fmt.println("b", b)
|
||||
|
||||
|
||||
c := a * b
|
||||
#assert(type_of(c) == matrix[2, 2]f32)
|
||||
fmt.tprintln("c = a * b", c)
|
||||
fmt.tprintln("c = a * b", c)
|
||||
}
|
||||
|
||||
|
||||
{ // Matrices support multiplication between matrices and arrays
|
||||
m := matrix[4, 4]f32{
|
||||
1, 2, 3, 4,
|
||||
5, 5, 4, 2,
|
||||
0, 1, 3, 0,
|
||||
1, 2, 3, 4,
|
||||
5, 5, 4, 2,
|
||||
0, 1, 3, 0,
|
||||
0, 1, 4, 1,
|
||||
}
|
||||
|
||||
|
||||
v := [4]f32{1, 5, 4, 3}
|
||||
|
||||
|
||||
// treating 'v' as a column vector
|
||||
fmt.println("m * v", m * v)
|
||||
|
||||
|
||||
// treating 'v' as a row vector
|
||||
fmt.println("v * m", v * m)
|
||||
|
||||
|
||||
// Support with non-square matrices
|
||||
s := matrix[2, 4]f32{ // [4][2]f32
|
||||
2, 4, 3, 1,
|
||||
7, 8, 6, 5,
|
||||
2, 4, 3, 1,
|
||||
7, 8, 6, 5,
|
||||
}
|
||||
|
||||
|
||||
w := [2]f32{1, 2}
|
||||
r: [4]f32 = w * s
|
||||
fmt.println("r", r)
|
||||
}
|
||||
|
||||
{ // Component-wise operations
|
||||
|
||||
{ // Component-wise operations
|
||||
// if the element type supports it
|
||||
// Not support for '/', '%', or '%%' operations
|
||||
|
||||
|
||||
a := matrix[2, 2]i32{
|
||||
1, 2,
|
||||
3, 4,
|
||||
}
|
||||
|
||||
|
||||
b := matrix[2, 2]i32{
|
||||
-5, 1,
|
||||
9, -7,
|
||||
}
|
||||
|
||||
|
||||
c0 := a + b
|
||||
c1 := a - b
|
||||
c2 := a & b
|
||||
@@ -2339,9 +2430,9 @@ matrix_type :: proc() {
|
||||
|
||||
// component-wise multiplication
|
||||
// since a * b would be a standard matrix multiplication
|
||||
c6 := hadamard_product(a, b)
|
||||
|
||||
|
||||
c6 := hadamard_product(a, b)
|
||||
|
||||
|
||||
fmt.println("a + b", c0)
|
||||
fmt.println("a - b", c1)
|
||||
fmt.println("a & b", c2)
|
||||
@@ -2350,23 +2441,23 @@ matrix_type :: proc() {
|
||||
fmt.println("a &~ b", c5)
|
||||
fmt.println("hadamard_product(a, b)", c6)
|
||||
}
|
||||
|
||||
|
||||
{ // Submatrix casting square matrices
|
||||
// Casting a square matrix to another square matrix with same element type
|
||||
// is supported.
|
||||
// is supported.
|
||||
// If the cast is to a smaller matrix type, the top-left submatrix is taken.
|
||||
// If the cast is to a larger matrix type, the matrix is extended with zeros
|
||||
// everywhere and ones in the diagonal for the unfilled elements of the
|
||||
// everywhere and ones in the diagonal for the unfilled elements of the
|
||||
// extended matrix.
|
||||
|
||||
|
||||
mat2 :: distinct matrix[2, 2]f32
|
||||
mat4 :: distinct matrix[4, 4]f32
|
||||
|
||||
|
||||
m2 := mat2{
|
||||
1, 3,
|
||||
2, 4,
|
||||
}
|
||||
|
||||
|
||||
m4 := mat4(m2)
|
||||
assert(m4[2, 2] == 1)
|
||||
assert(m4[3, 3] == 1)
|
||||
@@ -2374,7 +2465,7 @@ matrix_type :: proc() {
|
||||
fmt.println("m4", m4)
|
||||
fmt.println("mat2(m4)", mat2(m4))
|
||||
assert(mat2(m4) == m2)
|
||||
|
||||
|
||||
b4 := mat4{
|
||||
1, 2, 0, 0,
|
||||
3, 4, 0, 0,
|
||||
@@ -2383,43 +2474,43 @@ matrix_type :: proc() {
|
||||
}
|
||||
fmt.println("b4", matrix_flatten(b4))
|
||||
}
|
||||
|
||||
|
||||
{ // Casting non-square matrices
|
||||
// Casting a matrix to another matrix is allowed as long as they share
|
||||
// Casting a matrix to another matrix is allowed as long as they share
|
||||
// the same element type and the number of elements (rows*columns).
|
||||
// Matrices in Odin are stored in column-major order, which means
|
||||
// the casts will preserve this element order.
|
||||
|
||||
|
||||
mat2x4 :: distinct matrix[2, 4]f32
|
||||
mat4x2 :: distinct matrix[4, 2]f32
|
||||
|
||||
|
||||
x := mat2x4{
|
||||
1, 3, 5, 7,
|
||||
1, 3, 5, 7,
|
||||
2, 4, 6, 8,
|
||||
}
|
||||
|
||||
|
||||
y := mat4x2(x)
|
||||
fmt.println("x", x)
|
||||
fmt.println("y", y)
|
||||
}
|
||||
|
||||
|
||||
// TECHNICAL INFORMATION: the internal representation of a matrix in Odin is stored
|
||||
// in column-major format
|
||||
// e.g. matrix[2, 3]f32 is internally [3][2]f32 (with different a alignment requirement)
|
||||
// Column-major is used in order to utilize (SIMD) vector instructions effectively on
|
||||
// Column-major is used in order to utilize (SIMD) vector instructions effectively on
|
||||
// modern hardware, if possible.
|
||||
//
|
||||
// Unlike normal arrays, matrices try to maximize alignment to allow for the (SIMD) vectorization
|
||||
// properties whilst keeping zero padding (either between columns or at the end of the type).
|
||||
//
|
||||
//
|
||||
// Zero padding is a compromise for use with third-party libraries, instead of optimizing for performance.
|
||||
// Padding between columns was not taken even if that would have allowed each column to be loaded
|
||||
// individually into a SIMD register with the correct alignment properties.
|
||||
//
|
||||
// Padding between columns was not taken even if that would have allowed each column to be loaded
|
||||
// individually into a SIMD register with the correct alignment properties.
|
||||
//
|
||||
// Currently, matrices are limited to a maximum of 16 elements (rows*columns), and a minimum of 1 element.
|
||||
// This is because matrices are stored as values (not a reference type), and thus operations on them will
|
||||
// be stored on the stack. Restricting the maximum element count minimizing the possibility of stack overflows.
|
||||
|
||||
|
||||
// Built-in Procedures (Compiler Level)
|
||||
// transpose(m)
|
||||
// transposes a matrix
|
||||
@@ -2434,13 +2525,13 @@ matrix_type :: proc() {
|
||||
// Example:
|
||||
// m := matrix[2, 2]f32{
|
||||
// x0, x1,
|
||||
// y0, y1,
|
||||
// y0, y1,
|
||||
// }
|
||||
// array: [4]f32 = matrix_flatten(m)
|
||||
// assert(array == {x0, y0, x1, y1})
|
||||
// conj(x)
|
||||
// conjugates the elements of a matrix for complex element types only
|
||||
|
||||
|
||||
// Built-in Procedures (Runtime Level) (all square matrix procedures)
|
||||
// determinant(m)
|
||||
// adjugate(m)
|
||||
@@ -2454,8 +2545,8 @@ matrix_type :: proc() {
|
||||
main :: proc() {
|
||||
/*
|
||||
For More Odin Examples - https://github.com/odin-lang/examples
|
||||
This repository contains examples of how certain things can be accomplished
|
||||
in idiomatic Odin, allowing you learn its semantics, as well as how to use
|
||||
This repository contains examples of how certain things can be accomplished
|
||||
in idiomatic Odin, allowing you learn its semantics, as well as how to use
|
||||
parts of the core and vendor package collections.
|
||||
*/
|
||||
|
||||
@@ -2463,6 +2554,7 @@ main :: proc() {
|
||||
the_basics()
|
||||
control_flow()
|
||||
named_proc_return_parameters()
|
||||
variadic_procedures()
|
||||
explicit_procedure_overloading()
|
||||
struct_type()
|
||||
union_type()
|
||||
@@ -2492,7 +2584,8 @@ main :: proc() {
|
||||
relative_data_types()
|
||||
or_else_operator()
|
||||
or_return_operator()
|
||||
or_break_and_or_continue_operators()
|
||||
arbitrary_precision_mathematics()
|
||||
matrix_type()
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -2,9 +2,10 @@
|
||||
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
||||
set _NO_DEBUG_HEAP=1
|
||||
|
||||
set ODIN_IGNORE_MSVC_CHECK=1
|
||||
|
||||
@@ -168,6 +168,17 @@ gb_internal gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi)
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename T>
|
||||
gb_internal gb_inline Slice<T> slice(Array<T> const &array, isize lo, isize hi) {
|
||||
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||
Slice<T> out = {};
|
||||
isize len = hi-lo;
|
||||
if (len > 0) {
|
||||
out.data = array.data+lo;
|
||||
out.count = len;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
@@ -303,6 +314,14 @@ gb_internal void array_add(Array<T> *array, T const &t) {
|
||||
array->count++;
|
||||
}
|
||||
|
||||
gb_internal void array_add(Array<char const *> *array, char const *t) {
|
||||
if (array->capacity < array->count+1) {
|
||||
array__grow(array, 0);
|
||||
}
|
||||
array->data[array->count] = t;
|
||||
array->count++;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal T *array_add_and_get(Array<T> *array) {
|
||||
if (array->count < array->capacity) {
|
||||
|
||||
+79
-7
@@ -123,6 +123,18 @@ struct TargetMetrics {
|
||||
TargetABIKind abi;
|
||||
};
|
||||
|
||||
enum Subtarget : u32 {
|
||||
Subtarget_Default,
|
||||
Subtarget_iOS,
|
||||
|
||||
Subtarget_COUNT,
|
||||
};
|
||||
|
||||
gb_global String subtarget_strings[Subtarget_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("ios"),
|
||||
};
|
||||
|
||||
|
||||
enum QueryDataSetKind {
|
||||
QueryDataSet_Invalid,
|
||||
@@ -225,9 +237,7 @@ enum VetFlags : u64 {
|
||||
VetFlag_Style = 1u<<4, // 16
|
||||
VetFlag_Semicolon = 1u<<5, // 32
|
||||
|
||||
VetFlag_Extra = 1u<<16,
|
||||
|
||||
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt, // excluding extra
|
||||
VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt,
|
||||
|
||||
VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam,
|
||||
};
|
||||
@@ -245,13 +255,19 @@ u64 get_vet_flag_from_name(String const &name) {
|
||||
return VetFlag_Style;
|
||||
} else if (name == "semicolon") {
|
||||
return VetFlag_Semicolon;
|
||||
} else if (name == "extra") {
|
||||
return VetFlag_Extra;
|
||||
}
|
||||
return VetFlag_NONE;
|
||||
}
|
||||
|
||||
|
||||
enum SanitizerFlags : u32 {
|
||||
SanitizerFlag_NONE = 0,
|
||||
SanitizerFlag_Address = 1u<<0,
|
||||
SanitizerFlag_Memory = 1u<<1,
|
||||
SanitizerFlag_Thread = 1u<<2,
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
@@ -293,6 +309,7 @@ struct BuildContext {
|
||||
String pdb_filepath;
|
||||
|
||||
u64 vet_flags;
|
||||
u32 sanitizer_flags;
|
||||
|
||||
bool has_resource;
|
||||
String link_flags;
|
||||
@@ -354,6 +371,8 @@ struct BuildContext {
|
||||
|
||||
isize max_error_count;
|
||||
|
||||
bool tilde_backend;
|
||||
|
||||
|
||||
u32 cmd_doc_flags;
|
||||
Array<String> extra_packages;
|
||||
@@ -583,6 +602,8 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
};
|
||||
|
||||
gb_global NamedTargetMetrics *selected_target_metrics;
|
||||
gb_global Subtarget selected_subtarget;
|
||||
|
||||
|
||||
gb_internal TargetOsKind get_target_os_from_string(String str) {
|
||||
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
||||
@@ -1145,7 +1166,7 @@ gb_internal char *token_pos_to_string(TokenPos const &pos) {
|
||||
return s;
|
||||
}
|
||||
|
||||
gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||
gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subtarget) {
|
||||
BuildContext *bc = &build_context;
|
||||
|
||||
gb_affinity_init(&bc->affinity);
|
||||
@@ -1240,6 +1261,21 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||
|
||||
|
||||
bc->metrics = *metrics;
|
||||
switch (subtarget) {
|
||||
case Subtarget_Default:
|
||||
break;
|
||||
case Subtarget_iOS:
|
||||
GB_ASSERT(metrics->os == TargetOs_darwin);
|
||||
if (metrics->arch == TargetArch_arm64) {
|
||||
bc->metrics.target_triplet = str_lit("arm64-apple-ios");
|
||||
} else if (metrics->arch == TargetArch_amd64) {
|
||||
bc->metrics.target_triplet = str_lit("x86_64-apple-ios");
|
||||
} else {
|
||||
GB_PANIC("Unknown architecture for darwin");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bc->ODIN_OS = target_os_names[metrics->os];
|
||||
bc->ODIN_ARCH = target_arch_names[metrics->arch];
|
||||
bc->endian_kind = target_endians[metrics->arch];
|
||||
@@ -1350,7 +1386,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||
bc->optimization_level = -1; // -o:none
|
||||
}
|
||||
|
||||
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2);
|
||||
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 3);
|
||||
|
||||
// ENFORCE DYNAMIC MAP CALLS
|
||||
bc->dynamic_map_calls = true;
|
||||
@@ -1707,6 +1743,42 @@ gb_internal bool init_build_paths(String init_filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Address) {
|
||||
switch (build_context.metrics.os) {
|
||||
case TargetOs_windows:
|
||||
case TargetOs_linux:
|
||||
case TargetOs_darwin:
|
||||
break;
|
||||
default:
|
||||
gb_printf_err("-sanitize:address is only supported on windows, linux, and darwin\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Memory) {
|
||||
switch (build_context.metrics.os) {
|
||||
case TargetOs_linux:
|
||||
break;
|
||||
default:
|
||||
gb_printf_err("-sanitize:memory is only supported on linux\n");
|
||||
return false;
|
||||
}
|
||||
if (build_context.metrics.os != TargetOs_linux) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
|
||||
switch (build_context.metrics.os) {
|
||||
case TargetOs_linux:
|
||||
case TargetOs_darwin:
|
||||
break;
|
||||
default:
|
||||
gb_printf_err("-sanitize:thread is only supported on linux and darwin\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bc->target_features_string.len != 0) {
|
||||
enable_target_feature({}, bc->target_features_string);
|
||||
|
||||
@@ -471,10 +471,10 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
// Integer only
|
||||
case BuiltinProc_simd_add_sat:
|
||||
case BuiltinProc_simd_sub_sat:
|
||||
case BuiltinProc_simd_and:
|
||||
case BuiltinProc_simd_or:
|
||||
case BuiltinProc_simd_xor:
|
||||
case BuiltinProc_simd_and_not:
|
||||
case BuiltinProc_simd_bit_and:
|
||||
case BuiltinProc_simd_bit_or:
|
||||
case BuiltinProc_simd_bit_xor:
|
||||
case BuiltinProc_simd_bit_and_not:
|
||||
{
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
@@ -1748,7 +1748,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
mode = Addressing_Constant;
|
||||
value = exact_value_i64(at->EnumeratedArray.count);
|
||||
type = t_untyped_integer;
|
||||
} else if ((is_type_slice(op_type) || is_type_relative_slice(op_type)) && id == BuiltinProc_len) {
|
||||
} else if (is_type_slice(op_type) && id == BuiltinProc_len) {
|
||||
mode = Addressing_Value;
|
||||
} else if (is_type_dynamic_array(op_type)) {
|
||||
mode = Addressing_Value;
|
||||
@@ -2120,7 +2120,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
Type *t = o.type;
|
||||
if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) {
|
||||
if (t == nullptr || t == t_invalid || is_type_asm_proc(t) || is_type_polymorphic(t)) {
|
||||
error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
@@ -3692,6 +3692,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
case Type_SimdVector:
|
||||
operand->type = alloc_type_multi_pointer(base_array_type(base));
|
||||
break;
|
||||
case Type_Matrix:
|
||||
operand->type = alloc_type_multi_pointer(base->Matrix.elem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+7
-4
@@ -321,7 +321,14 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
|
||||
gb_string_free(str);
|
||||
is_distinct = false;
|
||||
}
|
||||
} else {
|
||||
if (is_type_typeid(e->type)) {
|
||||
error(init_expr, "'typeid' cannot be aliased");
|
||||
} else if (is_type_any(e->type)) {
|
||||
error(init_expr, "'any' cannot be aliased");
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_distinct) {
|
||||
e->type = bt;
|
||||
named->Named.base = bt;
|
||||
@@ -1329,10 +1336,6 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_Polymorphic:
|
||||
#if 0
|
||||
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
#endif
|
||||
break;
|
||||
case ProcOverload_ParamCount:
|
||||
case ProcOverload_ParamTypes:
|
||||
|
||||
+210
-104
@@ -629,6 +629,9 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
if (is_type_typeid(type)) {
|
||||
if (is_type_polymorphic(operand->type)) {
|
||||
return -1;
|
||||
}
|
||||
add_type_info_type(c, operand->type);
|
||||
return 4;
|
||||
}
|
||||
@@ -856,8 +859,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_relative_slice(dst)) {
|
||||
i64 score = check_distance_between_types(c, operand, dst->RelativeSlice.slice_type);
|
||||
if (is_type_relative_multi_pointer(dst)) {
|
||||
i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type);
|
||||
if (score >= 0) {
|
||||
return score+2;
|
||||
}
|
||||
@@ -1005,8 +1008,8 @@ gb_internal AstPackage *get_package_of_type(Type *type) {
|
||||
case Type_RelativePointer:
|
||||
type = type->RelativePointer.pointer_type;
|
||||
continue;
|
||||
case Type_RelativeSlice:
|
||||
type = type->RelativeSlice.slice_type;
|
||||
case Type_RelativeMultiPointer:
|
||||
type = type->RelativeMultiPointer.pointer_type;
|
||||
continue;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -1118,10 +1121,17 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
LIT(context_name));
|
||||
break;
|
||||
case Addressing_Type:
|
||||
error(operand->expr,
|
||||
"Cannot assign '%s' which is a type in %.*s",
|
||||
op_type_str,
|
||||
LIT(context_name));
|
||||
if (is_type_polymorphic(operand->type)) {
|
||||
error(operand->expr,
|
||||
"Cannot assign '%s' which is a polymorphic type in %.*s",
|
||||
op_type_str,
|
||||
LIT(context_name));
|
||||
} else {
|
||||
error(operand->expr,
|
||||
"Cannot assign '%s' which is a type in %.*s",
|
||||
op_type_str,
|
||||
LIT(context_name));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// TODO(bill): is this a good enough error message?
|
||||
@@ -2452,8 +2462,9 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t
|
||||
add_package_dependency(c, "runtime", "quaternion256_ne");
|
||||
break;
|
||||
case Basic_cstring:
|
||||
add_package_dependency(c, "runtime", "cstring_to_string");
|
||||
/*fallthrough*/
|
||||
add_package_dependency(c, "runtime", "cstring_eq");
|
||||
add_package_dependency(c, "runtime", "cstring_ne");
|
||||
break;
|
||||
case Basic_string:
|
||||
add_package_dependency(c, "runtime", "string_eq");
|
||||
add_package_dependency(c, "runtime", "string_ne");
|
||||
@@ -2611,7 +2622,16 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper
|
||||
if (!is_type_untyped(x->type)) size = gb_max(size, type_size_of(x->type));
|
||||
if (!is_type_untyped(y->type)) size = gb_max(size, type_size_of(y->type));
|
||||
|
||||
if (is_type_string(x->type) || is_type_string(y->type)) {
|
||||
if (is_type_cstring(x->type) && is_type_cstring(y->type)) {
|
||||
switch (op) {
|
||||
case Token_CmpEq: add_package_dependency(c, "runtime", "cstring_eq"); break;
|
||||
case Token_NotEq: add_package_dependency(c, "runtime", "cstring_ne"); break;
|
||||
case Token_Lt: add_package_dependency(c, "runtime", "cstring_lt"); break;
|
||||
case Token_Gt: add_package_dependency(c, "runtime", "cstring_gt"); break;
|
||||
case Token_LtEq: add_package_dependency(c, "runtime", "cstring_le"); break;
|
||||
case Token_GtEq: add_package_dependency(c, "runtime", "cstring_gt"); break;
|
||||
}
|
||||
} else if (is_type_string(x->type) || is_type_string(y->type)) {
|
||||
switch (op) {
|
||||
case Token_CmpEq: add_package_dependency(c, "runtime", "string_eq"); break;
|
||||
case Token_NotEq: add_package_dependency(c, "runtime", "string_ne"); break;
|
||||
@@ -3082,14 +3102,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
update_untyped_expr_type(c, x->expr, final_type, true);
|
||||
}
|
||||
|
||||
if (check_vet_flags(x->expr) & VetFlag_Extra) {
|
||||
if (are_types_identical(x->type, type)) {
|
||||
gbString str = type_to_string(type);
|
||||
warning(x->expr, "Unneeded cast to the same type '%s'", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
x->type = type;
|
||||
}
|
||||
|
||||
@@ -3154,14 +3166,6 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
|
||||
return false;
|
||||
}
|
||||
|
||||
if (check_vet_flags(node) & VetFlag_Extra) {
|
||||
if (are_types_identical(o->type, dst_t)) {
|
||||
gbString str = type_to_string(dst_t);
|
||||
warning(o->expr, "Unneeded transmute to the same type '%s'", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
o->expr = node;
|
||||
o->type = dst_t;
|
||||
if (o->mode == Addressing_Constant) {
|
||||
@@ -3663,18 +3667,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
||||
ExactValue b = y->value;
|
||||
|
||||
if (!is_type_constant_type(x->type)) {
|
||||
#if 0
|
||||
gbString xt = type_to_string(x->type);
|
||||
gbString err_str = expr_to_string(node);
|
||||
error(op, "Invalid type, '%s', for constant binary expression '%s'", xt, err_str);
|
||||
gb_string_free(err_str);
|
||||
gb_string_free(xt);
|
||||
x->mode = Addressing_Invalid;
|
||||
#else
|
||||
// NOTE(bill, 2021-04-21): The above is literally a useless error message.
|
||||
// Why did I add it in the first place?!
|
||||
x->mode = Addressing_Value;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3817,6 +3810,15 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type,
|
||||
update_untyped_expr_type(c, ore->expr, type, final);
|
||||
case_end;
|
||||
|
||||
case_ast_node(obe, OrBranchExpr, e);
|
||||
if (old->value.kind != ExactValue_Invalid) {
|
||||
// See above note in UnaryExpr case
|
||||
break;
|
||||
}
|
||||
|
||||
update_untyped_expr_type(c, obe->expr, type, final);
|
||||
case_end;
|
||||
|
||||
case_ast_node(oee, OrElseExpr, e);
|
||||
if (old->value.kind != ExactValue_Invalid) {
|
||||
// See above note in UnaryExpr case
|
||||
@@ -5092,27 +5094,6 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) {
|
||||
if (lhs != nullptr && c->decl != nullptr) {
|
||||
for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) {
|
||||
Entity *e = lhs[tuple_index + j];
|
||||
if (e != nullptr) {
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
if (decl != nullptr) {
|
||||
rw_mutex_shared_lock(&decl->deps_mutex);
|
||||
rw_mutex_lock(&c->decl->deps_mutex);
|
||||
for (Entity *dep : decl->deps) {
|
||||
ptr_set_add(&c->decl->deps, dep);
|
||||
}
|
||||
rw_mutex_unlock(&c->decl->deps_mutex);
|
||||
rw_mutex_shared_unlock(&decl->deps_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tuple_count;
|
||||
}
|
||||
|
||||
gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) {
|
||||
if (o.type && is_type_no_copy(o.type)) {
|
||||
Ast *expr = unparen_expr(o.expr);
|
||||
@@ -5220,6 +5201,31 @@ enum UnpackFlag : u32 {
|
||||
|
||||
|
||||
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs_arguments, UnpackFlags flags) {
|
||||
auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize {
|
||||
if (lhs == nullptr || c->decl == nullptr) {
|
||||
return tuple_count;
|
||||
}
|
||||
for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) {
|
||||
Entity *e = lhs[tuple_index + j];
|
||||
if (e == nullptr) {
|
||||
continue;
|
||||
}
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
if (decl == nullptr) {
|
||||
continue;
|
||||
}
|
||||
rw_mutex_shared_lock(&decl->deps_mutex);
|
||||
rw_mutex_lock(&c->decl->deps_mutex);
|
||||
for (Entity *dep : decl->deps) {
|
||||
ptr_set_add(&c->decl->deps, dep);
|
||||
}
|
||||
rw_mutex_unlock(&c->decl->deps_mutex);
|
||||
rw_mutex_shared_unlock(&decl->deps_mutex);
|
||||
}
|
||||
return tuple_count;
|
||||
};
|
||||
|
||||
|
||||
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
|
||||
bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
|
||||
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
|
||||
@@ -5474,6 +5480,8 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
|
||||
auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count);
|
||||
|
||||
bool named_variadic_param = false;
|
||||
|
||||
if (named_operands.count != 0) {
|
||||
GB_ASSERT(ce->split_args->named.count == named_operands.count);
|
||||
for_array(i, ce->split_args->named) {
|
||||
@@ -5499,6 +5507,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
err = CallArgumentError_ParameterNotFound;
|
||||
continue;
|
||||
}
|
||||
if (pt->variadic && param_index == pt->variadic_index) {
|
||||
named_variadic_param = true;
|
||||
}
|
||||
if (visited[param_index]) {
|
||||
if (show_error) {
|
||||
error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name));
|
||||
@@ -5546,11 +5557,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos;
|
||||
|
||||
Entity *vt = pt->params->Tuple.variables[pt->variadic_index];
|
||||
if (is_type_polymorphic(vt->type)) {
|
||||
o.type = alloc_type_slice(default_type(variadic_operands[0].type));
|
||||
} else {
|
||||
o.type = vt->type;
|
||||
}
|
||||
o.type = vt->type;
|
||||
} else {
|
||||
dummy_argument_count += 1;
|
||||
o.type = t_untyped_nil;
|
||||
@@ -5704,7 +5711,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
if (param_is_variadic) {
|
||||
continue;
|
||||
}
|
||||
|
||||
score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error);
|
||||
}
|
||||
}
|
||||
@@ -7154,6 +7160,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
c->decl->defer_used += 1;
|
||||
}
|
||||
}
|
||||
add_entity_use(c, operand->expr, initial_entity);
|
||||
}
|
||||
|
||||
if (operand->mode != Addressing_ProcGroup) {
|
||||
@@ -7361,11 +7368,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_RelativeSlice:
|
||||
case Type_RelativeMultiPointer:
|
||||
{
|
||||
Type *slice_type = base_type(t->RelativeSlice.slice_type);
|
||||
GB_ASSERT(slice_type->kind == Type_Slice);
|
||||
o->type = slice_type->Slice.elem;
|
||||
Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
|
||||
GB_ASSERT(pointer_type->kind == Type_MultiPointer);
|
||||
o->type = pointer_type->MultiPointer.elem;
|
||||
if (o->mode != Addressing_Constant) {
|
||||
o->mode = Addressing_Variable;
|
||||
}
|
||||
@@ -7753,7 +7760,10 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op
|
||||
multi_map_get_all(seen, key, taps);
|
||||
for (isize i = 0; i < count; i++) {
|
||||
TypeAndToken tap = taps[i];
|
||||
if (!are_types_identical(operand.type, tap.type)) {
|
||||
Operand to = {};
|
||||
to.mode = Addressing_Value;
|
||||
to.type = tap.type;
|
||||
if (!check_is_assignable_to_with_score(ctx, &to, operand.type, nullptr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -7796,20 +7806,8 @@ gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind u
|
||||
break;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (Entity *f : bt->Enum.fields) {
|
||||
GB_ASSERT(f->kind == Entity_Constant);
|
||||
|
||||
i64 fv = exact_value_to_i64(f->Constant.value);
|
||||
if (fv == vi) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
v.value = exact_value_i64(vi);
|
||||
add_constant_switch_case(ctx, seen, v);
|
||||
}
|
||||
v.value = exact_value_i64(vi);
|
||||
add_constant_switch_case(ctx, seen, v);
|
||||
}
|
||||
} else {
|
||||
add_constant_switch_case(ctx, seen, lhs);
|
||||
@@ -7931,7 +7929,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
|
||||
|
||||
// NOTE(bill, 2023-01-30): Allow for expression like this:
|
||||
// x: union{f32} = f32(123) if cond else nil
|
||||
if (type_hint && !is_type_any(type_hint) && !ternary_compare_types(x.type, y.type)) {
|
||||
if (type_hint && !is_type_any(type_hint)) {
|
||||
if (check_is_assignable_to(c, &x, type_hint) && check_is_assignable_to(c, &y, type_hint)) {
|
||||
check_cast(c, &x, type_hint);
|
||||
check_cast(c, &y, type_hint);
|
||||
@@ -8188,6 +8186,104 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
||||
ast_node(be, OrBranchExpr, node);
|
||||
|
||||
String name = be->token.string;
|
||||
Operand x = {};
|
||||
check_multi_expr_with_type_hint(c, &x, be->expr, type_hint);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
o->mode = Addressing_Value;
|
||||
o->type = t_invalid;
|
||||
o->expr = node;
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
Type *left_type = nullptr;
|
||||
Type *right_type = nullptr;
|
||||
check_or_return_split_types(c, &x, name, &left_type, &right_type);
|
||||
add_type_and_value(c, be->expr, x.mode, x.type, x.value);
|
||||
|
||||
if (right_type == nullptr) {
|
||||
check_or_else_expr_no_value_error(c, name, x, type_hint);
|
||||
} else {
|
||||
if (is_type_boolean(right_type) || type_has_nil(right_type)) {
|
||||
// okay
|
||||
} else {
|
||||
gbString s = type_to_string(right_type);
|
||||
error(node, "'%.*s' requires a boolean or nil-able type, got %s", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}
|
||||
|
||||
o->expr = node;
|
||||
o->type = left_type;
|
||||
if (left_type != nullptr) {
|
||||
o->mode = Addressing_Value;
|
||||
} else {
|
||||
o->mode = Addressing_NoValue;
|
||||
}
|
||||
|
||||
if (c->curr_proc_sig == nullptr) {
|
||||
error(node, "'%.*s' can only be used within a procedure", LIT(name));
|
||||
}
|
||||
|
||||
Ast *label = be->label;
|
||||
|
||||
switch (be->token.kind) {
|
||||
case Token_or_break:
|
||||
if ((c->stmt_flags & Stmt_BreakAllowed) == 0 && label == nullptr) {
|
||||
error(be->token, "'%.*s' only allowed in non-inline loops or 'switch' statements", LIT(name));
|
||||
}
|
||||
break;
|
||||
case Token_or_continue:
|
||||
if ((c->stmt_flags & Stmt_ContinueAllowed) == 0 && label == nullptr) {
|
||||
error(be->token, "'%.*s' only allowed in non-inline loops", LIT(name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (label != nullptr) {
|
||||
if (label->kind != Ast_Ident) {
|
||||
error(label, "A branch statement's label name must be an identifier");
|
||||
return Expr_Expr;
|
||||
}
|
||||
Ast *ident = label;
|
||||
String name = ident->Ident.token.string;
|
||||
Operand o = {};
|
||||
Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
|
||||
if (e == nullptr) {
|
||||
error(ident, "Undeclared label name: %.*s", LIT(name));
|
||||
return Expr_Expr;
|
||||
}
|
||||
add_entity_use(c, ident, e);
|
||||
if (e->kind != Entity_Label) {
|
||||
error(ident, "'%.*s' is not a label", LIT(name));
|
||||
return Expr_Expr;
|
||||
}
|
||||
Ast *parent = e->Label.parent;
|
||||
GB_ASSERT(parent != nullptr);
|
||||
switch (parent->kind) {
|
||||
case Ast_BlockStmt:
|
||||
case Ast_IfStmt:
|
||||
case Ast_SwitchStmt:
|
||||
if (be->token.kind != Token_or_break) {
|
||||
error(label, "Label '%.*s' can only be used with 'or_break'", LIT(e->token.string));
|
||||
}
|
||||
break;
|
||||
case Ast_RangeStmt:
|
||||
case Ast_ForStmt:
|
||||
if ((be->token.kind != Token_or_break) && (be->token.kind != Token_or_continue)) {
|
||||
error(label, "Label '%.*s' can only be used with 'or_break' and 'or_continue'", LIT(e->token.string));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
|
||||
gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<Ast *> const &elems, Operand *o, Type *type, bool &is_constant) {
|
||||
Type *bt = base_type(type);
|
||||
@@ -9497,14 +9593,14 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
|
||||
if (is_const) {
|
||||
if (is_type_array(t)) {
|
||||
// OKay
|
||||
// Okay
|
||||
} else if (is_type_slice(t)) {
|
||||
// Okay
|
||||
} else if (is_type_enumerated_array(t)) {
|
||||
// Okay
|
||||
} else if (is_type_string(t)) {
|
||||
// Okay
|
||||
} else if (is_type_relative_slice(t)) {
|
||||
} else if (is_type_relative_multi_pointer(t)) {
|
||||
// Okay
|
||||
} else if (is_type_matrix(t)) {
|
||||
// Okay
|
||||
@@ -9642,17 +9738,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_RelativeSlice:
|
||||
case Type_RelativeMultiPointer:
|
||||
valid = true;
|
||||
o->type = t->RelativeSlice.slice_type;
|
||||
if (o->mode != Addressing_Variable) {
|
||||
gbString str = expr_to_string(node);
|
||||
error(node, "Cannot relative slice '%s', as value is not addressable", str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
o->type = type_deref(o->type);
|
||||
break;
|
||||
|
||||
case Type_EnumeratedArray:
|
||||
@@ -9731,8 +9819,19 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
x[i:n] -> []T
|
||||
*/
|
||||
o->type = alloc_type_slice(t->MultiPointer.elem);
|
||||
} else if (t->kind == Type_RelativeMultiPointer && se->high != nullptr) {
|
||||
/*
|
||||
x[:] -> [^]T
|
||||
x[i:] -> [^]T
|
||||
x[:n] -> []T
|
||||
x[i:n] -> []T
|
||||
*/
|
||||
Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type);
|
||||
GB_ASSERT(pointer_type->kind == Type_MultiPointer);
|
||||
o->type = alloc_type_slice(pointer_type->MultiPointer.elem);
|
||||
}
|
||||
|
||||
|
||||
o->mode = Addressing_Value;
|
||||
|
||||
if (is_type_string(t) && max_count >= 0) {
|
||||
@@ -9939,6 +10038,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
return check_or_return_expr(c, o, node, type_hint);
|
||||
case_end;
|
||||
|
||||
case_ast_node(re, OrBranchExpr, node);
|
||||
return check_or_branch_expr(c, o, node, type_hint);
|
||||
case_end;
|
||||
|
||||
case_ast_node(cl, CompoundLit, node);
|
||||
kind = check_compound_literal(c, o, node, type_hint);
|
||||
case_end;
|
||||
@@ -10005,14 +10108,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
return kind;
|
||||
}
|
||||
if (type_hint) {
|
||||
Type *type = type_of_expr(ac->expr);
|
||||
check_cast(c, o, type_hint);
|
||||
if (is_type_typed(type) && are_types_identical(type, type_hint)) {
|
||||
if (check_vet_flags(node) & VetFlag_Extra) {
|
||||
error(node, "Redundant 'auto_cast' applied to expression");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
o->expr = node;
|
||||
return Expr_Expr;
|
||||
@@ -10505,6 +10601,16 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
|
||||
str = gb_string_appendc(str, " or_return");
|
||||
case_end;
|
||||
|
||||
case_ast_node(oe, OrBranchExpr, node);
|
||||
str = write_expr_to_string(str, oe->expr, shorthand);
|
||||
str = gb_string_append_rune(str, ' ');
|
||||
str = string_append_token(str, oe->token);
|
||||
if (oe->label) {
|
||||
str = gb_string_append_rune(str, ' ');
|
||||
str = write_expr_to_string(str, oe->label, shorthand);
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(pe, ParenExpr, node);
|
||||
str = gb_string_append_rune(str, '(');
|
||||
str = write_expr_to_string(str, pe->expr, shorthand);
|
||||
|
||||
+7
-2
@@ -102,8 +102,13 @@ gb_internal void check_stmt_list(CheckerContext *ctx, Slice<Ast *> const &stmts,
|
||||
new_flags |= Stmt_FallthroughAllowed;
|
||||
}
|
||||
|
||||
u32 prev_stmt_flags = ctx->stmt_flags;
|
||||
ctx->stmt_flags = new_flags;
|
||||
|
||||
check_stmt(ctx, n, new_flags);
|
||||
|
||||
ctx->stmt_flags = prev_stmt_flags;
|
||||
|
||||
if (i+1 < max_non_constant_declaration) {
|
||||
switch (n->kind) {
|
||||
case Ast_ReturnStmt:
|
||||
@@ -1893,7 +1898,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
}
|
||||
|
||||
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
|
||||
error(e->token, "@(thread_local) is not supported for this target platform");
|
||||
// error(e->token, "@(thread_local) is not supported for this target platform");
|
||||
}
|
||||
|
||||
|
||||
@@ -1983,7 +1988,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
for (auto const &entry : scope->elements) {
|
||||
Entity *f = entry.value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, e->identifier);
|
||||
uvar->flags |= (e->flags & EntityFlag_Value);
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user