mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-07 12:11:36 -07:00
Compare commits
562 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59025b75ba | |||
| 2289b7a33d | |||
| 79ec172797 | |||
| 2e6ad2a711 | |||
| 6be05f315d | |||
| b5aa50aaa4 | |||
| ab91fa6ad5 | |||
| 376327c87b | |||
| f8f91e52e0 | |||
| f4daf46ff4 | |||
| d10d54710c | |||
| 1ec997461d | |||
| ec5fc10988 | |||
| a232c0888c | |||
| cb5a6b531a | |||
| c930a3b4c8 | |||
| 4c14e92952 | |||
| 850d4a1e1b | |||
| dc012ed6dd | |||
| c21c993646 | |||
| c3a292a8c7 | |||
| 4044a577cc | |||
| 581d53b96b | |||
| 2bc89260f1 | |||
| c78b83f142 | |||
| e28525e28c | |||
| 73f9d12d47 | |||
| b21cf05d44 | |||
| 107bede9fd | |||
| 75cbb09744 | |||
| 76cf667a29 | |||
| 78ee97ec74 | |||
| bfcd7a35bf | |||
| 4484a3433d | |||
| 0c4f905d82 | |||
| 77de7ebde5 | |||
| 2ec3fa93b4 | |||
| 9f2d710c35 | |||
| 22b961ea53 | |||
| 9ea45d35db | |||
| 06e8476efc | |||
| 94dbac9a64 | |||
| 97a183f412 | |||
| b2f5b73532 | |||
| 1eac3482a6 | |||
| 6636376a81 | |||
| ed6bf28004 | |||
| 6bc0c611ab | |||
| ba1930eb01 | |||
| 203382461b | |||
| 4eb4ae6305 | |||
| 72ae061769 | |||
| 46161f7e19 | |||
| 0c55596f0f | |||
| 5f3bfa66c5 | |||
| 561b725b0e | |||
| 3a4630e6b4 | |||
| abf0fd7efc | |||
| a632db3618 | |||
| a3c81374be | |||
| 6a3ec5eb36 | |||
| 740ba6ad47 | |||
| df32b5b46c | |||
| 085fa199ea | |||
| 412c9a99d5 | |||
| 6e701ef36d | |||
| 24c48d22bc | |||
| 3cb8bb6672 | |||
| b1c2c0ea7a | |||
| 2c498c132e | |||
| 880d330cca | |||
| a2a503847a | |||
| 58f4d533b7 | |||
| d2ff6f424d | |||
| 92f985abd5 | |||
| 3ce17607c6 | |||
| 76277f83c1 | |||
| 2b7529977e | |||
| f4125d2d88 | |||
| 87e50e5e4d | |||
| 86a1c34c3a | |||
| 3f3cc342b4 | |||
| 3bf820cf99 | |||
| f2b4087d80 | |||
| 3b6d72bb94 | |||
| 9080fa4a9d | |||
| 5616ff9a40 | |||
| 73b81184fa | |||
| f8d3f86d8b | |||
| 2f9a410a45 | |||
| 8661457512 | |||
| 5d7b92d391 | |||
| 1d8bc3e917 | |||
| a2ad16b609 | |||
| a3b1ac3133 | |||
| e7b96cf286 | |||
| 01181517dc | |||
| f702c782f1 | |||
| 7203560b06 | |||
| 1baeb9406f | |||
| 17e36bd5e1 | |||
| b6b3377786 | |||
| 13cb894b30 | |||
| 3f935bea25 | |||
| 3e66eec735 | |||
| 277e0ac124 | |||
| 2ccfaa7d4e | |||
| 4bd5de34ea | |||
| 374e71e9b0 | |||
| 07bb93bb5d | |||
| b9efd09d17 | |||
| 507b718cb3 | |||
| 82f9cbecf8 | |||
| a8ac59a6e7 | |||
| 3d389ee028 | |||
| 10c5825715 | |||
| f89ebce807 | |||
| 64601ac439 | |||
| edce27812f | |||
| 193822b45d | |||
| 43640a8b59 | |||
| 0446d9721b | |||
| bae13b6387 | |||
| e48c0eee74 | |||
| 47e9857eb7 | |||
| 559fcfa291 | |||
| 84cee5d9d5 | |||
| 6d354524e2 | |||
| ae6441182d | |||
| a68f0b2d72 | |||
| fdbbf24271 | |||
| df233f72a9 | |||
| bff5a67f79 | |||
| 4f9df50dc1 | |||
| 34187424b8 | |||
| 50503cb405 | |||
| 5e04ddd653 | |||
| 4f5203e661 | |||
| d9ca4eb4d6 | |||
| 5534c031b3 | |||
| 19dc84e300 | |||
| a932168f50 | |||
| 1d147ba993 | |||
| 6ea9ba16e7 | |||
| 286549693e | |||
| 34727f99e3 | |||
| ffe6d81ecd | |||
| 8605833781 | |||
| 4474144c24 | |||
| ef3f448861 | |||
| a882260db6 | |||
| 633157f4f8 | |||
| 9fa69c3d3b | |||
| 743a461aa9 | |||
| fc0291d745 | |||
| 77eaf8e1e4 | |||
| a7adb2fb6e | |||
| 036900da51 | |||
| ed4c9335db | |||
| ca67cf032c | |||
| f907516cbd | |||
| c12c7d5370 | |||
| f7c8b40ea2 | |||
| 15f9795ab0 | |||
| 8982ae34e3 | |||
| e6d3e893a5 | |||
| 3da8fa9b27 | |||
| 32ba5e7ad2 | |||
| 52df80dccd | |||
| 7f845bb165 | |||
| 0e6de5673b | |||
| 7a7b87181d | |||
| c6dc517004 | |||
| d2bc41a2df | |||
| 7dbcaf792d | |||
| 2652c2d7a5 | |||
| a2250a5d49 | |||
| 7f8a9587e0 | |||
| 1306c53fb1 | |||
| 3bd1ac4c82 | |||
| dc8d28c383 | |||
| 7adaa4dc2b | |||
| 6d1a91f5b3 | |||
| 17eebf338c | |||
| c543ecd64c | |||
| 34a9f55f37 | |||
| 9aea990184 | |||
| d5b0632e4f | |||
| db169a4334 | |||
| f5cc8bd7bf | |||
| 005d52cab7 | |||
| d1477bcfa7 | |||
| 3092fb2ff3 | |||
| 5eebdebec8 | |||
| 8e4d6b3e5d | |||
| ea9c2fed57 | |||
| ba412fd87b | |||
| 0278ac85a0 | |||
| ff60b752bd | |||
| 9848e883c7 | |||
| 64705ddd1d | |||
| 2a41814985 | |||
| 26ffec845b | |||
| 52e60526ef | |||
| 76b10b5f5d | |||
| b94a7a87fa | |||
| 2b43387a9d | |||
| e76a5d8e12 | |||
| 6d7217f37a | |||
| 17dab04422 | |||
| 29e660b16f | |||
| 31959b0751 | |||
| 8f897de267 | |||
| 2855ff6df3 | |||
| deed20dea6 | |||
| a6c5143993 | |||
| 758d1e2a03 | |||
| ce057ff755 | |||
| ad719e7c3a | |||
| bff3426d25 | |||
| 4315033220 | |||
| 1cd89b2da3 | |||
| 7e8b9862b9 | |||
| 07062324d7 | |||
| 2e8f2e6dbc | |||
| 1abd95094d | |||
| 913d802e33 | |||
| bee475c38a | |||
| b4ca99ead9 | |||
| dfe2c0a600 | |||
| fad851d80c | |||
| 832961d539 | |||
| 499c657ffa | |||
| 8c6f39a68d | |||
| 09f5713cf8 | |||
| 26c0c6a525 | |||
| 6d9f84ba03 | |||
| 8af08f2153 | |||
| 2944969ca0 | |||
| bd1b54e0db | |||
| fcab5508be | |||
| 0b05650366 | |||
| 96e36c7c39 | |||
| 16c6dbcbe5 | |||
| 92a78c83d9 | |||
| 6b2302fa8b | |||
| ee28945e09 | |||
| 3dcea60f5b | |||
| f126e05034 | |||
| 68b74eb7c7 | |||
| 3b4199a669 | |||
| 562901aedf | |||
| 793117ed63 | |||
| 5b783d6376 | |||
| d3f3528d1d | |||
| 3145935d6b | |||
| 25430333ba | |||
| 2ca2b32dd0 | |||
| a5dde78f08 | |||
| fd415f0b45 | |||
| 507722954c | |||
| 524d23d45d | |||
| e9ee6f5291 | |||
| 7e5342f41f | |||
| 18607e53cb | |||
| ed933b3f21 | |||
| 49fecbdc5e | |||
| f971126183 | |||
| d4ccb69ccc | |||
| 37b4e0de6c | |||
| 737f440c7f | |||
| cba3f1e374 | |||
| a70dde34da | |||
| 410b85b5c7 | |||
| 0ae012ba08 | |||
| fc4eb4152c | |||
| 4f3b5d8dcb | |||
| f76f70c7cf | |||
| 15d783e920 | |||
| 09e4fff5b1 | |||
| 2d89faa17c | |||
| dd9843aa21 | |||
| 882116e358 | |||
| f3adbae1ed | |||
| 278e239973 | |||
| fda803b46a | |||
| 01162e08b5 | |||
| a7ae197a55 | |||
| 3c72cb67d3 | |||
| 37bba4c0a6 | |||
| ab9d1f99fd | |||
| 45124e4d5c | |||
| 7681c43b14 | |||
| 7e43cd7d97 | |||
| c223fc1766 | |||
| 04297bb680 | |||
| 553292ffd0 | |||
| 57862846a2 | |||
| 8e270d3a99 | |||
| ae5cb09041 | |||
| 093b2288c3 | |||
| ffe17a471d | |||
| e9f901b82d | |||
| ed3004f8a0 | |||
| d97df080f9 | |||
| 0e5c7e08fc | |||
| 83523badb7 | |||
| 0a90994403 | |||
| 376906e0ae | |||
| 47c79a2f25 | |||
| 32988b0363 | |||
| 00c138ce9f | |||
| 5676c9e7eb | |||
| 3a469dc13e | |||
| d3c70f2206 | |||
| 14f1793b3e | |||
| 8cecb6b9f5 | |||
| 4a66c3c420 | |||
| c3c88633a5 | |||
| aeaf1199ec | |||
| d4f62f52db | |||
| 384fb76a1b | |||
| 4a04a32e0a | |||
| 196bd735d4 | |||
| 493bc653b5 | |||
| 3d209798c9 | |||
| dd0d61e97c | |||
| 4b9324ff76 | |||
| e81ed9a960 | |||
| 83f7a887b7 | |||
| ad2f1ac24e | |||
| 62d232d798 | |||
| 8906a0120c | |||
| cad753e398 | |||
| fd627dc13b | |||
| 70e8d97ee1 | |||
| cdecb0ccc3 | |||
| 460b5149af | |||
| b6dc253d8b | |||
| e7be9493ba | |||
| ea34f321ed | |||
| 2b5bc1d558 | |||
| e6a7b85da4 | |||
| 6145185478 | |||
| 2abba6e057 | |||
| db5a1b0c78 | |||
| 14cb19c2df | |||
| 46bcd18946 | |||
| 3e5c60f746 | |||
| 0fa487f468 | |||
| 1bec9e5331 | |||
| ba61d911da | |||
| 3b69c6b204 | |||
| d7eabf571c | |||
| ddf9c4a65b | |||
| b3d797598e | |||
| 31c7945444 | |||
| 276e014d18 | |||
| 27f206784c | |||
| 54a6637d38 | |||
| 23be56af59 | |||
| 71df46456a | |||
| cd89d8a3c4 | |||
| 4c62a32b04 | |||
| 5f8137025d | |||
| 1843d52217 | |||
| 454c92dc64 | |||
| 7e33a86d54 | |||
| 197b832992 | |||
| 8f13724a4b | |||
| 746d5fc322 | |||
| ffc45e8cc2 | |||
| bea2f36443 | |||
| f138f71fa6 | |||
| 89b7a3f7ac | |||
| 75e15b05b0 | |||
| 78eb388110 | |||
| df23cf47c6 | |||
| 002ac6a1b7 | |||
| 40e4536887 | |||
| 536bf61323 | |||
| c76bdced55 | |||
| 459ea5f4f6 | |||
| 8e8a075a22 | |||
| db6bd9b358 | |||
| 42ad54c28e | |||
| 1857bc7b02 | |||
| e011d812ca | |||
| 0738822dda | |||
| 2213722776 | |||
| 65dedbb1ca | |||
| 0e69993d39 | |||
| 135091ddbe | |||
| d64e3b672c | |||
| a3bcacee27 | |||
| 855e7beab1 | |||
| edc13c29df | |||
| 21864d8d51 | |||
| d45ff0694d | |||
| d695a8a526 | |||
| 0380a288a9 | |||
| 1d4d0a3e1a | |||
| 9e98494fff | |||
| 86d334282c | |||
| 9cf937fef0 | |||
| f5697dd7f2 | |||
| a23ee1edc1 | |||
| 9dcb5c075a | |||
| 803648be89 | |||
| 3ab5db8297 | |||
| 3380ece4a1 | |||
| 0e5928ff39 | |||
| e6e04fc6c8 | |||
| 753cceea82 | |||
| 32c7e81745 | |||
| 03aec70287 | |||
| e69738c079 | |||
| 1afa7967f2 | |||
| 643e36b87b | |||
| 3d2405ac2c | |||
| 7392a3047a | |||
| 60f4d8f1ec | |||
| 7b42cbea20 | |||
| 4cc597f4df | |||
| 934e66ab3b | |||
| b755609438 | |||
| 83d63e572a | |||
| 5212f62f54 | |||
| 4d0fd4cf19 | |||
| e47953f7ca | |||
| 47f3773146 | |||
| 31c6ecad34 | |||
| af6e53c05c | |||
| 153140eb8f | |||
| 6fef44c041 | |||
| a88d149903 | |||
| f9fc488399 | |||
| bef806bef4 | |||
| 95e9bbf99f | |||
| 5936fa8871 | |||
| 02646b789c | |||
| 09e9dca869 | |||
| 9a43c0672e | |||
| 83a6169463 | |||
| debe2de5fe | |||
| ff7d591ebf | |||
| 7386ca9272 | |||
| fd8b2e0b88 | |||
| c34ae884ad | |||
| 2e7157ae9c | |||
| 441365b388 | |||
| f561147190 | |||
| 2958c1d6aa | |||
| 9dc83bc1b3 | |||
| 88b1b2c629 | |||
| 23bc643a81 | |||
| 41854bacf5 | |||
| cf528431f5 | |||
| e59064dd59 | |||
| 8966294823 | |||
| b8479ea79d | |||
| e2aa8f426d | |||
| 39a0f8c96a | |||
| b647b45ba5 | |||
| 5fe9aa919b | |||
| ff5d6a994b | |||
| ae3b95b194 | |||
| acaae1357c | |||
| f8afda3b22 | |||
| 31f544c258 | |||
| 1c57d1c019 | |||
| 251edf7bc7 | |||
| f77cd5533d | |||
| 416413bebf | |||
| c3809d7b84 | |||
| 42a1c58a80 | |||
| b6abaf739c | |||
| ef98e92e8d | |||
| 768c2684d0 | |||
| 5f2514db63 | |||
| b95ade40c0 | |||
| 340838c878 | |||
| c5d348515d | |||
| 05dd3d490d | |||
| 0cc40db565 | |||
| 546faab0cb | |||
| 83e9a6b417 | |||
| 30bb2382aa | |||
| 61a0b4ec5a | |||
| accb35506f | |||
| 817bc7434d | |||
| 3c2ed3bb69 | |||
| 9cbf46e689 | |||
| ad6ea3d6aa | |||
| cda9fd5271 | |||
| 0c16f27814 | |||
| 19aec13a10 | |||
| e896956275 | |||
| c59c6e98a5 | |||
| 8b1100bf2b | |||
| a3d99765cc | |||
| a724573bb3 | |||
| 25769f139a | |||
| 3edf638cc6 | |||
| de7e612186 | |||
| a571153458 | |||
| ada58c66fa | |||
| 697f8c7ee6 | |||
| b6ebfe4b2c | |||
| bccbdefde9 | |||
| 445ca70521 | |||
| c6ab8f82c8 | |||
| 67ce0ec29f | |||
| 23c3573c30 | |||
| a4308e7246 | |||
| 3439139b1c | |||
| cf246f65ff | |||
| dd84b61cc8 | |||
| b8c4bf2afb | |||
| e870041fe6 | |||
| 6418ec3b21 | |||
| 2bcc7b0064 | |||
| 97be867103 | |||
| fb710f8cbf | |||
| 1553137c23 | |||
| d5384c5aa4 | |||
| 3a81f2ab89 | |||
| b54fc96b1e | |||
| 48af78e469 | |||
| abb26e0bea | |||
| 76edfae0e0 | |||
| a5298e17ec | |||
| cf9f3d5e2d | |||
| 35c90fe124 | |||
| df8bdac33f | |||
| b4f7a527c2 | |||
| 35533a7baa | |||
| 2c9ed7464f | |||
| e190c024fd | |||
| e250475bf9 | |||
| 5db603ded2 | |||
| 78815778ee | |||
| ff5e036773 | |||
| 4dc29d141f | |||
| 8ecee32e1c | |||
| 6a7d821fcc | |||
| 1243b1a58c | |||
| ab3bae5c02 | |||
| 540c5400a0 | |||
| 01e29bf27e | |||
| 6223f48c3f | |||
| f2f20def37 | |||
| 77b91352ae | |||
| 3d7d347192 | |||
| e5868e3205 | |||
| 96d7c4ffdf | |||
| f19325cbe0 | |||
| d57ec4a11d | |||
| ebdb3ab43a | |||
| 29ca6ee420 | |||
| a4ba91a554 | |||
| cf390bf8b9 |
@@ -1,3 +1,4 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: odin-lang
|
||||||
patreon: gingerbill
|
patreon: gingerbill
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: Download LLVM, botan
|
- name: Download LLVM, botan
|
||||||
run: sudo apt-get install llvm-11 clang-11 llvm libbotan-2-dev botan
|
run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan
|
||||||
- name: build odin
|
- name: build odin
|
||||||
run: make release
|
run: ./build_odin.sh release
|
||||||
- name: Odin version
|
- name: Odin version
|
||||||
run: ./odin version
|
run: ./odin version
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
@@ -38,6 +38,18 @@ jobs:
|
|||||||
cd tests/vendor
|
cd tests/vendor
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin issues tests
|
||||||
|
run: tests/issues/run.sh
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Linux i386
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for FreeBSD amd64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for OpenBSD amd64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
|
||||||
|
timeout-minutes: 10
|
||||||
build_macOS:
|
build_macOS:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -49,7 +61,7 @@ jobs:
|
|||||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||||
- name: build odin
|
- name: build odin
|
||||||
run: make release
|
run: ./build_odin.sh release
|
||||||
- name: Odin version
|
- name: Odin version
|
||||||
run: ./odin version
|
run: ./odin version
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
@@ -78,8 +90,17 @@ jobs:
|
|||||||
cd tests/vendor
|
cd tests/vendor
|
||||||
make
|
make
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin issues tests
|
||||||
|
run: tests/issues/run.sh
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Darwin arm64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Linux arm64
|
||||||
|
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||||
|
timeout-minutes: 10
|
||||||
build_windows:
|
build_windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: build Odin
|
- name: build Odin
|
||||||
@@ -138,3 +159,15 @@ jobs:
|
|||||||
cd tests\core\math\big
|
cd tests\core\math\big
|
||||||
call build.bat
|
call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
- name: Odin issues tests
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
|
call tests\issues\run.bat
|
||||||
|
timeout-minutes: 10
|
||||||
|
- name: Odin check examples/all for Windows 32bits
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
|
odin check examples/all -strict-style -target:windows_i386
|
||||||
|
timeout-minutes: 10
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_windows:
|
build_windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: build Odin
|
- name: build Odin
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: (Linux) Download LLVM
|
- name: (Linux) Download LLVM
|
||||||
run: sudo apt-get install llvm-11 clang-11 llvm
|
run: sudo apt-get install llvm-11 clang-11
|
||||||
- name: build odin
|
- name: build odin
|
||||||
run: make nightly
|
run: make nightly
|
||||||
- name: Odin run
|
- name: Odin run
|
||||||
@@ -129,7 +129,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo Authorizing B2 account
|
echo Authorizing B2 account
|
||||||
b2 authorize-account "$APPID" "$APPKEY"
|
b2 authorize-account "$APPID" "$APPKEY"
|
||||||
|
|
||||||
echo Uploading artifcates to B2
|
echo Uploading artifcates to B2
|
||||||
chmod +x ./ci/upload_create_nightly.sh
|
chmod +x ./ci/upload_create_nightly.sh
|
||||||
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
|
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
|
||||||
@@ -141,7 +141,7 @@ jobs:
|
|||||||
|
|
||||||
echo Creating nightly.json
|
echo Creating nightly.json
|
||||||
python3 ci/create_nightly_json.py "$BUCKET" > nightly.json
|
python3 ci/create_nightly_json.py "$BUCKET" > nightly.json
|
||||||
|
|
||||||
echo Uploading nightly.json
|
echo Uploading nightly.json
|
||||||
b2 upload-file "$BUCKET" nightly.json nightly.json
|
b2 upload-file "$BUCKET" nightly.json nightly.json
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
|
# For macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
@@ -276,3 +279,5 @@ shared/
|
|||||||
*.ll
|
*.ll
|
||||||
|
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
examples/bug/
|
||||||
|
build.sh
|
||||||
|
|||||||
@@ -1,64 +1,3 @@
|
|||||||
GIT_SHA=$(shell git rev-parse --short HEAD)
|
|
||||||
DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value
|
|
||||||
LDFLAGS=-pthread -ldl -lm -lstdc++
|
|
||||||
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
|
|
||||||
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
|
|
||||||
CC=clang
|
|
||||||
|
|
||||||
OS=$(shell uname)
|
|
||||||
|
|
||||||
ifeq ($(OS), Darwin)
|
|
||||||
|
|
||||||
ARCH=$(shell uname -m)
|
|
||||||
LLVM_CONFIG=
|
|
||||||
|
|
||||||
# allow for arm only llvm's with version 13
|
|
||||||
ifeq ($(ARCH), arm64)
|
|
||||||
LLVM_VERSIONS = "13.%.%"
|
|
||||||
else
|
|
||||||
# allow for x86 / amd64 all llvm versions begining from 11
|
|
||||||
LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0"
|
|
||||||
endif
|
|
||||||
|
|
||||||
LLVM_VERSION_PATTERN_SEPERATOR = )|(
|
|
||||||
LLVM_VERSION_PATTERNS_ESCAPED_DOT = $(subst .,\.,$(LLVM_VERSIONS))
|
|
||||||
LLVM_VERSION_PATTERNS_REPLACE_PERCENT = $(subst %,.*,$(LLVM_VERSION_PATTERNS_ESCAPED_DOT))
|
|
||||||
LLVM_VERSION_PATTERN_REMOVE_ELEMENTS = $(subst " ",$(LLVM_VERSION_PATTERN_SEPERATOR),$(LLVM_VERSION_PATTERNS_REPLACE_PERCENT))
|
|
||||||
LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS))
|
|
||||||
LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))"
|
|
||||||
|
|
||||||
ifneq ($(shell llvm-config --version | grep -E $(LLVM_VERSION_PATTERN)),)
|
|
||||||
LLVM_CONFIG=llvm-config
|
|
||||||
else
|
|
||||||
ifeq ($(ARCH), arm64)
|
|
||||||
$(error "Requirement: llvm-config must be base version 13 for arm64")
|
|
||||||
else
|
|
||||||
$(error "Requirement: llvm-config must be base version greater than 11 for amd64/x86")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
LDFLAGS:=$(LDFLAGS) -liconv
|
|
||||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
|
||||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
|
||||||
endif
|
|
||||||
ifeq ($(OS), Linux)
|
|
||||||
LLVM_CONFIG=llvm-config-11
|
|
||||||
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
|
||||||
LLVM_CONFIG=llvm-config-11
|
|
||||||
else ifneq ($(shell which llvm-config-11-64 2>/dev/null),)
|
|
||||||
LLVM_CONFIG=llvm-config-11-64
|
|
||||||
else
|
|
||||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
|
||||||
LLVM_CONFIG=llvm-config
|
|
||||||
else
|
|
||||||
$(error "Requirement: llvm-config must be version 11")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
|
||||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: debug demo
|
all: debug demo
|
||||||
|
|
||||||
demo:
|
demo:
|
||||||
@@ -68,13 +7,13 @@ report:
|
|||||||
./odin report
|
./odin report
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
./build_odin.sh debug
|
||||||
|
|
||||||
release:
|
release:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 $(LDFLAGS) -o odin
|
./build_odin.sh release
|
||||||
|
|
||||||
release_native:
|
release_native:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
|
./build_odin.sh release-native
|
||||||
|
|
||||||
nightly:
|
nightly:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
./build_odin.sh nightly
|
||||||
|
|||||||
Executable
+150
@@ -0,0 +1,150 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
GIT_SHA=$(git rev-parse --short HEAD)
|
||||||
|
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
|
||||||
|
LDFLAGS="-pthread -lm -lstdc++"
|
||||||
|
CFLAGS="-std=c++14 -DGIT_SHA=\"$GIT_SHA\""
|
||||||
|
CFLAGS="$CFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
|
||||||
|
CC=clang
|
||||||
|
OS=$(uname)
|
||||||
|
|
||||||
|
panic() {
|
||||||
|
printf "%s\n" "$1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
|
||||||
|
|
||||||
|
config_darwin() {
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
LLVM_CONFIG=llvm-config
|
||||||
|
|
||||||
|
# allow for arm only llvm's with version 13
|
||||||
|
if [ ARCH == arm64 ]; then
|
||||||
|
MIN_LLVM_VERSION=("13.0.0")
|
||||||
|
else
|
||||||
|
# allow for x86 / amd64 all llvm versions begining from 11
|
||||||
|
MIN_LLVM_VERSION=("11.1.0")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||||
|
if [ ARCH == arm64 ]; then
|
||||||
|
panic "Requirement: llvm-config must be base version 13 for arm64"
|
||||||
|
else
|
||||||
|
panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||||
|
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||||
|
}
|
||||||
|
|
||||||
|
config_freebsd() {
|
||||||
|
LLVM_CONFIG=/usr/local/bin/llvm-config11
|
||||||
|
|
||||||
|
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||||
|
}
|
||||||
|
|
||||||
|
config_openbsd() {
|
||||||
|
LLVM_CONFIG=/usr/local/bin/llvm-config
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS -liconv"
|
||||||
|
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||||
|
}
|
||||||
|
|
||||||
|
config_linux() {
|
||||||
|
if which llvm-config > /dev/null 2>&1; then
|
||||||
|
LLVM_CONFIG=llvm-config
|
||||||
|
elif which llvm-config-11 > /dev/null 2>&1; then
|
||||||
|
LLVM_CONFIG=llvm-config-11
|
||||||
|
elif which llvm-config-11-64 > /dev/null 2>&1; then
|
||||||
|
LLVM_CONFIG=llvm-config-11-64
|
||||||
|
else
|
||||||
|
panic "Unable to find LLVM-config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
MIN_LLVM_VERSION=("11.0.0")
|
||||||
|
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||||
|
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
|
||||||
|
panic "Requirement: llvm-config must be base version greater than 11"
|
||||||
|
fi
|
||||||
|
|
||||||
|
LDFLAGS="$LDFLAGS -ldl"
|
||||||
|
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
|
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_odin() {
|
||||||
|
case $1 in
|
||||||
|
debug)
|
||||||
|
EXTRAFLAGS="-g"
|
||||||
|
;;
|
||||||
|
release)
|
||||||
|
EXTRAFLAGS="-O3"
|
||||||
|
;;
|
||||||
|
release-native)
|
||||||
|
EXTRAFLAGS="-O3 -march=native"
|
||||||
|
;;
|
||||||
|
nightly)
|
||||||
|
EXTRAFLAGS="-DNIGHTLY -O3"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
panic "Build mode unsupported!"
|
||||||
|
esac
|
||||||
|
|
||||||
|
set -x
|
||||||
|
$CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||||
|
set +x
|
||||||
|
}
|
||||||
|
|
||||||
|
run_demo() {
|
||||||
|
./odin run examples/demo/demo.odin
|
||||||
|
}
|
||||||
|
|
||||||
|
case $OS in
|
||||||
|
Linux)
|
||||||
|
config_linux
|
||||||
|
;;
|
||||||
|
Darwin)
|
||||||
|
config_darwin
|
||||||
|
;;
|
||||||
|
OpenBSD)
|
||||||
|
config_openbsd
|
||||||
|
;;
|
||||||
|
FreeBSD)
|
||||||
|
config_freebsd
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
panic "Platform unsupported!"
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
build_odin debug
|
||||||
|
run_demo
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $# -eq 1 ]]; then
|
||||||
|
case $1 in
|
||||||
|
report)
|
||||||
|
if [[ ! -f "./odin" ]]; then
|
||||||
|
build_odin debug
|
||||||
|
fi
|
||||||
|
|
||||||
|
./odin report
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
build_odin $1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
run_demo
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
panic "Too many arguments!"
|
||||||
|
fi
|
||||||
@@ -8,6 +8,7 @@ import "core:intrinsics"
|
|||||||
|
|
||||||
// Extra errors returns by scanning procedures
|
// Extra errors returns by scanning procedures
|
||||||
Scanner_Extra_Error :: enum i32 {
|
Scanner_Extra_Error :: enum i32 {
|
||||||
|
None,
|
||||||
Negative_Advance,
|
Negative_Advance,
|
||||||
Advanced_Too_Far,
|
Advanced_Too_Far,
|
||||||
Bad_Read_Count,
|
Bad_Read_Count,
|
||||||
@@ -15,7 +16,7 @@ Scanner_Extra_Error :: enum i32 {
|
|||||||
Too_Short,
|
Too_Short,
|
||||||
}
|
}
|
||||||
|
|
||||||
Scanner_Error :: union {
|
Scanner_Error :: union #shared_nil {
|
||||||
io.Error,
|
io.Error,
|
||||||
Scanner_Extra_Error,
|
Scanner_Extra_Error,
|
||||||
}
|
}
|
||||||
@@ -68,7 +69,7 @@ scanner_destroy :: proc(s: ^Scanner) {
|
|||||||
// Returns the first non-EOF error that was encounted by the scanner
|
// Returns the first non-EOF error that was encounted by the scanner
|
||||||
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
|
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
|
||||||
switch s._err {
|
switch s._err {
|
||||||
case .EOF, .None:
|
case .EOF, nil:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return s._err
|
return s._err
|
||||||
@@ -93,10 +94,6 @@ scanner_text :: proc(s: ^Scanner) -> string {
|
|||||||
// scanner_scan advances the scanner
|
// scanner_scan advances the scanner
|
||||||
scanner_scan :: proc(s: ^Scanner) -> bool {
|
scanner_scan :: proc(s: ^Scanner) -> bool {
|
||||||
set_err :: proc(s: ^Scanner, err: Scanner_Error) {
|
set_err :: proc(s: ^Scanner, err: Scanner_Error) {
|
||||||
err := err
|
|
||||||
if err == .None {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
switch s._err {
|
switch s._err {
|
||||||
case nil, .EOF:
|
case nil, .EOF:
|
||||||
s._err = err
|
s._err = err
|
||||||
|
|||||||
+11
-35
@@ -218,61 +218,37 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) ->
|
|||||||
|
|
||||||
|
|
||||||
@private
|
@private
|
||||||
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) {
|
_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save: int) -> (res: []byte, ok: bool) {
|
||||||
s, n := s, n
|
if len(sep) == 0 {
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if sep == nil {
|
|
||||||
res = s[:]
|
res = s[:]
|
||||||
ok = true
|
ok = true
|
||||||
s^ = s[len(s):]
|
s^ = s[len(s):]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < 0 {
|
m := index(s^, sep)
|
||||||
n = count(s^, sep) + 1
|
if m < 0 {
|
||||||
}
|
// not found
|
||||||
|
res = s[:]
|
||||||
n -= 1
|
ok = len(res) != 0
|
||||||
|
s^ = s[len(s):]
|
||||||
i := 0
|
} else {
|
||||||
for ; i < n; i += 1 {
|
|
||||||
m := index(s^, sep)
|
|
||||||
if m < 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
res = s[:m+sep_save]
|
res = s[:m+sep_save]
|
||||||
ok = true
|
ok = true
|
||||||
s^ = s[m+len(sep):]
|
s^ = s[m+len(sep):]
|
||||||
return
|
|
||||||
}
|
}
|
||||||
res = s[:]
|
|
||||||
ok = res != nil
|
|
||||||
s^ = s[len(s):]
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||||
return _split_iterator(s, sep, 0, -1)
|
return _split_iterator(s, sep, 0)
|
||||||
}
|
|
||||||
|
|
||||||
split_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
|
||||||
return _split_iterator(s, sep, 0, n)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
|
||||||
return _split_iterator(s, sep, len(sep), -1)
|
return _split_iterator(s, sep, len(sep))
|
||||||
}
|
}
|
||||||
|
|
||||||
split_after_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
|
|
||||||
return _split_iterator(s, sep, len(sep), n)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
index_byte :: proc(s: []byte, c: byte) -> int {
|
index_byte :: proc(s: []byte, c: byte) -> int {
|
||||||
for i := 0; i < len(s); i += 1 {
|
for i := 0; i < len(s); i += 1 {
|
||||||
|
|||||||
+4
-4
@@ -7,20 +7,20 @@ char :: builtin.u8 // assuming -funsigned-char
|
|||||||
schar :: builtin.i8
|
schar :: builtin.i8
|
||||||
short :: builtin.i16
|
short :: builtin.i16
|
||||||
int :: builtin.i32
|
int :: builtin.i32
|
||||||
long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64
|
long :: builtin.i32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||||
longlong :: builtin.i64
|
longlong :: builtin.i64
|
||||||
|
|
||||||
uchar :: builtin.u8
|
uchar :: builtin.u8
|
||||||
ushort :: builtin.u16
|
ushort :: builtin.u16
|
||||||
uint :: builtin.u32
|
uint :: builtin.u32
|
||||||
ulong :: builtin.u32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.u64
|
ulong :: builtin.u32 when (ODIN_OS == .Windows || size_of(builtin.rawptr) == 4) else builtin.u64
|
||||||
ulonglong :: builtin.u64
|
ulonglong :: builtin.u64
|
||||||
|
|
||||||
bool :: builtin.bool
|
bool :: builtin.bool
|
||||||
|
|
||||||
size_t :: builtin.uint
|
size_t :: builtin.uint
|
||||||
ssize_t :: builtin.int
|
ssize_t :: builtin.int
|
||||||
wchar_t :: builtin.u16 when (ODIN_OS == "windows") else builtin.u32
|
wchar_t :: builtin.u16 when (ODIN_OS == .Windows) else builtin.u32
|
||||||
|
|
||||||
float :: builtin.f32
|
float :: builtin.f32
|
||||||
double :: builtin.f64
|
double :: builtin.f64
|
||||||
@@ -48,7 +48,7 @@ int_least64_t :: builtin.i64
|
|||||||
uint_least64_t :: builtin.u64
|
uint_least64_t :: builtin.u64
|
||||||
|
|
||||||
// Same on Windows, Linux, and FreeBSD
|
// Same on Windows, Linux, and FreeBSD
|
||||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||||
int_fast8_t :: builtin.i8
|
int_fast8_t :: builtin.i8
|
||||||
uint_fast8_t :: builtin.u8
|
uint_fast8_t :: builtin.u8
|
||||||
int_fast16_t :: builtin.i32
|
int_fast16_t :: builtin.i32
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.3 Complex arithmetic
|
// 7.3 Complex arithmetic
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package libc
|
package libc
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
+18
-5
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.5 Errors
|
// 7.5 Errors
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -14,7 +14,7 @@ when ODIN_OS == "windows" {
|
|||||||
// EDOM,
|
// EDOM,
|
||||||
// EILSEQ
|
// EILSEQ
|
||||||
// ERANGE
|
// ERANGE
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@@ -27,7 +27,20 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
|||||||
ERANGE :: 34
|
ERANGE :: 34
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .OpenBSD {
|
||||||
|
@(private="file")
|
||||||
|
@(default_calling_convention="c")
|
||||||
|
foreign libc {
|
||||||
|
@(link_name="__errno")
|
||||||
|
_get_errno :: proc() -> ^int ---
|
||||||
|
}
|
||||||
|
|
||||||
|
EDOM :: 33
|
||||||
|
EILSEQ :: 84
|
||||||
|
ERANGE :: 34
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .Windows {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@@ -40,7 +53,7 @@ when ODIN_OS == "windows" {
|
|||||||
ERANGE :: 34
|
ERANGE :: 34
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ package libc
|
|||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package libc
|
|||||||
|
|
||||||
// 7.13 Nonlocal jumps
|
// 7.13 Nonlocal jumps
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
}
|
}
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.13.1 Save calling environment
|
// 7.13.1 Save calling environment
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.14 Signal handling
|
// 7.14 Signal handling
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -21,7 +21,7 @@ foreign libc {
|
|||||||
raise :: proc(sig: int) -> int ---
|
raise :: proc(sig: int) -> int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
@@ -34,7 +34,7 @@ when ODIN_OS == "windows" {
|
|||||||
SIGTERM :: 15
|
SIGTERM :: 15
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
@@ -47,7 +47,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" {
|
|||||||
SIGTERM :: 15
|
SIGTERM :: 15
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
|
|||||||
+111
-146
@@ -47,29 +47,30 @@ kill_dependency :: #force_inline proc(value: $T) -> T {
|
|||||||
|
|
||||||
// 7.17.4 Fences
|
// 7.17.4 Fences
|
||||||
atomic_thread_fence :: #force_inline proc(order: memory_order) {
|
atomic_thread_fence :: #force_inline proc(order: memory_order) {
|
||||||
switch (order) {
|
assert(order != .relaxed)
|
||||||
case .relaxed:
|
assert(order != .consume)
|
||||||
return
|
#partial switch order {
|
||||||
case .consume:
|
case .acquire: intrinsics.atomic_thread_fence(.Acquire)
|
||||||
intrinsics.atomic_fence_acq()
|
case .release: intrinsics.atomic_thread_fence(.Release)
|
||||||
case .acquire:
|
case .acq_rel: intrinsics.atomic_thread_fence(.Acq_Rel)
|
||||||
intrinsics.atomic_fence_acq()
|
case .seq_cst: intrinsics.atomic_thread_fence(.Seq_Cst)
|
||||||
case .release:
|
|
||||||
intrinsics.atomic_fence_rel()
|
|
||||||
case .acq_rel:
|
|
||||||
intrinsics.atomic_fence_acqrel()
|
|
||||||
case .seq_cst:
|
|
||||||
intrinsics.atomic_fence_acqrel()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_signal_fence :: #force_inline proc(order: memory_order) {
|
atomic_signal_fence :: #force_inline proc(order: memory_order) {
|
||||||
atomic_thread_fence(order)
|
assert(order != .relaxed)
|
||||||
|
assert(order != .consume)
|
||||||
|
#partial switch order {
|
||||||
|
case .acquire: intrinsics.atomic_signal_fence(.Acquire)
|
||||||
|
case .release: intrinsics.atomic_signal_fence(.Release)
|
||||||
|
case .acq_rel: intrinsics.atomic_signal_fence(.Acq_Rel)
|
||||||
|
case .seq_cst: intrinsics.atomic_signal_fence(.Seq_Cst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.17.5 Lock-free property
|
// 7.17.5 Lock-free property
|
||||||
atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
|
atomic_is_lock_free :: #force_inline proc(obj: ^$T) -> bool {
|
||||||
return size_of(T) <= 8 && (intrinsics.type_is_integer(T) || intrinsics.type_is_pointer(T))
|
return intrinsics.atomic_type_is_lock_free(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.17.6 Atomic integer types
|
// 7.17.6 Atomic integer types
|
||||||
@@ -121,13 +122,10 @@ atomic_store_explicit :: #force_inline proc(object: ^$T, desired: T, order: memo
|
|||||||
assert(order != .acquire)
|
assert(order != .acquire)
|
||||||
assert(order != .acq_rel)
|
assert(order != .acq_rel)
|
||||||
|
|
||||||
#partial switch (order) {
|
#partial switch order {
|
||||||
case .relaxed:
|
case .relaxed: intrinsics.atomic_store_explicit(object, desired, .Relaxed)
|
||||||
intrinsics.atomic_store_relaxed(object, desired)
|
case .release: intrinsics.atomic_store_explicit(object, desired, .Release)
|
||||||
case .release:
|
case .seq_cst: intrinsics.atomic_store_explicit(object, desired, .Seq_Cst)
|
||||||
intrinsics.atomic_store_rel(object, desired)
|
|
||||||
case .seq_cst:
|
|
||||||
intrinsics.atomic_store(object, desired)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,36 +137,26 @@ atomic_load_explicit :: #force_inline proc(object: ^$T, order: memory_order) {
|
|||||||
assert(order != .release)
|
assert(order != .release)
|
||||||
assert(order != .acq_rel)
|
assert(order != .acq_rel)
|
||||||
|
|
||||||
#partial switch (order) {
|
#partial switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_load_explicit(object, .Relaxed)
|
||||||
return intrinsics.atomic_load_relaxed(object)
|
case .consume: return intrinsics.atomic_load_explicit(object, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_load_explicit(object, .Acquire)
|
||||||
return intrinsics.atomic_load_acq(object)
|
case .seq_cst: return intrinsics.atomic_load_explicit(object, .Seq_Cst)
|
||||||
case .acquire:
|
|
||||||
return intrinsics.atomic_load_acq(object)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_load(object)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
|
atomic_exchange :: #force_inline proc(object: ^$T, desired: T) -> T {
|
||||||
return intrinsics.atomic_xchg(object, desired)
|
return intrinsics.atomic_exchange(object, desired)
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
|
atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_exchange_explicit(object, desired, .Relaxed)
|
||||||
return intrinsics.atomic_xchg_relaxed(object, desired)
|
case .consume: return intrinsics.atomic_exchange_explicit(object, desired, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_exchange_explicit(object, desired, .Acquire)
|
||||||
return intrinsics.atomic_xchg_acq(object, desired)
|
case .release: return intrinsics.atomic_exchange_explicit(object, desired, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_exchange_explicit(object, desired, .Acq_Rel)
|
||||||
return intrinsics.atomic_xchg_acq(object, desired)
|
case .seq_cst: return intrinsics.atomic_exchange_explicit(object, desired, .Seq_Cst)
|
||||||
case .release:
|
|
||||||
return intrinsics.atomic_xchg_rel(object, desired)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_xchg_acqrel(object, desired)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_xchg(object, desired)
|
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -189,102 +177,104 @@ atomic_exchange_explicit :: #force_inline proc(object: ^$T, desired: T, order: m
|
|||||||
// [success = seq_cst, failure = acquire] => failacq
|
// [success = seq_cst, failure = acquire] => failacq
|
||||||
// [success = acquire, failure = relaxed] => acq_failrelaxed
|
// [success = acquire, failure = relaxed] => acq_failrelaxed
|
||||||
// [success = acq_rel, failure = relaxed] => acqrel_failrelaxed
|
// [success = acq_rel, failure = relaxed] => acqrel_failrelaxed
|
||||||
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) {
|
atomic_compare_exchange_strong :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
|
||||||
value, ok := intrinsics.atomic_cxchg(object, expected^, desired)
|
value, ok := intrinsics.atomic_compare_exchange_strong(object, expected^, desired)
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) {
|
atomic_compare_exchange_strong_explicit :: #force_inline proc(object, expected: ^$T, desired: T, success, failure: memory_order) -> bool {
|
||||||
assert(failure != .release)
|
assert(failure != .release)
|
||||||
assert(failure != .acq_rel)
|
assert(failure != .acq_rel)
|
||||||
|
|
||||||
value: T; ok: bool
|
value: T; ok: bool
|
||||||
#partial switch (failure) {
|
#partial switch failure {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
assert(success != .relaxed)
|
assert(success != .relaxed)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchg(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Seq_Cst)
|
||||||
case .release:
|
case .release:
|
||||||
value, ok := intrinsics.atomic_cxchg_rel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Release, .Seq_Cst)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchg_acqrel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
|
||||||
}
|
}
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
assert(success != .release)
|
assert(success != .release)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
value, ok := intrinsics.atomic_cxchg_relaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Relaxed, .Relaxed)
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchg_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acquire, .Relaxed)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchg_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Consume, .Relaxed)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchg_acqrel_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
|
||||||
}
|
}
|
||||||
case .consume:
|
case .consume:
|
||||||
fallthrough
|
assert(success == .seq_cst)
|
||||||
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Consume)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
assert(success == .seq_cst)
|
assert(success == .seq_cst)
|
||||||
value, ok := intrinsics.atomic_cxchg_failacq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_strong_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
|
||||||
|
|
||||||
}
|
}
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) {
|
atomic_compare_exchange_weak :: #force_inline proc(object, expected: ^$T, desired: T) -> bool {
|
||||||
value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired)
|
value, ok := intrinsics.atomic_compare_exchange_weak(object, expected^, desired)
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) {
|
atomic_compare_exchange_weak_explicit :: #force_inline proc(object, expected: ^$T, desited: T, success, failure: memory_order) -> bool {
|
||||||
assert(failure != .release)
|
assert(failure != .release)
|
||||||
assert(failure != .acq_rel)
|
assert(failure != .acq_rel)
|
||||||
|
|
||||||
value: T; ok: bool
|
value: T; ok: bool
|
||||||
#partial switch (failure) {
|
#partial switch failure {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
assert(success != .relaxed)
|
assert(success != .relaxed)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchgweak(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Seq_Cst)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Seq_Cst)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Seq_Cst)
|
||||||
case .release:
|
case .release:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_rel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Release, .Seq_Cst)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acqrel(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Seq_Cst)
|
||||||
}
|
}
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
assert(success != .release)
|
assert(success != .release)
|
||||||
#partial switch (success) {
|
#partial switch success {
|
||||||
case .relaxed:
|
case .relaxed:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_relaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Relaxed, .Relaxed)
|
||||||
case .seq_cst:
|
case .seq_cst:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Relaxed)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acquire, .Relaxed)
|
||||||
case .consume:
|
case .consume:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acq_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Consume, .Relaxed)
|
||||||
case .acq_rel:
|
case .acq_rel:
|
||||||
value, ok := intrinsics.atomic_cxchgweak_acqrel_failrelaxed(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Acq_Rel, .Relaxed)
|
||||||
}
|
}
|
||||||
case .consume:
|
case .consume:
|
||||||
fallthrough
|
assert(success == .seq_cst)
|
||||||
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Consume)
|
||||||
case .acquire:
|
case .acquire:
|
||||||
assert(success == .seq_cst)
|
assert(success == .seq_cst)
|
||||||
value, ok := intrinsics.atomic_cxchgweak_failacq(object, expected^, desired)
|
value, ok = intrinsics.atomic_compare_exchange_weak_explicit(object, expected^, desired, .Seq_Cst, .Acquire)
|
||||||
|
|
||||||
}
|
}
|
||||||
if !ok { expected^ = value }
|
if !ok { expected^ = value }
|
||||||
@@ -297,19 +287,14 @@ atomic_fetch_add :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_add_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_add_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_add_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_add_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_add_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_add_acq(object, operand)
|
case .release: return intrinsics.atomic_add_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_add_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_add_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_add_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_add_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_add_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_add(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,19 +303,14 @@ atomic_fetch_sub :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_sub_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_sub_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_sub_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_sub_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_sub_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_sub_acq(object, operand)
|
case .release: return intrinsics.atomic_sub_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_sub_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_sub_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_sub_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_sub_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_sub_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_sub(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,19 +319,14 @@ atomic_fetch_or :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_or_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_or_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_or_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_or_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_or_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_or_acq(object, operand)
|
case .release: return intrinsics.atomic_or_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_or_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_or_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_or_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_or_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_or_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_or(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,19 +335,14 @@ atomic_fetch_xor :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_xor_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_xor_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_xor_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_xor_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_xor_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_xor_acq(object, operand)
|
case .release: return intrinsics.atomic_xor_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_xor_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_xor_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_xor_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_xor_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_xor_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_xor(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,19 +350,14 @@ atomic_fetch_and :: #force_inline proc(object: ^$T, operand: T) -> T {
|
|||||||
return intrinsics.atomic_and(object, operand)
|
return intrinsics.atomic_and(object, operand)
|
||||||
}
|
}
|
||||||
atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
atomic_fetch_and_explicit :: #force_inline proc(object: ^$T, operand: T, order: memory_order) -> T {
|
||||||
switch (order) {
|
switch order {
|
||||||
case .relaxed:
|
case .relaxed: return intrinsics.atomic_and_explicit(object, operand, .Relaxed)
|
||||||
return intrinsics.atomic_and_relaxed(object, operand)
|
case .consume: return intrinsics.atomic_and_explicit(object, operand, .Consume)
|
||||||
case .consume:
|
case .acquire: return intrinsics.atomic_and_explicit(object, operand, .Acquire)
|
||||||
return intrinsics.atomic_and_acq(object, operand)
|
case .release: return intrinsics.atomic_and_explicit(object, operand, .Release)
|
||||||
case .acquire:
|
case .acq_rel: return intrinsics.atomic_and_explicit(object, operand, .Acq_Rel)
|
||||||
return intrinsics.atomic_and_acq(object, operand)
|
case: fallthrough
|
||||||
case .release:
|
case .seq_cst: return intrinsics.atomic_and_explicit(object, operand, .Seq_Cst)
|
||||||
return intrinsics.atomic_and_rel(object, operand)
|
|
||||||
case .acq_rel:
|
|
||||||
return intrinsics.atomic_and_acqrel(object, operand)
|
|
||||||
case .seq_cst:
|
|
||||||
return intrinsics.atomic_and(object, operand)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+55
-5
@@ -1,8 +1,8 @@
|
|||||||
package libc
|
package libc
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -13,7 +13,7 @@ when ODIN_OS == "windows" {
|
|||||||
FILE :: struct {}
|
FILE :: struct {}
|
||||||
|
|
||||||
// MSVCRT compatible.
|
// MSVCRT compatible.
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
_IOFBF :: 0x0000
|
_IOFBF :: 0x0000
|
||||||
_IONBF :: 0x0004
|
_IONBF :: 0x0004
|
||||||
_IOLBF :: 0x0040
|
_IOLBF :: 0x0040
|
||||||
@@ -48,7 +48,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GLIBC and MUSL compatible.
|
// GLIBC and MUSL compatible.
|
||||||
when ODIN_OS == "linux" {
|
when ODIN_OS == .Linux {
|
||||||
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
||||||
|
|
||||||
_IOFBF :: 0
|
_IOFBF :: 0
|
||||||
@@ -78,7 +78,57 @@ when ODIN_OS == "linux" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .OpenBSD {
|
||||||
|
fpos_t :: distinct i64
|
||||||
|
|
||||||
|
_IOFBF :: 0
|
||||||
|
_IOLBF :: 1
|
||||||
|
_IONBF :: 1
|
||||||
|
|
||||||
|
BUFSIZ :: 1024
|
||||||
|
|
||||||
|
EOF :: int(-1)
|
||||||
|
|
||||||
|
FOPEN_MAX :: 20
|
||||||
|
FILENAME_MAX :: 1024
|
||||||
|
|
||||||
|
SEEK_SET :: 0
|
||||||
|
SEEK_CUR :: 1
|
||||||
|
SEEK_END :: 2
|
||||||
|
|
||||||
|
foreign libc {
|
||||||
|
stderr: ^FILE
|
||||||
|
stdin: ^FILE
|
||||||
|
stdout: ^FILE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .FreeBSD {
|
||||||
|
fpos_t :: distinct i64
|
||||||
|
|
||||||
|
_IOFBF :: 0
|
||||||
|
_IOLBF :: 1
|
||||||
|
_IONBF :: 1
|
||||||
|
|
||||||
|
BUFSIZ :: 1024
|
||||||
|
|
||||||
|
EOF :: int(-1)
|
||||||
|
|
||||||
|
FOPEN_MAX :: 20
|
||||||
|
FILENAME_MAX :: 1024
|
||||||
|
|
||||||
|
SEEK_SET :: 0
|
||||||
|
SEEK_CUR :: 1
|
||||||
|
SEEK_END :: 2
|
||||||
|
|
||||||
|
foreign libc {
|
||||||
|
stderr: ^FILE
|
||||||
|
stdin: ^FILE
|
||||||
|
stdout: ^FILE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .Darwin {
|
||||||
fpos_t :: distinct i64
|
fpos_t :: distinct i64
|
||||||
|
|
||||||
_IOFBF :: 0
|
_IOFBF :: 0
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ package libc
|
|||||||
|
|
||||||
// 7.22 General utilities
|
// 7.22 General utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
RAND_MAX :: 0x7fff
|
RAND_MAX :: 0x7fff
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
@@ -24,7 +24,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "linux" {
|
when ODIN_OS == .Linux {
|
||||||
RAND_MAX :: 0x7fffffff
|
RAND_MAX :: 0x7fffffff
|
||||||
|
|
||||||
// GLIBC and MUSL only
|
// GLIBC and MUSL only
|
||||||
@@ -40,7 +40,7 @@ when ODIN_OS == "linux" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
RAND_MAX :: 0x7fffffff
|
RAND_MAX :: 0x7fffffff
|
||||||
|
|
||||||
// GLIBC and MUSL only
|
// GLIBC and MUSL only
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import "core:runtime"
|
|||||||
|
|
||||||
// 7.24 String handling
|
// 7.24 String handling
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package libc
|
|||||||
thrd_start_t :: proc "c" (rawptr) -> int
|
thrd_start_t :: proc "c" (rawptr) -> int
|
||||||
tss_dtor_t :: proc "c" (rawptr)
|
tss_dtor_t :: proc "c" (rawptr)
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc {
|
foreign import libc {
|
||||||
"system:libucrt.lib",
|
"system:libucrt.lib",
|
||||||
"system:msvcprt.lib"
|
"system:msvcprt.lib"
|
||||||
@@ -74,7 +74,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GLIBC and MUSL compatible constants and types.
|
// GLIBC and MUSL compatible constants and types.
|
||||||
when ODIN_OS == "linux" {
|
when ODIN_OS == .Linux {
|
||||||
foreign import libc {
|
foreign import libc {
|
||||||
"system:c",
|
"system:c",
|
||||||
"system:pthread"
|
"system:pthread"
|
||||||
@@ -138,6 +138,6 @@ when ODIN_OS == "linux" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
// TODO: find out what this is meant to be!
|
// TODO: find out what this is meant to be!
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.27 Date and time
|
// 7.27 Date and time
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -12,7 +12,7 @@ when ODIN_OS == "windows" {
|
|||||||
|
|
||||||
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
||||||
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.27.2 Time manipulation functions
|
// 7.27.2 Time manipulation functions
|
||||||
clock :: proc() -> clock_t ---
|
clock :: proc() -> clock_t ---
|
||||||
@@ -45,7 +45,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.27.2 Time manipulation functions
|
// 7.27.2 Time manipulation functions
|
||||||
@@ -63,7 +63,12 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" {
|
|||||||
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
||||||
}
|
}
|
||||||
|
|
||||||
CLOCKS_PER_SEC :: 1000000
|
when ODIN_OS == .OpenBSD {
|
||||||
|
CLOCKS_PER_SEC :: 100
|
||||||
|
} else {
|
||||||
|
CLOCKS_PER_SEC :: 1000000
|
||||||
|
}
|
||||||
|
|
||||||
TIME_UTC :: 1
|
TIME_UTC :: 1
|
||||||
|
|
||||||
time_t :: distinct i64
|
time_t :: distinct i64
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.28 Unicode utilities
|
// 7.28 Unicode utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package libc
|
|||||||
|
|
||||||
// 7.29 Extended multibyte and wide character utilities
|
// 7.29 Extended multibyte and wide character utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
|
|||||||
+14
-7
@@ -2,27 +2,34 @@ package libc
|
|||||||
|
|
||||||
// 7.30 Wide character classification and mapping utilities
|
// 7.30 Wide character classification and mapping utilities
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
foreign import libc "system:libucrt.lib"
|
foreign import libc "system:libucrt.lib"
|
||||||
} else when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
foreign import libc "system:System.framework"
|
foreign import libc "system:System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
wctrans_t :: distinct wchar_t
|
wctrans_t :: distinct wchar_t
|
||||||
wctype_t :: distinct ushort
|
wctype_t :: distinct ushort
|
||||||
}
|
|
||||||
|
|
||||||
when ODIN_OS == "linux" {
|
} else when ODIN_OS == .Linux {
|
||||||
wctrans_t :: distinct intptr_t
|
wctrans_t :: distinct intptr_t
|
||||||
wctype_t :: distinct ulong
|
wctype_t :: distinct ulong
|
||||||
}
|
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
} else when ODIN_OS == .Darwin {
|
||||||
wctrans_t :: distinct int
|
wctrans_t :: distinct int
|
||||||
wctype_t :: distinct u32
|
wctype_t :: distinct u32
|
||||||
|
|
||||||
|
} else when ODIN_OS == .OpenBSD {
|
||||||
|
wctrans_t :: distinct rawptr
|
||||||
|
wctype_t :: distinct rawptr
|
||||||
|
|
||||||
|
} else when ODIN_OS == .FreeBSD {
|
||||||
|
wctrans_t :: distinct int
|
||||||
|
wctype_t :: distinct ulong
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ when size_of(uintptr) == 8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Error :: union {
|
Error :: union #shared_nil {
|
||||||
General_Error,
|
General_Error,
|
||||||
Deflate_Error,
|
Deflate_Error,
|
||||||
ZLIB_Error,
|
ZLIB_Error,
|
||||||
@@ -58,6 +58,7 @@ Error :: union {
|
|||||||
}
|
}
|
||||||
|
|
||||||
General_Error :: enum {
|
General_Error :: enum {
|
||||||
|
None = 0,
|
||||||
File_Not_Found,
|
File_Not_Found,
|
||||||
Cannot_Open_File,
|
Cannot_Open_File,
|
||||||
File_Too_Short,
|
File_Too_Short,
|
||||||
@@ -76,6 +77,7 @@ General_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GZIP_Error :: enum {
|
GZIP_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Invalid_GZIP_Signature,
|
Invalid_GZIP_Signature,
|
||||||
Reserved_Flag_Set,
|
Reserved_Flag_Set,
|
||||||
Invalid_Extra_Data,
|
Invalid_Extra_Data,
|
||||||
@@ -100,6 +102,7 @@ GZIP_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZIP_Error :: enum {
|
ZIP_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Invalid_ZIP_File_Signature,
|
Invalid_ZIP_File_Signature,
|
||||||
Unexpected_Signature,
|
Unexpected_Signature,
|
||||||
Insert_Next_Disk,
|
Insert_Next_Disk,
|
||||||
@@ -107,6 +110,7 @@ ZIP_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZLIB_Error :: enum {
|
ZLIB_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Unsupported_Window_Size,
|
Unsupported_Window_Size,
|
||||||
FDICT_Unsupported,
|
FDICT_Unsupported,
|
||||||
Unsupported_Compression_Level,
|
Unsupported_Compression_Level,
|
||||||
@@ -114,6 +118,7 @@ ZLIB_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Deflate_Error :: enum {
|
Deflate_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Huffman_Bad_Sizes,
|
Huffman_Bad_Sizes,
|
||||||
Huffman_Bad_Code_Lengths,
|
Huffman_Bad_Code_Lengths,
|
||||||
Inflate_Error,
|
Inflate_Error,
|
||||||
@@ -139,7 +144,13 @@ Context_Memory_Input :: struct #packed {
|
|||||||
size_packed: i64,
|
size_packed: i64,
|
||||||
size_unpacked: i64,
|
size_unpacked: i64,
|
||||||
}
|
}
|
||||||
#assert(size_of(Context_Memory_Input) == 64)
|
when size_of(rawptr) == 8 {
|
||||||
|
#assert(size_of(Context_Memory_Input) == 64)
|
||||||
|
} else {
|
||||||
|
// e.g. `-target:windows_i386`
|
||||||
|
#assert(size_of(Context_Memory_Input) == 52)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Context_Stream_Input :: struct #packed {
|
Context_Stream_Input :: struct #packed {
|
||||||
input_data: []u8,
|
input_data: []u8,
|
||||||
@@ -473,4 +484,4 @@ discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
|
|||||||
consume_bits_lsb(z, discard)
|
consume_bits_lsb(z, discard)
|
||||||
}
|
}
|
||||||
|
|
||||||
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream};
|
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream}
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ OS :: enum u8 {
|
|||||||
_Unknown = 14,
|
_Unknown = 14,
|
||||||
Unknown = 255,
|
Unknown = 255,
|
||||||
}
|
}
|
||||||
OS_Name :: #partial [OS]string{
|
OS_Name :: #sparse[OS]string{
|
||||||
|
._Unknown = "",
|
||||||
.FAT = "FAT",
|
.FAT = "FAT",
|
||||||
.Amiga = "Amiga",
|
.Amiga = "Amiga",
|
||||||
.VMS = "VMS/OpenVMS",
|
.VMS = "VMS/OpenVMS",
|
||||||
@@ -99,7 +100,7 @@ E_GZIP :: compress.GZIP_Error
|
|||||||
E_ZLIB :: compress.ZLIB_Error
|
E_ZLIB :: compress.ZLIB_Error
|
||||||
E_Deflate :: compress.Deflate_Error
|
E_Deflate :: compress.Deflate_Error
|
||||||
|
|
||||||
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le))
|
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
|
||||||
|
|
||||||
load :: proc{load_from_slice, load_from_file, load_from_context}
|
load :: proc{load_from_slice, load_from_file, load_from_context}
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
|
|||||||
|
|
||||||
z.output = buf
|
z.output = buf
|
||||||
|
|
||||||
if expected_output_size > GZIP_MAX_PAYLOAD_SIZE {
|
if i64(expected_output_size) > i64(GZIP_MAX_PAYLOAD_SIZE) {
|
||||||
return E_GZIP.Payload_Size_Exceeds_Max_Payload
|
return E_GZIP.Payload_Size_Exceeds_Max_Payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ Options :: struct {
|
|||||||
level: u8,
|
level: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
Error :: compress.Error
|
Error :: compress.Error
|
||||||
E_General :: compress.General_Error
|
General_Error :: compress.General_Error
|
||||||
E_ZLIB :: compress.ZLIB_Error
|
ZLIB_Error :: compress.ZLIB_Error
|
||||||
E_Deflate :: compress.Deflate_Error
|
Deflate_Error :: compress.Deflate_Error
|
||||||
|
|
||||||
DEFLATE_MAX_CHUNK_SIZE :: 65535
|
DEFLATE_MAX_CHUNK_SIZE :: 65535
|
||||||
DEFLATE_MAX_LITERAL_SIZE :: 65535
|
DEFLATE_MAX_LITERAL_SIZE :: 65535
|
||||||
@@ -258,7 +258,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
|||||||
|
|
||||||
for i in 1 ..< HUFFMAN_MAX_BITS {
|
for i in 1 ..< HUFFMAN_MAX_BITS {
|
||||||
if sizes[i] > (1 << uint(i)) {
|
if sizes[i] > (1 << uint(i)) {
|
||||||
return E_Deflate.Huffman_Bad_Sizes
|
return .Huffman_Bad_Sizes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code := int(0)
|
code := int(0)
|
||||||
@@ -270,7 +270,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
|||||||
code = code + sizes[i]
|
code = code + sizes[i]
|
||||||
if sizes[i] != 0 {
|
if sizes[i] != 0 {
|
||||||
if code - 1 >= (1 << u16(i)) {
|
if code - 1 >= (1 << u16(i)) {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
|
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
|
||||||
@@ -314,15 +314,15 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
|||||||
s += 1
|
s += 1
|
||||||
}
|
}
|
||||||
if s >= 16 {
|
if s >= 16 {
|
||||||
return 0, E_Deflate.Bad_Huffman_Code
|
return 0, .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
// code size is s, so:
|
// code size is s, so:
|
||||||
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
|
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
|
||||||
if b >= size_of(t.size) {
|
if b >= size_of(t.size) {
|
||||||
return 0, E_Deflate.Bad_Huffman_Code
|
return 0, .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
if t.size[b] != s {
|
if t.size[b] != s {
|
||||||
return 0, E_Deflate.Bad_Huffman_Code
|
return 0, .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
|
|
||||||
compress.consume_bits_lsb(z, s)
|
compress.consume_bits_lsb(z, s)
|
||||||
@@ -335,11 +335,11 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
|
|||||||
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
|
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
|
||||||
if z.num_bits < 16 {
|
if z.num_bits < 16 {
|
||||||
if z.num_bits > 63 {
|
if z.num_bits > 63 {
|
||||||
return 0, E_ZLIB.Code_Buffer_Malformed
|
return 0, .Code_Buffer_Malformed
|
||||||
}
|
}
|
||||||
compress.refill_lsb(z)
|
compress.refill_lsb(z)
|
||||||
if z.num_bits > 63 {
|
if z.num_bits > 63 {
|
||||||
return 0, E_General.Stream_Too_Short
|
return 0, .Stream_Too_Short
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
|
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
|
||||||
@@ -361,7 +361,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
if value < 256 {
|
if value < 256 {
|
||||||
e := write_byte(z, u8(value))
|
e := write_byte(z, u8(value))
|
||||||
if e != .None {
|
if e != .None {
|
||||||
return E_General.Output_Too_Short
|
return .Output_Too_Short
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if value == 256 {
|
if value == 256 {
|
||||||
@@ -377,7 +377,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
|
|
||||||
value, e = decode_huffman(z, z_offset)
|
value, e = decode_huffman(z, z_offset)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return E_Deflate.Bad_Huffman_Code
|
return .Bad_Huffman_Code
|
||||||
}
|
}
|
||||||
|
|
||||||
distance := Z_DIST_BASE[value]
|
distance := Z_DIST_BASE[value]
|
||||||
@@ -387,7 +387,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
|
|
||||||
if z.bytes_written < i64(distance) {
|
if z.bytes_written < i64(distance) {
|
||||||
// Distance is longer than we've decoded so far.
|
// Distance is longer than we've decoded so far.
|
||||||
return E_Deflate.Bad_Distance
|
return .Bad_Distance
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -405,14 +405,14 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
|
|||||||
c := z.output.buf[z.bytes_written - i64(distance)]
|
c := z.output.buf[z.bytes_written - i64(distance)]
|
||||||
e := repl_byte(z, length, c)
|
e := repl_byte(z, length, c)
|
||||||
if e != .None {
|
if e != .None {
|
||||||
return E_General.Output_Too_Short
|
return .Output_Too_Short
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if length > 0 {
|
if length > 0 {
|
||||||
e := repl_bytes(z, length, distance)
|
e := repl_bytes(z, length, distance)
|
||||||
if e != .None {
|
if e != .None {
|
||||||
return E_General.Output_Too_Short
|
return .Output_Too_Short
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,25 +432,25 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
if !raw {
|
if !raw {
|
||||||
size, size_err := compress.input_size(ctx)
|
size, size_err := compress.input_size(ctx)
|
||||||
if size < 6 || size_err != nil {
|
if size < 6 || size_err != nil {
|
||||||
return E_General.Stream_Too_Short
|
return .Stream_Too_Short
|
||||||
}
|
}
|
||||||
|
|
||||||
cmf, _ := compress.read_u8(ctx)
|
cmf, _ := compress.read_u8(ctx)
|
||||||
|
|
||||||
method := Compression_Method(cmf & 0xf)
|
method := Compression_Method(cmf & 0xf)
|
||||||
if method != .DEFLATE {
|
if method != .DEFLATE {
|
||||||
return E_General.Unknown_Compression_Method
|
return .Unknown_Compression_Method
|
||||||
}
|
}
|
||||||
|
|
||||||
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
|
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
|
||||||
return E_ZLIB.Unsupported_Window_Size
|
return .Unsupported_Window_Size
|
||||||
}
|
}
|
||||||
flg, _ := compress.read_u8(ctx)
|
flg, _ := compress.read_u8(ctx)
|
||||||
|
|
||||||
fcheck := flg & 0x1f
|
fcheck := flg & 0x1f
|
||||||
fcheck_computed := (cmf << 8 | flg) & 0x1f
|
fcheck_computed := (cmf << 8 | flg) & 0x1f
|
||||||
if fcheck != fcheck_computed {
|
if fcheck != fcheck_computed {
|
||||||
return E_General.Checksum_Failed
|
return .Checksum_Failed
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -458,7 +458,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
They're application specific and PNG doesn't use them.
|
They're application specific and PNG doesn't use them.
|
||||||
*/
|
*/
|
||||||
if fdict := (flg >> 5) & 1; fdict != 0 {
|
if fdict := (flg >> 5) & 1; fdict != 0 {
|
||||||
return E_ZLIB.FDICT_Unsupported
|
return .FDICT_Unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// flevel := Compression_Level((flg >> 6) & 3);
|
// flevel := Compression_Level((flg >> 6) & 3);
|
||||||
@@ -485,7 +485,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
|
|||||||
output_hash := hash.adler32(ctx.output.buf[:])
|
output_hash := hash.adler32(ctx.output.buf[:])
|
||||||
|
|
||||||
if output_hash != u32(adler) {
|
if output_hash != u32(adler) {
|
||||||
return E_General.Checksum_Failed
|
return .Checksum_Failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -555,7 +555,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
|
|
||||||
|
|
||||||
if ~uncompressed_len != length_check {
|
if ~uncompressed_len != length_check {
|
||||||
return E_Deflate.Len_Nlen_Mismatch
|
return .Len_Nlen_Mismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -571,7 +571,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
assert(uncompressed_len == 0)
|
assert(uncompressed_len == 0)
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return E_Deflate.BType_3
|
return .BType_3
|
||||||
case:
|
case:
|
||||||
// fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type)
|
// fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type)
|
||||||
if type == 1 {
|
if type == 1 {
|
||||||
@@ -604,7 +604,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
c = decode_huffman(z, codelength_ht) or_return
|
c = decode_huffman(z, codelength_ht) or_return
|
||||||
|
|
||||||
if c < 0 || c >= 19 {
|
if c < 0 || c >= 19 {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
if c < 16 {
|
if c < 16 {
|
||||||
lencodes[n] = u8(c)
|
lencodes[n] = u8(c)
|
||||||
@@ -616,7 +616,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
case 16:
|
case 16:
|
||||||
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
|
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
fill = lencodes[n - 1]
|
fill = lencodes[n - 1]
|
||||||
case 17:
|
case 17:
|
||||||
@@ -624,11 +624,11 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
case 18:
|
case 18:
|
||||||
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
|
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
|
||||||
case:
|
case:
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
if ntot - n < u32(c) {
|
if ntot - n < u32(c) {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
nc := n + u32(c)
|
nc := n + u32(c)
|
||||||
@@ -639,7 +639,7 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n != ntot {
|
if n != ntot {
|
||||||
return E_Deflate.Huffman_Bad_Code_Lengths
|
return .Huffman_Bad_Code_Lengths
|
||||||
}
|
}
|
||||||
|
|
||||||
build_huffman(z_repeat, lencodes[:hlit]) or_return
|
build_huffman(z_repeat, lencodes[:hlit]) or_return
|
||||||
@@ -677,4 +677,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
|
|||||||
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
inflate :: proc{inflate_from_context, inflate_from_byte_array};
|
inflate :: proc{inflate_from_context, inflate_from_byte_array}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package dynamic_bit_array
|
package dynamic_bit_array
|
||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Note that these constants are dependent on the backing being a u64.
|
Note that these constants are dependent on the backing being a u64.
|
||||||
@@ -11,11 +12,120 @@ INDEX_SHIFT :: 6
|
|||||||
@(private="file")
|
@(private="file")
|
||||||
INDEX_MASK :: 63
|
INDEX_MASK :: 63
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
NUM_BITS :: 64
|
||||||
|
|
||||||
Bit_Array :: struct {
|
Bit_Array :: struct {
|
||||||
bits: [dynamic]u64,
|
bits: [dynamic]u64,
|
||||||
bias: int,
|
bias: int,
|
||||||
|
max_index: int,
|
||||||
|
free_pointer: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bit_Array_Iterator :: struct {
|
||||||
|
array: ^Bit_Array,
|
||||||
|
word_idx: int,
|
||||||
|
bit_idx: uint,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- ba: ^Bit_Array - the array to iterate over
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator that holds iteration state
|
||||||
|
*/
|
||||||
|
make_iterator :: proc (ba: ^Bit_Array) -> (it: Bit_Array_Iterator) {
|
||||||
|
return Bit_Array_Iterator { array = ba }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- set: bool - the state of the bit at `index`
|
||||||
|
- index: int - the next bit of the Bit_Array referenced by `it`.
|
||||||
|
- ok: bool - `true` if the iterator returned a valid index,
|
||||||
|
`false` if there were no more bits
|
||||||
|
*/
|
||||||
|
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
|
||||||
|
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||||
|
if index > it.array.max_index { return false, 0, false }
|
||||||
|
|
||||||
|
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||||
|
set = (word >> it.bit_idx & 1) == 1
|
||||||
|
|
||||||
|
it.bit_idx += 1
|
||||||
|
if it.bit_idx >= NUM_BITS {
|
||||||
|
it.bit_idx = 0
|
||||||
|
it.word_idx += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return set, index, true
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- index: int - the next set bit of the Bit_Array referenced by `it`.
|
||||||
|
- ok: bool - `true` if the iterator returned a valid index,
|
||||||
|
`false` if there were no more bits set
|
||||||
|
*/
|
||||||
|
iterate_by_set :: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||||
|
return iterate_internal_(it, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
In:
|
||||||
|
- it: ^Bit_Array_Iterator - the iterator struct that holds the state.
|
||||||
|
|
||||||
|
Out:
|
||||||
|
- index: int - the next unset bit of the Bit_Array referenced by `it`.
|
||||||
|
- ok: bool - `true` if the iterator returned a valid index,
|
||||||
|
`false` if there were no more unset bits
|
||||||
|
*/
|
||||||
|
iterate_by_unset:: proc (it: ^Bit_Array_Iterator) -> (index: int, ok: bool) {
|
||||||
|
return iterate_internal_(it, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
|
||||||
|
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||||
|
when ! ITERATE_SET_BITS { word = ~word }
|
||||||
|
|
||||||
|
// if the word is empty or we have already gone over all the bits in it,
|
||||||
|
// b.bit_idx is greater than the index of any set bit in the word,
|
||||||
|
// meaning that word >> b.bit_idx == 0.
|
||||||
|
for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
|
||||||
|
it.word_idx += 1
|
||||||
|
it.bit_idx = 0
|
||||||
|
word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||||
|
when ! ITERATE_SET_BITS { word = ~word }
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are iterating the set bits, reaching the end of the array means we have no more bits to check
|
||||||
|
when ITERATE_SET_BITS {
|
||||||
|
if it.word_idx >= len(it.array.bits) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reaching here means that the word has some set bits
|
||||||
|
it.bit_idx += uint(intrinsics.count_trailing_zeros(word >> it.bit_idx))
|
||||||
|
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||||
|
|
||||||
|
it.bit_idx += 1
|
||||||
|
if it.bit_idx >= NUM_BITS {
|
||||||
|
it.bit_idx = 0
|
||||||
|
it.word_idx += 1
|
||||||
|
}
|
||||||
|
return index, index <= it.array.max_index
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In:
|
In:
|
||||||
- ba: ^Bit_Array - a pointer to the Bit Array
|
- ba: ^Bit_Array - a pointer to the Bit Array
|
||||||
@@ -70,6 +180,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
|||||||
|
|
||||||
resize_if_needed(ba, leg_index) or_return
|
resize_if_needed(ba, leg_index) or_return
|
||||||
|
|
||||||
|
ba.max_index = max(idx, ba.max_index)
|
||||||
ba.bits[leg_index] |= 1 << uint(bit_index)
|
ba.bits[leg_index] |= 1 << uint(bit_index)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -77,7 +188,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator
|
|||||||
/*
|
/*
|
||||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||||
*/
|
*/
|
||||||
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: Bit_Array, ok: bool) #optional_ok {
|
create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: ^Bit_Array, ok: bool) #optional_ok {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
size_in_bits := max_index - min_index
|
size_in_bits := max_index - min_index
|
||||||
|
|
||||||
@@ -85,10 +196,11 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
|
|||||||
|
|
||||||
legs := size_in_bits >> INDEX_SHIFT
|
legs := size_in_bits >> INDEX_SHIFT
|
||||||
|
|
||||||
res = Bit_Array{
|
res = new(Bit_Array)
|
||||||
bias = min_index,
|
res.bias = min_index
|
||||||
}
|
res.max_index = max_index
|
||||||
return res, resize_if_needed(&res, legs)
|
res.free_pointer = true
|
||||||
|
return res, resize_if_needed(res, legs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -96,7 +208,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
|
|||||||
*/
|
*/
|
||||||
clear :: proc(ba: ^Bit_Array) {
|
clear :: proc(ba: ^Bit_Array) {
|
||||||
if ba == nil { return }
|
if ba == nil { return }
|
||||||
ba.bits = {}
|
mem.zero_slice(ba.bits[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -105,6 +217,9 @@ clear :: proc(ba: ^Bit_Array) {
|
|||||||
destroy :: proc(ba: ^Bit_Array) {
|
destroy :: proc(ba: ^Bit_Array) {
|
||||||
if ba == nil { return }
|
if ba == nil { return }
|
||||||
delete(ba.bits)
|
delete(ba.bits)
|
||||||
|
if ba.free_pointer { // Only free if this Bit_Array was created using `create`, not when on the stack.
|
||||||
|
free(ba)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -121,4 +236,4 @@ resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocat
|
|||||||
resize(&ba.bits, legs + 1)
|
resize(&ba.bits, legs + 1)
|
||||||
}
|
}
|
||||||
return len(ba.bits) > legs
|
return len(ba.bits) > legs
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package dynamic_bit_array
|
|||||||
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
|
// returns `false`, `false`, because this Bit Array wasn't created to allow negative indices.
|
||||||
was_set, was_retrieved := get(&bits, -1)
|
was_set, was_retrieved := get(&bits, -1)
|
||||||
fmt.println(was_set, was_retrieved)
|
fmt.println(was_set, was_retrieved)
|
||||||
|
destroy(&bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
|
-- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation:
|
||||||
@@ -40,13 +41,13 @@ package dynamic_bit_array
|
|||||||
using bit_array
|
using bit_array
|
||||||
|
|
||||||
bits := create(int(max(Foo)), int(min(Foo)))
|
bits := create(int(max(Foo)), int(min(Foo)))
|
||||||
defer destroy(&bits)
|
defer destroy(bits)
|
||||||
|
|
||||||
fmt.printf("Set(Bar): %v\n", set(&bits, Foo.Bar))
|
fmt.printf("Set(Bar): %v\n", set(bits, Foo.Bar))
|
||||||
fmt.printf("Get(Bar): %v, %v\n", get(&bits, Foo.Bar))
|
fmt.printf("Get(Bar): %v, %v\n", get(bits, Foo.Bar))
|
||||||
fmt.printf("Set(Negative_Test): %v\n", set(&bits, Foo.Negative_Test))
|
fmt.printf("Set(Negative_Test): %v\n", set(bits, Foo.Negative_Test))
|
||||||
fmt.printf("Get(Leaves): %v, %v\n", get(&bits, Foo.Leaves))
|
fmt.printf("Get(Leaves): %v, %v\n", get(bits, Foo.Leaves))
|
||||||
fmt.printf("Get(Negative_Test): %v, %v\n", get(&bits, Foo.Negative_Test))
|
fmt.printf("Get(Negative_Test): %v, %v\n", get(bits, Foo.Negative_Test))
|
||||||
fmt.printf("Freed.\n")
|
fmt.printf("Freed.\n")
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package container_lru
|
package container_lru
|
||||||
|
|
||||||
|
import "core:runtime"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:mem"
|
_ :: runtime
|
||||||
_ :: intrinsics
|
_ :: intrinsics
|
||||||
_ :: mem
|
|
||||||
|
|
||||||
Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||||
prev, next: ^Node(Key, Value),
|
prev, next: ^Node(Key, Value),
|
||||||
@@ -23,11 +23,10 @@ Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key
|
|||||||
count: int,
|
count: int,
|
||||||
capacity: int,
|
capacity: int,
|
||||||
|
|
||||||
node_allocator: mem.Allocator,
|
node_allocator: runtime.Allocator,
|
||||||
|
|
||||||
on_remove: proc(key: Key, value: Value, user_data: rawptr),
|
on_remove: proc(key: Key, value: Value, user_data: rawptr),
|
||||||
on_remove_user_data: rawptr,
|
on_remove_user_data: rawptr,
|
||||||
call_on_remove_on_destroy: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// init initializes a Cache
|
// init initializes a Cache
|
||||||
@@ -37,23 +36,28 @@ init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := con
|
|||||||
c.capacity = capacity
|
c.capacity = capacity
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroy deinitializes a Cache
|
// destroy deinitializes a Cachem
|
||||||
destroy :: proc(c: ^$C/Cache($Key, $Value)) {
|
destroy :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
|
||||||
|
clear(c, call_on_remove)
|
||||||
|
delete(c.entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the contents of a Cache
|
||||||
|
clear :: proc(c: ^$C/Cache($Key, $Value), call_on_remove: bool) {
|
||||||
for _, node in c.entries {
|
for _, node in c.entries {
|
||||||
if c.call_on_remove_on_destroy && c.on_remove != nil {
|
if call_on_remove {
|
||||||
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
_call_on_remove(c, node)
|
||||||
}
|
}
|
||||||
free(node, c.node_allocator)
|
free(node, c.node_allocator)
|
||||||
}
|
}
|
||||||
clear(&c.entries)
|
runtime.clear(&c.entries)
|
||||||
delete(c.entries)
|
|
||||||
c.head = nil
|
c.head = nil
|
||||||
c.tail = nil
|
c.tail = nil
|
||||||
c.count = 0
|
c.count = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the given key value pair. This operation updates the recent usage of the item.
|
// set the given key value pair. This operation updates the recent usage of the item.
|
||||||
set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> mem.Allocator_Error {
|
set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> runtime.Allocator_Error {
|
||||||
if e, ok := c.entries[key]; ok {
|
if e, ok := c.entries[key]; ok {
|
||||||
e.value = value
|
e.value = value
|
||||||
return nil
|
return nil
|
||||||
@@ -143,14 +147,19 @@ _remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
|||||||
|
|
||||||
delete_key(&c.entries, node.key)
|
delete_key(&c.entries, node.key)
|
||||||
|
|
||||||
if c.on_remove != nil {
|
_call_on_remove(c, node)
|
||||||
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
free(node, c.node_allocator)
|
free(node, c.node_allocator)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_call_on_remove :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
||||||
|
if c.on_remove != nil {
|
||||||
|
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||||
if c.head != nil {
|
if c.head != nil {
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T {
|
get :: proc(a: $A/Small_Array($N, $T), index: int) -> T {
|
||||||
return a.data[index]
|
return a.data[index]
|
||||||
}
|
}
|
||||||
get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T {
|
get_ptr :: proc(a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
||||||
return &a.data[index]
|
return &a.data[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) {
|
set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||||
a.data[index] = item
|
a.data[index] = item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// The following is a generic O(V+E) topological sorter implementation.
|
||||||
|
// This is the fastest known method for topological sorting and Odin's
|
||||||
|
// map type is being used to accelerate lookups.
|
||||||
|
package container_topological_sort
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:runtime"
|
||||||
|
_ :: intrinsics
|
||||||
|
_ :: runtime
|
||||||
|
|
||||||
|
|
||||||
|
Relations :: struct($K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||||
|
dependents: map[K]bool,
|
||||||
|
dependencies: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
Sorter :: struct(K: typeid) where intrinsics.type_is_valid_map_key(K) {
|
||||||
|
relations: map[K]Relations(K),
|
||||||
|
dependents_allocator: runtime.Allocator,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
make_relations :: proc(sorter: ^$S/Sorter($K)) -> (r: Relations(K)) {
|
||||||
|
r.dependents.allocator = sorter.dependents_allocator
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
init :: proc(sorter: ^$S/Sorter($K)) {
|
||||||
|
sorter.relations = make(map[K]Relations(K))
|
||||||
|
sorter.dependents_allocator = context.allocator
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy :: proc(sorter: ^$S/Sorter($K)) {
|
||||||
|
for _, v in &sorter.relations {
|
||||||
|
delete(v.dependents)
|
||||||
|
}
|
||||||
|
delete(sorter.relations)
|
||||||
|
}
|
||||||
|
|
||||||
|
add_key :: proc(sorter: ^$S/Sorter($K), key: K) -> bool {
|
||||||
|
if key in sorter.relations {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sorter.relations[key] = make_relations(sorter)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
add_dependency :: proc(sorter: ^$S/Sorter($K), key, dependency: K) -> bool {
|
||||||
|
if key == dependency {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
find := &sorter.relations[dependency]
|
||||||
|
if find == nil {
|
||||||
|
find = map_insert(&sorter.relations, dependency, make_relations(sorter))
|
||||||
|
}
|
||||||
|
|
||||||
|
if find.dependents[key] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
find.dependents[key] = true
|
||||||
|
|
||||||
|
find = &sorter.relations[key]
|
||||||
|
if find == nil {
|
||||||
|
find = map_insert(&sorter.relations, key, make_relations(sorter))
|
||||||
|
}
|
||||||
|
|
||||||
|
find.dependencies += 1
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) {
|
||||||
|
relations := &sorter.relations
|
||||||
|
|
||||||
|
for k, v in relations {
|
||||||
|
if v.dependencies == 0 {
|
||||||
|
append(&sorted, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for root in &sorted do for k, _ in relations[root].dependents {
|
||||||
|
relation := &relations[k]
|
||||||
|
relation.dependencies -= 1
|
||||||
|
if relation.dependencies == 0 {
|
||||||
|
append(&sorted, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in relations {
|
||||||
|
if v.dependencies != 0 {
|
||||||
|
append(&cycled, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
|
|||||||
|
|
||||||
assert(len(arg1) == 16)
|
assert(len(arg1) == 16)
|
||||||
|
|
||||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||||
// While it may be unwise to do deserialization here on our
|
// While it may be unwise to do deserialization here on our
|
||||||
// own when fiat-crypto provides equivalent functionality,
|
// own when fiat-crypto provides equivalent functionality,
|
||||||
// doing it this way provides a little under 3x performance
|
// doing it this way provides a little under 3x performance
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
|||||||
// Until dedicated assembly can be written leverage the fact that
|
// Until dedicated assembly can be written leverage the fact that
|
||||||
// the callers of this routine ensure that src/dst are valid.
|
// the callers of this routine ensure that src/dst are valid.
|
||||||
|
|
||||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
|
||||||
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
||||||
// systems that also happen to not be strict about aligned
|
// systems that also happen to not be strict about aligned
|
||||||
// memory access.
|
// memory access.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
when ODIN_OS != "linux" {
|
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows {
|
||||||
_rand_bytes :: proc (dst: []byte) {
|
_rand_bytes :: proc (dst: []byte) {
|
||||||
unimplemented("crypto: rand_bytes not supported on this OS")
|
unimplemented("crypto: rand_bytes not supported on this OS")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
|
||||||
|
foreign import libc "system:c"
|
||||||
|
foreign libc {
|
||||||
|
arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
|
||||||
|
}
|
||||||
|
|
||||||
|
_rand_bytes :: proc (dst: []byte) {
|
||||||
|
arc4random_buf(raw_data(dst), len(dst))
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import win32 "core:sys/windows"
|
||||||
|
import "core:os"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
_rand_bytes :: proc(dst: []byte) {
|
||||||
|
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
|
||||||
|
if ret != os.ERROR_NONE {
|
||||||
|
switch ret {
|
||||||
|
case os.ERROR_INVALID_HANDLE:
|
||||||
|
// The handle to the first parameter is invalid.
|
||||||
|
// This should not happen here, since we explicitly pass nil to it
|
||||||
|
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
|
||||||
|
case os.ERROR_INVALID_PARAMETER:
|
||||||
|
// One of the parameters was invalid
|
||||||
|
panic("crypto: BCryptGenRandom Invalid parameter")
|
||||||
|
case:
|
||||||
|
// Unknown error
|
||||||
|
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
package siphash
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2022 zhibog
|
||||||
|
Made available under the BSD-3 license.
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
zhibog: Initial implementation.
|
||||||
|
|
||||||
|
Implementation of the SipHash hashing algorithm, as defined at <https://github.com/veorq/SipHash> and <https://www.aumasson.jp/siphash/siphash.pdf>
|
||||||
|
|
||||||
|
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "core:crypto"
|
||||||
|
import "core:crypto/util"
|
||||||
|
|
||||||
|
/*
|
||||||
|
High level API
|
||||||
|
*/
|
||||||
|
|
||||||
|
KEY_SIZE :: 16
|
||||||
|
DIGEST_SIZE :: 8
|
||||||
|
|
||||||
|
// sum_string_1_3 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_string_1_3 :: proc(msg, key: string) -> u64 {
|
||||||
|
return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_1_3 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 {
|
||||||
|
ctx: Context
|
||||||
|
hash: u64
|
||||||
|
init(&ctx, key, 1, 3)
|
||||||
|
update(&ctx, msg)
|
||||||
|
final(&ctx, &hash)
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_to_buffer_1_3 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) {
|
||||||
|
sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_to_buffer_1_3 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) {
|
||||||
|
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||||
|
hash := sum_bytes_1_3(msg, key)
|
||||||
|
_collect_output(dst[:], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_1_3 :: proc {
|
||||||
|
sum_string_1_3,
|
||||||
|
sum_bytes_1_3,
|
||||||
|
sum_string_to_buffer_1_3,
|
||||||
|
sum_bytes_to_buffer_1_3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_u64_1_3 will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||||
|
return sum_bytes_1_3(msg, key) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_bytes will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool {
|
||||||
|
derived_tag: [8]byte
|
||||||
|
sum_bytes_to_buffer_1_3(msg, key, derived_tag[:])
|
||||||
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_1_3 :: proc {
|
||||||
|
verify_bytes_1_3,
|
||||||
|
verify_u64_1_3,
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_2_4 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_string_2_4 :: proc(msg, key: string) -> u64 {
|
||||||
|
return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_2_4 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 {
|
||||||
|
ctx: Context
|
||||||
|
hash: u64
|
||||||
|
init(&ctx, key, 2, 4)
|
||||||
|
update(&ctx, msg)
|
||||||
|
final(&ctx, &hash)
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_to_buffer_2_4 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) {
|
||||||
|
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_to_buffer_2_4 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) {
|
||||||
|
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||||
|
hash := sum_bytes_2_4(msg, key)
|
||||||
|
_collect_output(dst[:], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_2_4 :: proc {
|
||||||
|
sum_string_2_4,
|
||||||
|
sum_bytes_2_4,
|
||||||
|
sum_string_to_buffer_2_4,
|
||||||
|
sum_bytes_to_buffer_2_4,
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_string :: sum_string_2_4
|
||||||
|
sum_bytes :: sum_bytes_2_4
|
||||||
|
sum_string_to_buffer :: sum_string_to_buffer_2_4
|
||||||
|
sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4
|
||||||
|
sum :: proc {
|
||||||
|
sum_string,
|
||||||
|
sum_bytes,
|
||||||
|
sum_string_to_buffer,
|
||||||
|
sum_bytes_to_buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_u64_2_4 will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||||
|
return sum_bytes_2_4(msg, key) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_bytes will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool {
|
||||||
|
derived_tag: [8]byte
|
||||||
|
sum_bytes_to_buffer_2_4(msg, key, derived_tag[:])
|
||||||
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_2_4 :: proc {
|
||||||
|
verify_bytes_2_4,
|
||||||
|
verify_u64_2_4,
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_bytes :: verify_bytes_2_4
|
||||||
|
verify_u64 :: verify_u64_2_4
|
||||||
|
verify :: proc {
|
||||||
|
verify_bytes,
|
||||||
|
verify_u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_4_8 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_string_4_8 :: proc(msg, key: string) -> u64 {
|
||||||
|
return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_4_8 will hash the given message with the key and return
|
||||||
|
// the computed hash as a u64
|
||||||
|
sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 {
|
||||||
|
ctx: Context
|
||||||
|
hash: u64
|
||||||
|
init(&ctx, key, 4, 8)
|
||||||
|
update(&ctx, msg)
|
||||||
|
final(&ctx, &hash)
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_string_to_buffer_4_8 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) {
|
||||||
|
sum_bytes_to_buffer_4_8(transmute([]byte)(msg), transmute([]byte)(key), dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum_bytes_to_buffer_4_8 will hash the given message with the key and write
|
||||||
|
// the computed hash into the provided destination buffer
|
||||||
|
sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) {
|
||||||
|
assert(len(dst) >= DIGEST_SIZE, "crypto/siphash: Destination buffer needs to be at least of size 8")
|
||||||
|
hash := sum_bytes_4_8(msg, key)
|
||||||
|
_collect_output(dst[:], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_4_8 :: proc {
|
||||||
|
sum_string_4_8,
|
||||||
|
sum_bytes_4_8,
|
||||||
|
sum_string_to_buffer_4_8,
|
||||||
|
sum_bytes_to_buffer_4_8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_u64_4_8 will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool {
|
||||||
|
return sum_bytes_4_8(msg, key) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify_bytes will check if the supplied tag matches with the output you
|
||||||
|
// will get from the provided message and key
|
||||||
|
verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool {
|
||||||
|
derived_tag: [8]byte
|
||||||
|
sum_bytes_to_buffer_4_8(msg, key, derived_tag[:])
|
||||||
|
return crypto.compare_constant_time(derived_tag[:], tag) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_4_8 :: proc {
|
||||||
|
verify_bytes_4_8,
|
||||||
|
verify_u64_4_8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Low level API
|
||||||
|
*/
|
||||||
|
|
||||||
|
init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
|
||||||
|
assert(len(key) == KEY_SIZE, "crypto/siphash: Invalid key size, want 16")
|
||||||
|
ctx.c_rounds = c_rounds
|
||||||
|
ctx.d_rounds = d_rounds
|
||||||
|
is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) ||
|
||||||
|
(ctx.c_rounds == 2 && ctx.d_rounds == 4) ||
|
||||||
|
(ctx.c_rounds == 4 && ctx.d_rounds == 8)
|
||||||
|
assert(is_valid_setting, "crypto/siphash: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)")
|
||||||
|
ctx.k0 = util.U64_LE(key[:8])
|
||||||
|
ctx.k1 = util.U64_LE(key[8:])
|
||||||
|
ctx.v0 = 0x736f6d6570736575 ~ ctx.k0
|
||||||
|
ctx.v1 = 0x646f72616e646f6d ~ ctx.k1
|
||||||
|
ctx.v2 = 0x6c7967656e657261 ~ ctx.k0
|
||||||
|
ctx.v3 = 0x7465646279746573 ~ ctx.k1
|
||||||
|
ctx.is_initialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
update :: proc(ctx: ^Context, data: []byte) {
|
||||||
|
assert(ctx.is_initialized, "crypto/siphash: Context is not initalized")
|
||||||
|
ctx.last_block = len(data) / 8 * 8
|
||||||
|
ctx.buf = data
|
||||||
|
i := 0
|
||||||
|
m: u64
|
||||||
|
for i < ctx.last_block {
|
||||||
|
m = u64(ctx.buf[i] & 0xff)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
for r in u64(1)..<8 {
|
||||||
|
m |= u64(ctx.buf[i] & 0xff) << (r * 8)
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.v3 ~= m
|
||||||
|
for _ in 0..<ctx.c_rounds {
|
||||||
|
_compress(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.v0 ~= m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final :: proc(ctx: ^Context, dst: ^u64) {
|
||||||
|
m: u64
|
||||||
|
for i := len(ctx.buf) - 1; i >= ctx.last_block; i -= 1 {
|
||||||
|
m <<= 8
|
||||||
|
m |= u64(ctx.buf[i] & 0xff)
|
||||||
|
}
|
||||||
|
m |= u64(len(ctx.buf) << 56)
|
||||||
|
|
||||||
|
ctx.v3 ~= m
|
||||||
|
|
||||||
|
for _ in 0..<ctx.c_rounds {
|
||||||
|
_compress(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.v0 ~= m
|
||||||
|
ctx.v2 ~= 0xff
|
||||||
|
|
||||||
|
for _ in 0..<ctx.d_rounds {
|
||||||
|
_compress(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst^ = ctx.v0 ~ ctx.v1 ~ ctx.v2 ~ ctx.v3
|
||||||
|
|
||||||
|
reset(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
reset :: proc(ctx: ^Context) {
|
||||||
|
ctx.k0, ctx.k1 = 0, 0
|
||||||
|
ctx.v0, ctx.v1 = 0, 0
|
||||||
|
ctx.v2, ctx.v3 = 0, 0
|
||||||
|
ctx.last_block = 0
|
||||||
|
ctx.c_rounds = 0
|
||||||
|
ctx.d_rounds = 0
|
||||||
|
ctx.is_initialized = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Context :: struct {
|
||||||
|
v0, v1, v2, v3: u64, // State values
|
||||||
|
k0, k1: u64, // Split key
|
||||||
|
c_rounds: int, // Number of message rounds
|
||||||
|
d_rounds: int, // Number of finalization rounds
|
||||||
|
buf: []byte, // Provided data
|
||||||
|
last_block: int, // Offset from the last block
|
||||||
|
is_initialized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byte {
|
||||||
|
return byte(into >> (((~byte_num) & (size_of(u64) - 1)) << 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_output :: #force_inline proc "contextless" (dst: []byte, hash: u64) {
|
||||||
|
dst[0] = _get_byte(7, hash)
|
||||||
|
dst[1] = _get_byte(6, hash)
|
||||||
|
dst[2] = _get_byte(5, hash)
|
||||||
|
dst[3] = _get_byte(4, hash)
|
||||||
|
dst[4] = _get_byte(3, hash)
|
||||||
|
dst[5] = _get_byte(2, hash)
|
||||||
|
dst[6] = _get_byte(1, hash)
|
||||||
|
dst[7] = _get_byte(0, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
_compress :: #force_inline proc "contextless" (ctx: ^Context) {
|
||||||
|
ctx.v0 += ctx.v1
|
||||||
|
ctx.v1 = util.ROTL64(ctx.v1, 13)
|
||||||
|
ctx.v1 ~= ctx.v0
|
||||||
|
ctx.v0 = util.ROTL64(ctx.v0, 32)
|
||||||
|
ctx.v2 += ctx.v3
|
||||||
|
ctx.v3 = util.ROTL64(ctx.v3, 16)
|
||||||
|
ctx.v3 ~= ctx.v2
|
||||||
|
ctx.v0 += ctx.v3
|
||||||
|
ctx.v3 = util.ROTL64(ctx.v3, 21)
|
||||||
|
ctx.v3 ~= ctx.v0
|
||||||
|
ctx.v2 += ctx.v1
|
||||||
|
ctx.v1 = util.ROTL64(ctx.v1, 17)
|
||||||
|
ctx.v1 ~= ctx.v2
|
||||||
|
ctx.v2 = util.ROTL64(ctx.v2, 32)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build linux, darwin, freebsd
|
// +build linux, darwin, freebsd, openbsd
|
||||||
package dynlib
|
package dynlib
|
||||||
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
read_value :: proc(r: ^Reader, $T: typeid) -> (value: T, err: Read_Error) {
|
read_value :: proc(r: ^Reader, $T: typeid) -> (value: T, err: Read_Error) {
|
||||||
remaining := len(r.data) - r.offset
|
remaining := len(r.data) - r.offset
|
||||||
if remaining < size_of(T) {
|
if remaining < size_of(T) {
|
||||||
|
if r.print_error {
|
||||||
|
fmt.eprintf("file '%s' failed to read value at offset %v\n", r.filename, r.offset)
|
||||||
|
}
|
||||||
err = .Short_Read
|
err = .Short_Read
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -51,6 +54,10 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
read_array :: proc(r: ^Reader, $T: typeid, count: int) -> (value: []T, err: Read_Error) {
|
read_array :: proc(r: ^Reader, $T: typeid, count: int) -> (value: []T, err: Read_Error) {
|
||||||
remaining := len(r.data) - r.offset
|
remaining := len(r.data) - r.offset
|
||||||
if remaining < size_of(T)*count {
|
if remaining < size_of(T)*count {
|
||||||
|
if r.print_error {
|
||||||
|
fmt.eprintf("file '%s' failed to read array of %d elements at offset %v\n",
|
||||||
|
r.filename, count, r.offset)
|
||||||
|
}
|
||||||
err = .Short_Read
|
err = .Short_Read
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -82,7 +89,8 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
type := read_value(r, Meta_Value_Type) or_return
|
type := read_value(r, Meta_Value_Type) or_return
|
||||||
if type > max(Meta_Value_Type) {
|
if type > max(Meta_Value_Type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is ", r.filename, u8(type), u8(max(Meta_Value_Type)))
|
fmt.eprintf("HxA Error: file '%s' has meta value type %d. Maximum value is %d\n",
|
||||||
|
r.filename, u8(type), u8(max(Meta_Value_Type)))
|
||||||
}
|
}
|
||||||
err = .Invalid_Data
|
err = .Invalid_Data
|
||||||
return
|
return
|
||||||
@@ -114,7 +122,8 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
type := read_value(r, Layer_Data_Type) or_return
|
type := read_value(r, Layer_Data_Type) or_return
|
||||||
if type > max(type) {
|
if type > max(type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is ", r.filename, u8(type), u8(max(Layer_Data_Type)))
|
fmt.eprintf("HxA Error: file '%s' has layer data type %d. Maximum value is %d\n",
|
||||||
|
r.filename, u8(type), u8(max(Layer_Data_Type)))
|
||||||
}
|
}
|
||||||
err = .Invalid_Data
|
err = .Invalid_Data
|
||||||
return
|
return
|
||||||
@@ -134,13 +143,23 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(data) < size_of(Header) {
|
if len(data) < size_of(Header) {
|
||||||
|
if print_error {
|
||||||
|
fmt.eprintf("HxA Error: file '%s' has no header\n", filename)
|
||||||
|
}
|
||||||
|
err = .Short_Read
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
header := cast(^Header)raw_data(data)
|
header := cast(^Header)raw_data(data)
|
||||||
assert(header.magic_number == MAGIC_NUMBER)
|
if (header.magic_number != MAGIC_NUMBER) {
|
||||||
|
if print_error {
|
||||||
|
fmt.eprintf("HxA Error: file '%s' has invalid magic number 0x%x\n", filename, header.magic_number)
|
||||||
|
}
|
||||||
|
err = .Invalid_Data
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r := &Reader{
|
r := &Reader{
|
||||||
filename = filename,
|
filename = filename,
|
||||||
@@ -150,6 +169,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
}
|
}
|
||||||
|
|
||||||
node_count := 0
|
node_count := 0
|
||||||
|
file.header = header^
|
||||||
file.nodes = make([]Node, header.internal_node_count)
|
file.nodes = make([]Node, header.internal_node_count)
|
||||||
defer if err != nil {
|
defer if err != nil {
|
||||||
nodes_destroy(file.nodes)
|
nodes_destroy(file.nodes)
|
||||||
@@ -162,7 +182,8 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato
|
|||||||
type := read_value(r, Node_Type) or_return
|
type := read_value(r, Node_Type) or_return
|
||||||
if type > max(Node_Type) {
|
if type > max(Node_Type) {
|
||||||
if r.print_error {
|
if r.print_error {
|
||||||
fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is ", r.filename, u8(type), u8(max(Node_Type)))
|
fmt.eprintf("HxA Error: file '%s' has node type %d. Maximum value is %d\n",
|
||||||
|
r.filename, u8(type), u8(max(Node_Type)))
|
||||||
}
|
}
|
||||||
err = .Invalid_Data
|
err = .Invalid_Data
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ write_internal :: proc(w: ^Writer, file: File) {
|
|||||||
|
|
||||||
write_metadata :: proc(w: ^Writer, meta_data: []Meta) {
|
write_metadata :: proc(w: ^Writer, meta_data: []Meta) {
|
||||||
for m in meta_data {
|
for m in meta_data {
|
||||||
name_len := max(len(m.name), 255)
|
name_len := min(len(m.name), 255)
|
||||||
write_value(w, u8(name_len))
|
write_value(w, u8(name_len))
|
||||||
write_string(w, m.name[:name_len])
|
write_string(w, m.name[:name_len])
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ write_internal :: proc(w: ^Writer, file: File) {
|
|||||||
write_layer_stack :: proc(w: ^Writer, layers: Layer_Stack) {
|
write_layer_stack :: proc(w: ^Writer, layers: Layer_Stack) {
|
||||||
write_value(w, u32(len(layers)))
|
write_value(w, u32(len(layers)))
|
||||||
for layer in layers {
|
for layer in layers {
|
||||||
name_len := max(len(layer.name), 255)
|
name_len := min(len(layer.name), 255)
|
||||||
write_value(w, u8(name_len))
|
write_value(w, u8(name_len))
|
||||||
write_string(w, layer .name[:name_len])
|
write_string(w, layer .name[:name_len])
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ write_internal :: proc(w: ^Writer, file: File) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
write_value(w, &Header{
|
write_value(w, Header{
|
||||||
magic_number = MAGIC_NUMBER,
|
magic_number = MAGIC_NUMBER,
|
||||||
version = LATEST_VERSION,
|
version = LATEST_VERSION,
|
||||||
internal_node_count = u32le(len(file.nodes)),
|
internal_node_count = u32le(len(file.nodes)),
|
||||||
|
|||||||
@@ -8,17 +8,18 @@ import "core:strings"
|
|||||||
import "core:io"
|
import "core:io"
|
||||||
|
|
||||||
Marshal_Data_Error :: enum {
|
Marshal_Data_Error :: enum {
|
||||||
|
None,
|
||||||
Unsupported_Type,
|
Unsupported_Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
Marshal_Error :: union {
|
Marshal_Error :: union #shared_nil {
|
||||||
Marshal_Data_Error,
|
Marshal_Data_Error,
|
||||||
io.Error,
|
io.Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
|
marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
|
||||||
b := strings.make_builder(allocator)
|
b := strings.make_builder(allocator)
|
||||||
defer if err != .None {
|
defer if err != nil {
|
||||||
strings.destroy_builder(&b)
|
strings.destroy_builder(&b)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: M
|
|||||||
if len(b.buf) != 0 {
|
if len(b.buf) != 0 {
|
||||||
data = b.buf[:]
|
data = b.buf[:]
|
||||||
}
|
}
|
||||||
return data, .None
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
|
||||||
|
|
||||||
|
Author of this Odin package: Jeroen van Rijn
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```odin
|
||||||
|
import "core:encoding/varint"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
buf: [varint.LEB128_MAX_BYTES]u8
|
||||||
|
|
||||||
|
value := u128(42)
|
||||||
|
|
||||||
|
encode_size, encode_err := varint.encode_uleb128(buf[:], value)
|
||||||
|
assert(encode_size == 1 && encode_err == .None)
|
||||||
|
|
||||||
|
fmt.println(buf[:encode_size])
|
||||||
|
|
||||||
|
decoded_val, decode_size, decode_err := varint.decode_uleb128(buf[:encode_size])
|
||||||
|
assert(decoded_val == value && decode_size == encode_size && decode_err == .None)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
*/
|
||||||
|
package varint
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||||
|
Made available under Odin's BSD-3 license.
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
Jeroen van Rijn: Initial implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package varint implements variable length integer encoding and decoding using
|
||||||
|
// the LEB128 format as used by DWARF debug info, Android .dex and other file formats.
|
||||||
|
package varint
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
|
||||||
|
// Instead we'll set limits on the values we'll encode/decode
|
||||||
|
// 18 * 7 bits = 126, which means that a possible 19th byte may at most be `0b0000_0011`.
|
||||||
|
LEB128_MAX_BYTES :: 19
|
||||||
|
|
||||||
|
Error :: enum {
|
||||||
|
None = 0,
|
||||||
|
Buffer_Too_Small = 1,
|
||||||
|
Value_Too_Large = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used.
|
||||||
|
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
|
||||||
|
decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int, err: Error) {
|
||||||
|
more := true
|
||||||
|
|
||||||
|
for v, i in buf {
|
||||||
|
size = i + 1
|
||||||
|
|
||||||
|
// 18 * 7 bits = 126, which means that a possible 19th byte may at most be 0b0000_0011.
|
||||||
|
if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0b0000_0011 {
|
||||||
|
return 0, 0, .Value_Too_Large
|
||||||
|
}
|
||||||
|
|
||||||
|
val |= u128(v & 0x7f) << uint(i * 7)
|
||||||
|
|
||||||
|
if v < 128 {
|
||||||
|
more = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the buffer runs out before the number ends, return an error.
|
||||||
|
if more {
|
||||||
|
return 0, 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used.
|
||||||
|
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 18 bytes.
|
||||||
|
decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int, err: Error) {
|
||||||
|
shift: uint
|
||||||
|
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in buf {
|
||||||
|
size += 1
|
||||||
|
|
||||||
|
// 18 * 7 bits = 126, which including sign means we can have a 19th byte.
|
||||||
|
if size > LEB128_MAX_BYTES || size == LEB128_MAX_BYTES && v > 0x7f {
|
||||||
|
return 0, 0, .Value_Too_Large
|
||||||
|
}
|
||||||
|
|
||||||
|
val |= i128(v & 0x7f) << shift
|
||||||
|
shift += 7
|
||||||
|
|
||||||
|
if v < 128 { break }
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf[size - 1] & 0x40 == 0x40 {
|
||||||
|
val |= max(i128) << shift
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode `val` into `buf` as an unsigned LEB128 encoded series of bytes.
|
||||||
|
// `buf` must be appropriately sized.
|
||||||
|
encode_uleb128 :: proc(buf: []u8, val: u128) -> (size: int, err: Error) {
|
||||||
|
val := val
|
||||||
|
|
||||||
|
for {
|
||||||
|
size += 1
|
||||||
|
|
||||||
|
if size > len(buf) {
|
||||||
|
fmt.println(val, buf[:size - 1])
|
||||||
|
return 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
low := val & 0x7f
|
||||||
|
val >>= 7
|
||||||
|
|
||||||
|
if val > 0 {
|
||||||
|
low |= 0x80 // more bytes to follow
|
||||||
|
}
|
||||||
|
buf[size - 1] = u8(low)
|
||||||
|
|
||||||
|
if val == 0 { break }
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
SIGN_MASK :: (i128(1) << 121) // sign extend mask
|
||||||
|
|
||||||
|
// Encode `val` into `buf` as a signed LEB128 encoded series of bytes.
|
||||||
|
// `buf` must be appropriately sized.
|
||||||
|
encode_ileb128 :: proc(buf: []u8, val: i128) -> (size: int, err: Error) {
|
||||||
|
val := val
|
||||||
|
more := true
|
||||||
|
|
||||||
|
for more {
|
||||||
|
size += 1
|
||||||
|
|
||||||
|
if size > len(buf) {
|
||||||
|
return 0, .Buffer_Too_Small
|
||||||
|
}
|
||||||
|
|
||||||
|
low := val & 0x7f
|
||||||
|
val >>= 7
|
||||||
|
|
||||||
|
low = (low ~ SIGN_MASK) - SIGN_MASK
|
||||||
|
|
||||||
|
if (val == 0 && low & 0x40 != 0x40) || (val == -1 && low & 0x40 == 0x40) {
|
||||||
|
more = false
|
||||||
|
} else {
|
||||||
|
low |= 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[size - 1] = u8(low)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
+224
-214
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -151,7 +151,7 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
|
|||||||
k1 ~= u32(tail[2]) << 16
|
k1 ~= u32(tail[2]) << 16
|
||||||
fallthrough
|
fallthrough
|
||||||
case 2:
|
case 2:
|
||||||
k1 ~= u32(tail[2]) << 8
|
k1 ~= u32(tail[1]) << 8
|
||||||
fallthrough
|
fallthrough
|
||||||
case 1:
|
case 1:
|
||||||
k1 ~= u32(tail[0])
|
k1 ~= u32(tail[0])
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ Option :: enum {
|
|||||||
}
|
}
|
||||||
Options :: distinct bit_set[Option]
|
Options :: distinct bit_set[Option]
|
||||||
|
|
||||||
Error :: union {
|
Error :: union #shared_nil {
|
||||||
General_Image_Error,
|
General_Image_Error,
|
||||||
PNG_Error,
|
PNG_Error,
|
||||||
|
|
||||||
@@ -137,6 +137,7 @@ General_Image_Error :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PNG_Error :: enum {
|
PNG_Error :: enum {
|
||||||
|
None = 0,
|
||||||
Invalid_PNG_Signature,
|
Invalid_PNG_Signature,
|
||||||
IHDR_Not_First_Chunk,
|
IHDR_Not_First_Chunk,
|
||||||
IHDR_Corrupt,
|
IHDR_Corrupt,
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode: int = 0
|
mode: int = 0
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
|
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
|
||||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -439,18 +439,18 @@ when false {
|
|||||||
flags: int = O_WRONLY|O_CREATE|O_TRUNC
|
flags: int = O_WRONLY|O_CREATE|O_TRUNC
|
||||||
|
|
||||||
if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
|
if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
|
||||||
return E_PNG.Invalid_Image_Dimensions
|
return .Invalid_Image_Dimensions
|
||||||
}
|
}
|
||||||
|
|
||||||
mode: int = 0
|
mode: int = 0
|
||||||
when ODIN_OS == "linux" || ODIN_OS == "darwin" {
|
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
|
||||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, fderr := open(filename, flags, mode)
|
fd, fderr := open(filename, flags, mode)
|
||||||
if fderr != 0 {
|
if fderr != 0 {
|
||||||
return E_General.Cannot_Open_File
|
return .Cannot_Open_File
|
||||||
}
|
}
|
||||||
defer close(fd)
|
defer close(fd)
|
||||||
|
|
||||||
@@ -473,7 +473,7 @@ when false {
|
|||||||
case 3: ihdr.color_type = Color_Type{.Color}
|
case 3: ihdr.color_type = Color_Type{.Color}
|
||||||
case 4: ihdr.color_type = Color_Type{.Color, .Alpha}
|
case 4: ihdr.color_type = Color_Type{.Color, .Alpha}
|
||||||
case:// Unhandled
|
case:// Unhandled
|
||||||
return E_PNG.Unknown_Color_Type
|
return .Unknown_Color_Type
|
||||||
}
|
}
|
||||||
h := make_chunk(ihdr, .IHDR)
|
h := make_chunk(ihdr, .IHDR)
|
||||||
write_chunk(fd, h)
|
write_chunk(fd, h)
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) ---
|
|||||||
mem_zero :: proc(ptr: rawptr, len: int) ---
|
mem_zero :: proc(ptr: rawptr, len: int) ---
|
||||||
mem_zero_volatile :: proc(ptr: rawptr, len: int) ---
|
mem_zero_volatile :: proc(ptr: rawptr, len: int) ---
|
||||||
|
|
||||||
|
unaligned_load :: proc(src: ^$T) -> T ---
|
||||||
|
unaligned_store :: proc(dst: ^$T, val: T) -> T ---
|
||||||
|
|
||||||
fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
|
fixed_point_mul :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
|
||||||
fixed_point_div :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
|
fixed_point_div :: proc(lhs, rhs: $T, #const scale: uint) -> T where type_is_integer(T) ---
|
||||||
@@ -60,77 +62,46 @@ syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr ---
|
|||||||
|
|
||||||
|
|
||||||
// Atomics
|
// Atomics
|
||||||
atomic_fence :: proc() ---
|
Atomic_Memory_Order :: enum {
|
||||||
atomic_fence_acq :: proc() ---
|
Relaxed = 0, // Unordered
|
||||||
atomic_fence_rel :: proc() ---
|
Consume = 1, // Monotonic
|
||||||
atomic_fence_acqrel :: proc() ---
|
Acquire = 2,
|
||||||
|
Release = 3,
|
||||||
|
Acq_Rel = 4,
|
||||||
|
Seq_Cst = 5,
|
||||||
|
}
|
||||||
|
|
||||||
atomic_store :: proc(dst: ^$T, val: T) ---
|
atomic_type_is_lock_free :: proc($T: typeid) -> bool ---
|
||||||
atomic_store_rel :: proc(dst: ^$T, val: T) ---
|
|
||||||
atomic_store_relaxed :: proc(dst: ^$T, val: T) ---
|
atomic_thread_fence :: proc(order: Atomic_Memory_Order) ---
|
||||||
atomic_store_unordered :: proc(dst: ^$T, val: T) ---
|
atomic_signal_fence :: proc(order: Atomic_Memory_Order) ---
|
||||||
|
|
||||||
|
atomic_store :: proc(dst: ^$T, val: T) ---
|
||||||
|
atomic_store_explicit :: proc(dst: ^$T, val: T, order: Atomic_Memory_Order) ---
|
||||||
|
|
||||||
atomic_load :: proc(dst: ^$T) -> T ---
|
atomic_load :: proc(dst: ^$T) -> T ---
|
||||||
atomic_load_acq :: proc(dst: ^$T) -> T ---
|
atomic_load_explicit :: proc(dst: ^$T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_load_relaxed :: proc(dst: ^$T) -> T ---
|
|
||||||
atomic_load_unordered :: proc(dst: ^$T) -> T ---
|
|
||||||
|
|
||||||
atomic_add :: proc(dst; ^$T, val: T) -> T ---
|
atomic_add :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_add_acq :: proc(dst; ^$T, val: T) -> T ---
|
atomic_add_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_add_rel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_sub :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_add_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_sub_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_add_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
atomic_and :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_sub :: proc(dst; ^$T, val: T) -> T ---
|
atomic_and_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_sub_acq :: proc(dst; ^$T, val: T) -> T ---
|
atomic_nand :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_sub_rel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_nand_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_sub_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_or :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_sub_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
atomic_or_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_and :: proc(dst; ^$T, val: T) -> T ---
|
atomic_xor :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_and_acq :: proc(dst; ^$T, val: T) -> T ---
|
atomic_xor_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_and_rel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_exchange :: proc(dst; ^$T, val: T) -> T ---
|
||||||
atomic_and_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_exchange_explicit :: proc(dst; ^$T, val: T, order: Atomic_Memory_Order) -> T ---
|
||||||
atomic_and_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_nand :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_nand_acq :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_nand_rel :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_nand_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_nand_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_or :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_or_acq :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_or_rel :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_or_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_or_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_xor :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_xor_acq :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_xor_rel :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_xor_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
atomic_xor_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
|
|
||||||
atomic_xchg :: proc(dst; ^$T, val: T) -> T ---
|
atomic_compare_exchange_strong :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
||||||
atomic_xchg_acq :: proc(dst; ^$T, val: T) -> T ---
|
atomic_compare_exchange_strong_explicit :: proc(dst: ^$T, old, new: T, success, failure: Atomic_Memory_Order) -> (T, bool) #optional_ok ---
|
||||||
atomic_xchg_rel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_compare_exchange_weak :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
||||||
atomic_xchg_acqrel :: proc(dst; ^$T, val: T) -> T ---
|
atomic_compare_exchange_weak_explicit :: proc(dst: ^$T, old, new: T, success, failure: Atomic_Memory_Order) -> (T, bool) #optional_ok ---
|
||||||
atomic_xchg_relaxed :: proc(dst; ^$T, val: T) -> T ---
|
|
||||||
|
|
||||||
atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
|
|
||||||
atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, bool) #optional_ok ---
|
|
||||||
|
|
||||||
// Constant type tests
|
// Constant type tests
|
||||||
|
|
||||||
@@ -199,6 +170,10 @@ type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, raw
|
|||||||
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
||||||
|
|
||||||
|
|
||||||
|
// WASM targets only
|
||||||
|
wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
|
||||||
|
wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||||
|
|
||||||
// Internal compiler use only
|
// Internal compiler use only
|
||||||
|
|
||||||
__entry_point :: proc() ---
|
__entry_point :: proc() ---
|
||||||
@@ -172,7 +172,7 @@ Error :: enum int {
|
|||||||
Unimplemented = 127,
|
Unimplemented = 127,
|
||||||
}
|
}
|
||||||
|
|
||||||
Error_String :: #partial [Error]string{
|
Error_String :: #sparse[Error]string{
|
||||||
.Okay = "Okay",
|
.Okay = "Okay",
|
||||||
.Out_Of_Memory = "Out of memory",
|
.Out_Of_Memory = "Out of memory",
|
||||||
.Invalid_Pointer = "Invalid pointer",
|
.Invalid_Pointer = "Invalid pointer",
|
||||||
@@ -182,6 +182,7 @@ Error_String :: #partial [Error]string{
|
|||||||
.Max_Iterations_Reached = "Max iterations reached",
|
.Max_Iterations_Reached = "Max iterations reached",
|
||||||
.Buffer_Overflow = "Buffer overflow",
|
.Buffer_Overflow = "Buffer overflow",
|
||||||
.Integer_Overflow = "Integer overflow",
|
.Integer_Overflow = "Integer overflow",
|
||||||
|
.Integer_Underflow = "Integer underflow",
|
||||||
|
|
||||||
.Division_by_Zero = "Division by zero",
|
.Division_by_Zero = "Division by zero",
|
||||||
.Math_Domain_Error = "Math domain error",
|
.Math_Domain_Error = "Math domain error",
|
||||||
|
|||||||
@@ -0,0 +1,483 @@
|
|||||||
|
// easing procedures and flux easing used for animations
|
||||||
|
package ease
|
||||||
|
|
||||||
|
import "core:math"
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:time"
|
||||||
|
|
||||||
|
@(private) PI_2 :: math.PI / 2
|
||||||
|
|
||||||
|
// converted to odin from https://github.com/warrenm/AHEasing
|
||||||
|
// with additional enum based call
|
||||||
|
|
||||||
|
// Modeled after the parabola y = x^2
|
||||||
|
quadratic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p * p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the parabola y = -x^2 + 2x
|
||||||
|
quadratic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return -(p * (p - 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise quadratic
|
||||||
|
// y = (1/2)((2x)^2) ; [0, 0.5)
|
||||||
|
// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
|
||||||
|
quadratic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 2 * p * p
|
||||||
|
} else {
|
||||||
|
return (-2 * p * p) + (4 * p) - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the cubic y = x^3
|
||||||
|
cubic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p * p * p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the cubic y = (x - 1)^3 + 1
|
||||||
|
cubic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
f := p - 1
|
||||||
|
return f * f * f + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise cubic
|
||||||
|
// y = (1/2)((2x)^3) ; [0, 0.5)
|
||||||
|
// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
|
||||||
|
cubic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 4 * p * p * p
|
||||||
|
} else {
|
||||||
|
f := (2 * p) - 2
|
||||||
|
return 0.5 * f * f * f + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the quartic x^4
|
||||||
|
quartic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p * p * p * p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the quartic y = 1 - (x - 1)^4
|
||||||
|
quartic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
f := p - 1
|
||||||
|
return f * f * f * (1 - p) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise quartic
|
||||||
|
// y = (1/2)((2x)^4) ; [0, 0.5)
|
||||||
|
// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
|
||||||
|
quartic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 8 * p * p * p * p
|
||||||
|
} else {
|
||||||
|
f := p - 1
|
||||||
|
return -8 * f * f * f * f + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the quintic y = x^5
|
||||||
|
quintic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p * p * p * p * p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the quintic y = (x - 1)^5 + 1
|
||||||
|
quintic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
f := p - 1
|
||||||
|
return f * f * f * f * f + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise quintic
|
||||||
|
// y = (1/2)((2x)^5) ; [0, 0.5)
|
||||||
|
// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
|
||||||
|
quintic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 16 * p * p * p * p * p
|
||||||
|
} else {
|
||||||
|
f := (2 * p) - 2
|
||||||
|
return 0.5 * f * f * f * f * f + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after quarter-cycle of sine wave
|
||||||
|
sine_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return math.sin((p - 1) * PI_2) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after quarter-cycle of sine wave (different phase)
|
||||||
|
sine_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return math.sin(p * PI_2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after half sine wave
|
||||||
|
sine_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return 0.5 * (1 - math.cos(p * math.PI))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after shifted quadrant IV of unit circle
|
||||||
|
circular_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return 1 - math.sqrt(1 - (p * p))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after shifted quadrant II of unit circle
|
||||||
|
circular_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return math.sqrt((2 - p) * p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise circular function
|
||||||
|
// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5)
|
||||||
|
// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
|
||||||
|
circular_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 0.5 * (1 - math.sqrt(1 - 4 * (p * p)))
|
||||||
|
} else {
|
||||||
|
return 0.5 * (math.sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the exponential function y = 2^(10(x - 1))
|
||||||
|
exponential_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p == 0.0 ? p : math.pow(2, 10 * (p - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the exponential function y = -2^(-10x) + 1
|
||||||
|
exponential_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p == 1.0 ? p : 1 - math.pow(2, -10 * p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise exponential
|
||||||
|
// y = (1/2)2^(10(2x - 1)) ; [0,0.5)
|
||||||
|
// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
|
||||||
|
exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p == 0.0 || p == 1.0 {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
if p < 0.5 {
|
||||||
|
return 0.5 * math.pow(2, (20 * p) - 10)
|
||||||
|
} else {
|
||||||
|
return -0.5 * math.pow(2, (-20 * p) + 10) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
|
||||||
|
elastic_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return math.sin(13 * PI_2 * p) * math.pow(2, 10 * (p - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
|
||||||
|
elastic_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return math.sin(-13 * PI_2 * (p + 1)) * math.pow(2, -10 * p) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise exponentially-damped sine wave:
|
||||||
|
// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5)
|
||||||
|
// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
|
||||||
|
elastic_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 0.5 * math.sin(13 * PI_2 * (2 * p)) * math.pow(2, 10 * ((2 * p) - 1))
|
||||||
|
} else {
|
||||||
|
return 0.5 * (math.sin(-13 * PI_2 * ((2 * p - 1) + 1)) * math.pow(2, -10 * (2 * p - 1)) + 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
|
||||||
|
back_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return p * p * p - p * math.sin(p * math.PI)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
|
||||||
|
back_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
f := 1 - p
|
||||||
|
return 1 - (f * f * f - f * math.sin(f * math.PI))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modeled after the piecewise overshooting cubic function:
|
||||||
|
// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5)
|
||||||
|
// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
|
||||||
|
back_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
f := 2 * p
|
||||||
|
return 0.5 * (f * f * f - f * math.sin(f * math.PI))
|
||||||
|
} else {
|
||||||
|
f := (1 - (2*p - 1))
|
||||||
|
return 0.5 * (1 - (f * f * f - f * math.sin(f * math.PI))) + 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce_in :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
return 1 - bounce_out(1 - p)
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 4/11.0 {
|
||||||
|
return (121 * p * p)/16.0
|
||||||
|
} else if p < 8/11.0 {
|
||||||
|
return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0
|
||||||
|
} else if p < 9/10.0 {
|
||||||
|
return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0
|
||||||
|
} else {
|
||||||
|
return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bounce_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
|
||||||
|
if p < 0.5 {
|
||||||
|
return 0.5 * bounce_in(p*2)
|
||||||
|
} else {
|
||||||
|
return 0.5 * bounce_out(p * 2 - 1) + 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional enum variant
|
||||||
|
|
||||||
|
Ease :: enum {
|
||||||
|
Linear,
|
||||||
|
|
||||||
|
Quadratic_In,
|
||||||
|
Quadratic_Out,
|
||||||
|
Quadratic_In_Out,
|
||||||
|
|
||||||
|
Cubic_In,
|
||||||
|
Cubic_Out,
|
||||||
|
Cubic_In_Out,
|
||||||
|
|
||||||
|
Quartic_In,
|
||||||
|
Quartic_Out,
|
||||||
|
Quartic_In_Out,
|
||||||
|
|
||||||
|
Quintic_In,
|
||||||
|
Quintic_Out,
|
||||||
|
Quintic_In_Out,
|
||||||
|
|
||||||
|
Sine_In,
|
||||||
|
Sine_Out,
|
||||||
|
Sine_In_Out,
|
||||||
|
|
||||||
|
Circular_In,
|
||||||
|
Circular_Out,
|
||||||
|
Circular_In_Out,
|
||||||
|
|
||||||
|
Exponential_In,
|
||||||
|
Exponential_Out,
|
||||||
|
Exponential_In_Out,
|
||||||
|
|
||||||
|
Elastic_In,
|
||||||
|
Elastic_Out,
|
||||||
|
Elastic_In_Out,
|
||||||
|
|
||||||
|
Back_In,
|
||||||
|
Back_Out,
|
||||||
|
Back_In_Out,
|
||||||
|
|
||||||
|
Bounce_In,
|
||||||
|
Bounce_Out,
|
||||||
|
Bounce_In_Out,
|
||||||
|
}
|
||||||
|
|
||||||
|
ease :: proc "contextless" (type: Ease, p: $T) -> T
|
||||||
|
where intrinsics.type_is_float(T) {
|
||||||
|
switch type {
|
||||||
|
case .Linear: return p
|
||||||
|
|
||||||
|
case .Quadratic_In: return quadratic_in(p)
|
||||||
|
case .Quadratic_Out: return quadratic_out(p)
|
||||||
|
case .Quadratic_In_Out: return quadratic_in_out(p)
|
||||||
|
|
||||||
|
case .Cubic_In: return cubic_in(p)
|
||||||
|
case .Cubic_Out: return cubic_out(p)
|
||||||
|
case .Cubic_In_Out: return cubic_in_out(p)
|
||||||
|
|
||||||
|
case .Quartic_In: return quartic_in(p)
|
||||||
|
case .Quartic_Out: return quartic_out(p)
|
||||||
|
case .Quartic_In_Out: return quartic_in_out(p)
|
||||||
|
|
||||||
|
case .Quintic_In: return quintic_in(p)
|
||||||
|
case .Quintic_Out: return quintic_out(p)
|
||||||
|
case .Quintic_In_Out: return quintic_in_out(p)
|
||||||
|
|
||||||
|
case .Sine_In: return sine_in(p)
|
||||||
|
case .Sine_Out: return sine_out(p)
|
||||||
|
case .Sine_In_Out: return sine_in_out(p)
|
||||||
|
|
||||||
|
case .Circular_In: return circular_in(p)
|
||||||
|
case .Circular_Out: return circular_out(p)
|
||||||
|
case .Circular_In_Out: return circular_in_out(p)
|
||||||
|
|
||||||
|
case .Exponential_In: return exponential_in(p)
|
||||||
|
case .Exponential_Out: return exponential_out(p)
|
||||||
|
case .Exponential_In_Out: return exponential_in_out(p)
|
||||||
|
|
||||||
|
case .Elastic_In: return elastic_in(p)
|
||||||
|
case .Elastic_Out: return elastic_out(p)
|
||||||
|
case .Elastic_In_Out: return elastic_in_out(p)
|
||||||
|
|
||||||
|
case .Back_In: return back_in(p)
|
||||||
|
case .Back_Out: return back_out(p)
|
||||||
|
case .Back_In_Out: return back_in_out(p)
|
||||||
|
|
||||||
|
case .Bounce_In: return bounce_in(p)
|
||||||
|
case .Bounce_Out: return bounce_out(p)
|
||||||
|
case .Bounce_In_Out: return bounce_in_out(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case type was invalid
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Flux_Map :: struct($T: typeid) {
|
||||||
|
values: map[^T]Flux_Tween(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
Flux_Tween :: struct($T: typeid) {
|
||||||
|
value: ^T,
|
||||||
|
start: T,
|
||||||
|
diff: T,
|
||||||
|
goal: T,
|
||||||
|
|
||||||
|
delay: f64, // in seconds
|
||||||
|
duration: time.Duration,
|
||||||
|
|
||||||
|
progress: f64,
|
||||||
|
rate: f64,
|
||||||
|
type: Ease,
|
||||||
|
|
||||||
|
inited: bool,
|
||||||
|
|
||||||
|
// callbacks, data can be set, will be pushed to callback
|
||||||
|
data: rawptr, // by default gets set to value input
|
||||||
|
on_start: proc(flux: ^Flux_Map(T), data: rawptr),
|
||||||
|
on_update: proc(flux: ^Flux_Map(T), data: rawptr),
|
||||||
|
on_complete: proc(flux: ^Flux_Map(T), data: rawptr),
|
||||||
|
}
|
||||||
|
|
||||||
|
// init flux map to a float type and a wanted cap
|
||||||
|
flux_init :: proc($T: typeid, cap := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
|
||||||
|
return {
|
||||||
|
make(map[^T]Flux_Tween(T), cap),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete map content
|
||||||
|
flux_destroy :: proc(flux: Flux_Map($T)) where intrinsics.type_is_float(T) {
|
||||||
|
delete(flux.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear map content, stops all animations
|
||||||
|
flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
|
||||||
|
clear(&flux.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// append / overwrite existing tween value to parameters
|
||||||
|
// rest is initialized in flux_tween_init, inside update
|
||||||
|
// return value can be used to set callbacks
|
||||||
|
flux_to :: proc(
|
||||||
|
flux: ^Flux_Map($T),
|
||||||
|
value: ^f32,
|
||||||
|
goal: f32,
|
||||||
|
type: Ease = .Quadratic_Out,
|
||||||
|
duration: time.Duration = time.Second,
|
||||||
|
delay: f64 = 0,
|
||||||
|
) -> (tween: ^Flux_Tween(T)) where intrinsics.type_is_float(T) {
|
||||||
|
if res, ok := &flux.values[value]; ok {
|
||||||
|
tween = res
|
||||||
|
} else {
|
||||||
|
flux.values[value] = {}
|
||||||
|
tween = &flux.values[value]
|
||||||
|
}
|
||||||
|
|
||||||
|
tween^ = {
|
||||||
|
value = value,
|
||||||
|
goal = goal,
|
||||||
|
duration = duration,
|
||||||
|
delay = delay,
|
||||||
|
type = type,
|
||||||
|
data = value,
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init internal properties
|
||||||
|
flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where intrinsics.type_is_float(T) {
|
||||||
|
tween.inited = true
|
||||||
|
tween.start = tween.value^
|
||||||
|
tween.diff = tween.goal - tween.value^
|
||||||
|
s := time.duration_seconds(duration)
|
||||||
|
tween.rate = duration > 0 ? 1.0 / s : 0
|
||||||
|
tween.progress = duration > 0 ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// update all tweens, wait for their delay if one exists
|
||||||
|
// calls callbacks in all stages, when they're filled
|
||||||
|
// deletes tween from the map after completion
|
||||||
|
flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) {
|
||||||
|
for key, tween in &flux.values {
|
||||||
|
delay_remainder := f64(0)
|
||||||
|
|
||||||
|
// Update delay if necessary.
|
||||||
|
if tween.delay > 0 {
|
||||||
|
tween.delay -= dt
|
||||||
|
|
||||||
|
if tween.delay < 0 {
|
||||||
|
// We finished the delay, but in doing so consumed part of this frame's `dt` budget.
|
||||||
|
// Keep track of it so we can apply it to this tween without affecting others.
|
||||||
|
delay_remainder = tween.delay
|
||||||
|
// We're done with this delay.
|
||||||
|
tween.delay = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We either had no delay, or the delay has been consumed.
|
||||||
|
if tween.delay <= 0 {
|
||||||
|
if !tween.inited {
|
||||||
|
flux_tween_init(&tween, tween.duration)
|
||||||
|
|
||||||
|
if tween.on_start != nil {
|
||||||
|
tween.on_start(flux, tween.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If part of the `dt` budget was consumed this frame, then `delay_remainder` will be
|
||||||
|
// that remainder, a negative value. Adding it to `dt` applies what's left of the `dt`
|
||||||
|
// to the tween so it advances properly, instead of too much or little.
|
||||||
|
tween.progress += tween.rate * (dt + delay_remainder)
|
||||||
|
x := tween.progress >= 1 ? 1 : ease(tween.type, tween.progress)
|
||||||
|
tween.value^ = tween.start + tween.diff * T(x)
|
||||||
|
|
||||||
|
if tween.on_update != nil {
|
||||||
|
tween.on_update(flux, tween.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tween.progress >= 1 {
|
||||||
|
delete_key(&flux.values, key)
|
||||||
|
|
||||||
|
if tween.on_complete != nil {
|
||||||
|
tween.on_complete(flux, tween.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop a specific key inside the map
|
||||||
|
// returns true when it successfully removed the key
|
||||||
|
flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
|
||||||
|
if key in flux.values {
|
||||||
|
delete_key(&flux.values, key)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the amount of time left for the tween animation, if the key exists in the map
|
||||||
|
// returns 0 if the tween doesnt exist on the map
|
||||||
|
flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 {
|
||||||
|
if tween, ok := flux.values[key]; ok {
|
||||||
|
return ((1 - tween.progress) * tween.rate) + tween.delay
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
-6
@@ -396,7 +396,7 @@ trunc_f16 :: proc "contextless" (x: f16) -> f16 {
|
|||||||
e := (x >> shift) & mask - bias
|
e := (x >> shift) & mask - bias
|
||||||
|
|
||||||
if e < shift {
|
if e < shift {
|
||||||
x &= ~(1 << (shift-e)) - 1
|
x &~= 1 << (shift-e) - 1
|
||||||
}
|
}
|
||||||
return transmute(f16)x
|
return transmute(f16)x
|
||||||
}
|
}
|
||||||
@@ -428,7 +428,7 @@ trunc_f32 :: proc "contextless" (x: f32) -> f32 {
|
|||||||
e := (x >> shift) & mask - bias
|
e := (x >> shift) & mask - bias
|
||||||
|
|
||||||
if e < shift {
|
if e < shift {
|
||||||
x &= ~(1 << (shift-e)) - 1
|
x &~= 1 << (shift-e) - 1
|
||||||
}
|
}
|
||||||
return transmute(f32)x
|
return transmute(f32)x
|
||||||
}
|
}
|
||||||
@@ -460,7 +460,7 @@ trunc_f64 :: proc "contextless" (x: f64) -> f64 {
|
|||||||
e := (x >> shift) & mask - bias
|
e := (x >> shift) & mask - bias
|
||||||
|
|
||||||
if e < shift {
|
if e < shift {
|
||||||
x &= ~(1 << (shift-e)) - 1
|
x &~= 1 << (shift-e) - 1
|
||||||
}
|
}
|
||||||
return transmute(f64)x
|
return transmute(f64)x
|
||||||
}
|
}
|
||||||
@@ -473,6 +473,7 @@ trunc_f64 :: proc "contextless" (x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
trunc_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))) }
|
trunc_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))) }
|
||||||
trunc_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))) }
|
trunc_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))) }
|
||||||
|
// Removes the fractional part of the value, i.e. rounds towards zero.
|
||||||
trunc :: proc{
|
trunc :: proc{
|
||||||
trunc_f16, trunc_f16le, trunc_f16be,
|
trunc_f16, trunc_f16le, trunc_f16be,
|
||||||
trunc_f32, trunc_f32le, trunc_f32be,
|
trunc_f32, trunc_f32le, trunc_f32be,
|
||||||
@@ -958,7 +959,7 @@ classify_f16 :: proc "contextless" (x: f16) -> Float_Class {
|
|||||||
return .Neg_Zero
|
return .Neg_Zero
|
||||||
}
|
}
|
||||||
return .Zero
|
return .Zero
|
||||||
case x*0.5 == x:
|
case x*0.25 == x:
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
return .Neg_Inf
|
return .Neg_Inf
|
||||||
}
|
}
|
||||||
@@ -1027,6 +1028,8 @@ classify_f64 :: proc "contextless" (x: f64) -> Float_Class {
|
|||||||
}
|
}
|
||||||
classify_f64le :: proc "contextless" (x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)) }
|
classify_f64le :: proc "contextless" (x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)) }
|
||||||
classify_f64be :: proc "contextless" (x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)) }
|
classify_f64be :: proc "contextless" (x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)) }
|
||||||
|
// Returns the `Float_Class` of the value, i.e. whether normal, subnormal, zero, negative zero, NaN, infinity or
|
||||||
|
// negative infinity.
|
||||||
classify :: proc{
|
classify :: proc{
|
||||||
classify_f16, classify_f16le, classify_f16be,
|
classify_f16, classify_f16le, classify_f16be,
|
||||||
classify_f32, classify_f32le, classify_f32be,
|
classify_f32, classify_f32le, classify_f32be,
|
||||||
@@ -1203,7 +1206,7 @@ prod :: proc "contextless" (x: $T/[]$E) -> (res: E)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cumsum_inplace :: proc "contextless" (x: $T/[]$E) -> T
|
cumsum_inplace :: proc "contextless" (x: $T/[]$E)
|
||||||
where intrinsics.type_is_numeric(E) {
|
where intrinsics.type_is_numeric(E) {
|
||||||
for i in 1..<len(x) {
|
for i in 1..<len(x) {
|
||||||
x[i] = x[i-1] + x[i]
|
x[i] = x[i-1] + x[i]
|
||||||
@@ -1715,4 +1718,22 @@ F32_BIAS :: 0x7f
|
|||||||
|
|
||||||
F64_MASK :: 0x7ff
|
F64_MASK :: 0x7ff
|
||||||
F64_SHIFT :: 64 - 12
|
F64_SHIFT :: 64 - 12
|
||||||
F64_BIAS :: 0x3ff
|
F64_BIAS :: 0x3ff
|
||||||
|
|
||||||
|
INF_F16 :f16: 0h7C00
|
||||||
|
NEG_INF_F16 :f16: 0hFC00
|
||||||
|
|
||||||
|
SNAN_F16 :f16: 0h7C01
|
||||||
|
QNAN_F16 :f16: 0h7E01
|
||||||
|
|
||||||
|
INF_F32 :f32: 0h7F80_0000
|
||||||
|
NEG_INF_F32 :f32: 0hFF80_0000
|
||||||
|
|
||||||
|
SNAN_F32 :f32: 0hFF80_0001
|
||||||
|
QNAN_F32 :f32: 0hFFC0_0001
|
||||||
|
|
||||||
|
INF_F64 :f64: 0h7FF0_0000_0000_0000
|
||||||
|
NEG_INF_F64 :f64: 0hFFF0_0000_0000_0000
|
||||||
|
|
||||||
|
SNAN_F64 :f64: 0h7FF0_0000_0000_0001
|
||||||
|
QNAN_F64 :f64: 0h7FF8_0000_0000_0001
|
||||||
|
|||||||
@@ -0,0 +1,734 @@
|
|||||||
|
/*
|
||||||
|
OpenSimplex2 noise implementation.
|
||||||
|
|
||||||
|
Ported from https://github.com/KdotJPG/OpenSimplex2.
|
||||||
|
Copyright 2022 Yuki2 (https://github.com/NoahR02)
|
||||||
|
*/
|
||||||
|
//+private
|
||||||
|
package math_noise
|
||||||
|
|
||||||
|
/*
|
||||||
|
Private implementation details follow.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PRIME_X :: i64(0x5205402B9270C86F)
|
||||||
|
PRIME_Y :: i64(0x598CD327003817B5)
|
||||||
|
PRIME_Z :: i64(0x5BCC226E9FA0BACB)
|
||||||
|
PRIME_W :: i64(0x56CC5227E58F554B)
|
||||||
|
|
||||||
|
HASH_MULTIPLIER :: i64(0x53A3F72DEEC546F5)
|
||||||
|
SEED_FLIP_3D :: i64(-0x52D547B2E96ED629)
|
||||||
|
SEED_OFFSET_4D :: i64(0xE83DC3E0DA7164D)
|
||||||
|
|
||||||
|
ROOT_2_OVER_2 :: f64(0.7071067811865476)
|
||||||
|
SKEW_2D :: f64(0.366025403784439)
|
||||||
|
UNSKEW_2D :: f64(-0.21132486540518713)
|
||||||
|
ROOT_3_OVER_3 :: f64(0.577350269189626)
|
||||||
|
|
||||||
|
FALLBACK_ROTATE_3D :: f64(2.0) / f64(3.0)
|
||||||
|
ROTATE_3D_ORTHOGONALIZER :: f64(UNSKEW_2D)
|
||||||
|
|
||||||
|
SKEW_4D :: f32(0hbe0d8369)
|
||||||
|
UNSKEW_4D :: f32(0.309016994374947)
|
||||||
|
LATTICE_STEP_4D :: f32(0.2)
|
||||||
|
|
||||||
|
N_GRADS_2D_EXPONENT :: 7
|
||||||
|
N_GRADS_3D_EXPONENT :: 8
|
||||||
|
N_GRADS_4D_EXPONENT :: 9
|
||||||
|
N_GRADS_2D :: 1 << N_GRADS_2D_EXPONENT
|
||||||
|
N_GRADS_3D :: 1 << N_GRADS_3D_EXPONENT
|
||||||
|
N_GRADS_4D :: 1 << N_GRADS_4D_EXPONENT
|
||||||
|
|
||||||
|
NORMALIZER_2D :: f64(0.01001634121365712)
|
||||||
|
NORMALIZER_3D :: f64(0.07969837668935331)
|
||||||
|
NORMALIZER_4D :: f64(0.0220065933241897)
|
||||||
|
RSQUARED_2D :: f32(0.5)
|
||||||
|
RSQUARED_3D :: f32(0.6)
|
||||||
|
RSQUARED_4D :: f32(0.6)
|
||||||
|
|
||||||
|
GRADIENTS_2D := [N_GRADS_2D * 2]f32{
|
||||||
|
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||||
|
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||||
|
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||||
|
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||||
|
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||||
|
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||||
|
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||||
|
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||||
|
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||||
|
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||||
|
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||||
|
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||||
|
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||||
|
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||||
|
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||||
|
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||||
|
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||||
|
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||||
|
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||||
|
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||||
|
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||||
|
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||||
|
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||||
|
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||||
|
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||||
|
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||||
|
0h4150804d, 0h42c5f72a, 0h42731b78, 0h429e696c, 0h429e696c, 0h42731b78, 0h42c5f72a, 0h4150804d,
|
||||||
|
0h42c5f72a, 0hc150804d, 0h429e696c, 0hc2731b78, 0h42731b78, 0hc29e696c, 0h4150804d, 0hc2c5f72a,
|
||||||
|
0hc150804d, 0hc2c5f72a, 0hc2731b78, 0hc29e696c, 0hc29e696c, 0hc2731b78, 0hc2c5f72a, 0hc150804d,
|
||||||
|
0hc2c5f72a, 0h4150804d, 0hc29e696c, 0h42731b78, 0hc2731b78, 0h429e696c, 0hc150804d, 0h42c5f72a,
|
||||||
|
0h4218d2da, 0h42b87975, 0h42b87975, 0h4218d2da, 0h42b87975, 0hc218d2da, 0h4218d2da, 0hc2b87975,
|
||||||
|
0hc218d2da, 0hc2b87975, 0hc2b87975, 0hc218d2da, 0hc2b87975, 0h4218d2da, 0hc218d2da, 0h42b87975,
|
||||||
|
}
|
||||||
|
|
||||||
|
GRADIENTS_3D := [N_GRADS_3D * 4]f32{
|
||||||
|
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||||
|
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||||
|
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||||
|
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||||
|
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0hc16b5146, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc21ae5b8, 0h00000000, 0hc16b5146, 0h00000000,
|
||||||
|
0hc1df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0hc1df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0hc21ae5b8, 0h00000000, 0h416b5146, 0h00000000, 0hc16b5146, 0h00000000, 0h421ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000,
|
||||||
|
0hc148c1c5, 0h41df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0h41df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc1df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0hc1df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h416b5146, 0hc21ae5b8, 0h00000000, 0h00000000, 0h421ae5b8, 0hc16b5146, 0h00000000, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0hc1df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0hc1df5103, 0h00000000,
|
||||||
|
0h421ae5b8, 0h00000000, 0hc16b5146, 0h00000000, 0h416b5146, 0h00000000, 0hc21ae5b8, 0h00000000,
|
||||||
|
0h41df5103, 0hc148c1c5, 0h41df5103, 0h00000000, 0h41df5103, 0h4148c1c5, 0h41df5103, 0h00000000,
|
||||||
|
0h416b5146, 0h00000000, 0h421ae5b8, 0h00000000, 0h421ae5b8, 0h00000000, 0h416b5146, 0h00000000,
|
||||||
|
0h41df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0h41df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0h421ae5b8, 0h416b5146, 0h00000000, 0h00000000, 0h416b5146, 0h421ae5b8, 0h00000000, 0h00000000,
|
||||||
|
0hc1df5103, 0h41df5103, 0hc148c1c5, 0h00000000, 0hc1df5103, 0h41df5103, 0h4148c1c5, 0h00000000,
|
||||||
|
0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0hc1df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc21ae5b8, 0hc16b5146, 0h00000000, 0h00000000, 0hc16b5146, 0hc21ae5b8, 0h00000000,
|
||||||
|
0hc148c1c5, 0hc1df5103, 0h41df5103, 0h00000000, 0h4148c1c5, 0hc1df5103, 0h41df5103, 0h00000000,
|
||||||
|
0h00000000, 0hc16b5146, 0h421ae5b8, 0h00000000, 0h00000000, 0hc21ae5b8, 0h416b5146, 0h00000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
GRADIENTS_4D := [N_GRADS_4D * 4]f32{
|
||||||
|
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||||
|
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||||
|
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||||
|
0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85,
|
||||||
|
0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee,
|
||||||
|
0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d,
|
||||||
|
0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85,
|
||||||
|
0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee,
|
||||||
|
0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d,
|
||||||
|
0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85,
|
||||||
|
0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee,
|
||||||
|
0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d,
|
||||||
|
0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a,
|
||||||
|
0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a,
|
||||||
|
0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252,
|
||||||
|
0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c,
|
||||||
|
0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c,
|
||||||
|
0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966,
|
||||||
|
0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418,
|
||||||
|
0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c,
|
||||||
|
0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507,
|
||||||
|
0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0,
|
||||||
|
0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c,
|
||||||
|
0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5,
|
||||||
|
0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966,
|
||||||
|
0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716,
|
||||||
|
0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d,
|
||||||
|
0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf,
|
||||||
|
0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0,
|
||||||
|
0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00,
|
||||||
|
0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c,
|
||||||
|
0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5,
|
||||||
|
0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966,
|
||||||
|
0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716,
|
||||||
|
0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0,
|
||||||
|
0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c,
|
||||||
|
0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5,
|
||||||
|
0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966,
|
||||||
|
0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716,
|
||||||
|
0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252,
|
||||||
|
0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a,
|
||||||
|
0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a,
|
||||||
|
0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18,
|
||||||
|
0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d,
|
||||||
|
0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee,
|
||||||
|
0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee,
|
||||||
|
0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670,
|
||||||
|
0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d,
|
||||||
|
0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee,
|
||||||
|
0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee,
|
||||||
|
0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670,
|
||||||
|
0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d,
|
||||||
|
0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee,
|
||||||
|
0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee,
|
||||||
|
0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||||
|
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||||
|
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||||
|
0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85,
|
||||||
|
0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee,
|
||||||
|
0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d,
|
||||||
|
0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85,
|
||||||
|
0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee,
|
||||||
|
0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d,
|
||||||
|
0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85,
|
||||||
|
0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee,
|
||||||
|
0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d,
|
||||||
|
0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a,
|
||||||
|
0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a,
|
||||||
|
0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252,
|
||||||
|
0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c,
|
||||||
|
0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c,
|
||||||
|
0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966,
|
||||||
|
0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418,
|
||||||
|
0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c,
|
||||||
|
0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507,
|
||||||
|
0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0,
|
||||||
|
0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c,
|
||||||
|
0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5,
|
||||||
|
0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966,
|
||||||
|
0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716,
|
||||||
|
0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d,
|
||||||
|
0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf,
|
||||||
|
0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0,
|
||||||
|
0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00,
|
||||||
|
0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c,
|
||||||
|
0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5,
|
||||||
|
0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966,
|
||||||
|
0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716,
|
||||||
|
0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0,
|
||||||
|
0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c,
|
||||||
|
0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5,
|
||||||
|
0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966,
|
||||||
|
0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716,
|
||||||
|
0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252,
|
||||||
|
0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a,
|
||||||
|
0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a,
|
||||||
|
0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18,
|
||||||
|
0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d,
|
||||||
|
0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee,
|
||||||
|
0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee,
|
||||||
|
0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670,
|
||||||
|
0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d,
|
||||||
|
0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee,
|
||||||
|
0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee,
|
||||||
|
0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670,
|
||||||
|
0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d,
|
||||||
|
0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee,
|
||||||
|
0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee,
|
||||||
|
0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||||
|
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||||
|
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||||
|
0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee, 0h40b05c85,
|
||||||
|
0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee,
|
||||||
|
0hc21c1252, 0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d,
|
||||||
|
0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc235739c, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc18a0670, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85,
|
||||||
|
0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0hc19d18ee,
|
||||||
|
0hc1b8e69d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0h40024b8d,
|
||||||
|
0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0hbfc4b564, 0hc235739c, 0hbfc4b564, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc18a0670, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85,
|
||||||
|
0hc19d18ee, 0h40b05c85, 0hc20e2b7a, 0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0hc19d18ee,
|
||||||
|
0hc1b8e69d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0h40024b8d,
|
||||||
|
0h40024b8d, 0h40024b8d, 0hc21c1252, 0hc1b8e69d, 0hbfc4b564, 0hbfc4b564, 0hc235739c, 0hbfc4b564,
|
||||||
|
0hc18a0670, 0hc18a0670, 0hc18a0670, 0hc208ee18, 0hc19d18ee, 0hc19d18ee, 0h40b05c85, 0hc20e2b7a,
|
||||||
|
0hc19d18ee, 0h40b05c85, 0hc19d18ee, 0hc20e2b7a, 0h40b05c85, 0hc19d18ee, 0hc19d18ee, 0hc20e2b7a,
|
||||||
|
0hc1b8e69d, 0h40024b8d, 0h40024b8d, 0hc21c1252, 0h40024b8d, 0hc1b8e69d, 0h40024b8d, 0hc21c1252,
|
||||||
|
0h40024b8d, 0h40024b8d, 0hc1b8e69d, 0hc21c1252, 0hbfc4b564, 0hbfc4b564, 0hbfc4b564, 0hc235739c,
|
||||||
|
0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc19194b0, 0hc208695c, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h406d72bf, 0hc22076c5, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc0de6d7d, 0hc1b6d966, 0h419194b0, 0h4208695c,
|
||||||
|
0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h416b8e00, 0hc1d2a716, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc19194b0, 0h40de6d7d, 0hc208695c, 0h41b6d966,
|
||||||
|
0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h406d72bf, 0h406d72bf, 0hc22076c5, 0h41a58418,
|
||||||
|
0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc0de6d7d, 0h419194b0, 0hc1b6d966, 0h4208695c,
|
||||||
|
0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h416b8e00, 0h416b8e00, 0hc1d2a716, 0h41f50507,
|
||||||
|
0hc16b8e00, 0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc19194b0, 0hc208695c, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0h40de6d7d, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h406d72bf, 0hc22076c5, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc06d72bf, 0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc0de6d7d, 0hc1b6d966, 0h4208695c, 0h419194b0,
|
||||||
|
0h419194b0, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h416b8e00, 0hc1d2a716, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc19194b0, 0h40de6d7d, 0h41b6d966, 0hc208695c,
|
||||||
|
0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h406d72bf, 0h406d72bf, 0h41a58418, 0hc22076c5,
|
||||||
|
0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc0de6d7d, 0h419194b0, 0h4208695c, 0hc1b6d966,
|
||||||
|
0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h416b8e00, 0h416b8e00, 0h41f50507, 0hc1d2a716,
|
||||||
|
0hc16b8e00, 0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc19194b0, 0h41b6d966, 0hc208695c, 0h40de6d7d,
|
||||||
|
0h40de6d7d, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h406d72bf, 0h41a58418, 0hc22076c5, 0h406d72bf,
|
||||||
|
0hc06d72bf, 0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc0de6d7d, 0h4208695c, 0hc1b6d966, 0h419194b0,
|
||||||
|
0h419194b0, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h416b8e00, 0h41f50507, 0hc1d2a716, 0h416b8e00,
|
||||||
|
0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc19194b0, 0h41b6d966, 0h40de6d7d, 0hc208695c,
|
||||||
|
0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h406d72bf, 0h41a58418, 0h406d72bf, 0hc22076c5,
|
||||||
|
0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc0de6d7d, 0h4208695c, 0h419194b0, 0hc1b6d966,
|
||||||
|
0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h416b8e00, 0h41f50507, 0h416b8e00, 0hc1d2a716,
|
||||||
|
0h41d2a716, 0hc16b8e00, 0hc1f50507, 0hc16b8e00, 0h41b6d966, 0hc19194b0, 0hc208695c, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0h40de6d7d, 0hc208695c, 0hc19194b0, 0h41a58418, 0h406d72bf, 0hc22076c5, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc06d72bf, 0hc1a58418, 0hc06d72bf, 0h4208695c, 0hc0de6d7d, 0hc1b6d966, 0h419194b0,
|
||||||
|
0h4208695c, 0h419194b0, 0hc1b6d966, 0hc0de6d7d, 0h41f50507, 0h416b8e00, 0hc1d2a716, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc1f50507, 0h41b6d966, 0hc19194b0, 0h40de6d7d, 0hc208695c,
|
||||||
|
0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc208695c, 0h41a58418, 0h406d72bf, 0h406d72bf, 0hc22076c5,
|
||||||
|
0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1a58418, 0h4208695c, 0hc0de6d7d, 0h419194b0, 0hc1b6d966,
|
||||||
|
0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1b6d966, 0h41f50507, 0h416b8e00, 0h416b8e00, 0hc1d2a716,
|
||||||
|
0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h4235739c, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d, 0h421c1252,
|
||||||
|
0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0b05c85, 0h419d18ee, 0h419d18ee, 0h420e2b7a,
|
||||||
|
0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h421c1252, 0h419d18ee, 0hc0b05c85, 0h419d18ee, 0h420e2b7a,
|
||||||
|
0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h418a0670, 0h418a0670, 0h418a0670, 0h4208ee18,
|
||||||
|
0h3fc4b564, 0h3fc4b564, 0h4235739c, 0h3fc4b564, 0hc0024b8d, 0h40024b8d, 0h421c1252, 0h41b8e69d,
|
||||||
|
0hc0024b8d, 0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0b05c85, 0h419d18ee, 0h420e2b7a, 0h419d18ee,
|
||||||
|
0h41b8e69d, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h419d18ee, 0hc0b05c85, 0h420e2b7a, 0h419d18ee,
|
||||||
|
0h419d18ee, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h418a0670, 0h418a0670, 0h4208ee18, 0h418a0670,
|
||||||
|
0h3fc4b564, 0h4235739c, 0h3fc4b564, 0h3fc4b564, 0hc0024b8d, 0h421c1252, 0hc0024b8d, 0h41b8e69d,
|
||||||
|
0hc0024b8d, 0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0b05c85, 0h420e2b7a, 0h419d18ee, 0h419d18ee,
|
||||||
|
0h41b8e69d, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h419d18ee, 0h420e2b7a, 0hc0b05c85, 0h419d18ee,
|
||||||
|
0h419d18ee, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h418a0670, 0h4208ee18, 0h418a0670, 0h418a0670,
|
||||||
|
0h4235739c, 0h3fc4b564, 0h3fc4b564, 0h3fc4b564, 0h421c1252, 0hc0024b8d, 0hc0024b8d, 0h41b8e69d,
|
||||||
|
0h421c1252, 0hc0024b8d, 0h41b8e69d, 0hc0024b8d, 0h420e2b7a, 0hc0b05c85, 0h419d18ee, 0h419d18ee,
|
||||||
|
0h421c1252, 0h41b8e69d, 0hc0024b8d, 0hc0024b8d, 0h420e2b7a, 0h419d18ee, 0hc0b05c85, 0h419d18ee,
|
||||||
|
0h420e2b7a, 0h419d18ee, 0h419d18ee, 0hc0b05c85, 0h4208ee18, 0h418a0670, 0h418a0670, 0h418a0670,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41d2a716, 0hc208695c, 0hc19194b0, 0h40de6d7d, 0h41b6d966,
|
||||||
|
0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41b6d966, 0hc22076c5, 0h406d72bf, 0h406d72bf, 0h41a58418,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h422076c5, 0hc1b6d966, 0hc0de6d7d, 0h419194b0, 0h4208695c,
|
||||||
|
0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h4208695c, 0hc1d2a716, 0h416b8e00, 0h416b8e00, 0h41f50507,
|
||||||
|
0hc1f50507, 0hc16b8e00, 0h41d2a716, 0hc16b8e00, 0hc208695c, 0hc19194b0, 0h41b6d966, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h40de6d7d, 0h41b6d966, 0hc19194b0, 0hc22076c5, 0h406d72bf, 0h41a58418, 0h406d72bf,
|
||||||
|
0hc1a58418, 0hc06d72bf, 0h422076c5, 0hc06d72bf, 0hc1b6d966, 0hc0de6d7d, 0h4208695c, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h419194b0, 0h4208695c, 0hc0de6d7d, 0hc1d2a716, 0h416b8e00, 0h41f50507, 0h416b8e00,
|
||||||
|
0hc1f50507, 0h41d2a716, 0hc16b8e00, 0hc16b8e00, 0hc208695c, 0h41b6d966, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0hc208695c, 0h41b6d966, 0h40de6d7d, 0hc19194b0, 0hc22076c5, 0h41a58418, 0h406d72bf, 0h406d72bf,
|
||||||
|
0hc1a58418, 0h422076c5, 0hc06d72bf, 0hc06d72bf, 0hc1b6d966, 0h4208695c, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0hc1b6d966, 0h4208695c, 0h419194b0, 0hc0de6d7d, 0hc1d2a716, 0h41f50507, 0h416b8e00, 0h416b8e00,
|
||||||
|
0h41d2a716, 0hc1f50507, 0hc16b8e00, 0hc16b8e00, 0h41b6d966, 0hc208695c, 0hc19194b0, 0h40de6d7d,
|
||||||
|
0h41b6d966, 0hc208695c, 0h40de6d7d, 0hc19194b0, 0h41a58418, 0hc22076c5, 0h406d72bf, 0h406d72bf,
|
||||||
|
0h422076c5, 0hc1a58418, 0hc06d72bf, 0hc06d72bf, 0h4208695c, 0hc1b6d966, 0hc0de6d7d, 0h419194b0,
|
||||||
|
0h4208695c, 0hc1b6d966, 0h419194b0, 0hc0de6d7d, 0h41f50507, 0hc1d2a716, 0h416b8e00, 0h416b8e00,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
2D Simplex noise base.
|
||||||
|
*/
|
||||||
|
_internal_noise_2d_unskewed_base :: proc(seed: i64, coord: Vec2) -> (value: f32) {
|
||||||
|
// Get base points and offsets.
|
||||||
|
base := [2]i64{fast_floor(coord.x), fast_floor(coord.y)}
|
||||||
|
i := [2]f32{f32(coord.x - f64(base.x)), f32(coord.y - f64(base.y))}
|
||||||
|
|
||||||
|
// Prime pre-multiplication for hash.
|
||||||
|
bp := base * [2]i64{PRIME_X, PRIME_Y}
|
||||||
|
|
||||||
|
// Unskew.
|
||||||
|
t := f32(i.x + i.y) * f32(UNSKEW_2D)
|
||||||
|
d0 := i + [2]f32{t, t}
|
||||||
|
|
||||||
|
// First vertex.
|
||||||
|
a0 := RSQUARED_2D - d0.x * d0.x - d0.y * d0.y
|
||||||
|
if a0 > 0 {
|
||||||
|
value = (a0 * a0) * (a0 * a0) * grad(seed, [2]i64{bp.x, bp.y}, d0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second vertex.
|
||||||
|
a1 := f32(2 * (1 + 2 * UNSKEW_2D) * (1 / UNSKEW_2D + 2)) * t + f32(-2 * (1 + 2 * UNSKEW_2D) * (1 + 2 * UNSKEW_2D)) + a0
|
||||||
|
if a1 > 0 {
|
||||||
|
d1 := d0 - [2]f32{f32(1 + 2 * UNSKEW_2D), f32(1 + 2 * UNSKEW_2D)}
|
||||||
|
value += (a1 * a1) * (a1 * a1) * grad(seed, [2]i64{bp.x + PRIME_X, bp.y + PRIME_Y}, d1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third vertex.
|
||||||
|
if d0.y > d0.x {
|
||||||
|
d2 := d0 - [2]f32{f32(UNSKEW_2D), f32(UNSKEW_2D + 1)}
|
||||||
|
a2 := RSQUARED_2D - d2.x * d2.x - d2.y * d2.y
|
||||||
|
if(a2 > 0) {
|
||||||
|
value += (a2 * a2) * (a2 * a2) * grad(seed, [2]i64{bp.x, bp.y + PRIME_Y}, d2)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d2 := d0 - [2]f32{f32(UNSKEW_2D + 1), f32(UNSKEW_2D)}
|
||||||
|
a2 := RSQUARED_2D - d2.x * d2.x - d2.y * d2.y
|
||||||
|
if(a2 > 0) {
|
||||||
|
value += (a2 * a2) * (a2 * a2) * grad(seed, [2]i64{bp.x + PRIME_X, bp.y}, d2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generate overlapping cubic lattices for 3D OpenSimplex2 noise.
|
||||||
|
*/
|
||||||
|
_internal_noise_3d_unrotated_base :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||||
|
seed := seed
|
||||||
|
// Get base points and offsets.
|
||||||
|
// xr, yr, zr := coord.x, coord.y, coord.z
|
||||||
|
|
||||||
|
rb := [3]i64{fast_round(coord.x), fast_round(coord.y), fast_round(coord.z)}
|
||||||
|
ri := [3]f32{f32(coord.x - f64(rb.x)), f32(coord.y - f64(rb.y)), f32(coord.z - f64(rb.z))}
|
||||||
|
|
||||||
|
// -1 if positive, 1 if negative.
|
||||||
|
i_sign := [3]i64{i64(-1.0 - ri.x) | 1, i64(-1.0 - ri.y) | 1, i64(-1.0 - ri.z) | 1}
|
||||||
|
f_sign := [3]f32{f32(i_sign.x), f32(i_sign.y), f32(i_sign.z)}
|
||||||
|
|
||||||
|
// Compute absolute values, using the above as a shortcut. This was faster in my tests for some reason.
|
||||||
|
a0 := f_sign * -ri
|
||||||
|
|
||||||
|
// Prime pre-multiplication for hash.
|
||||||
|
rbp := rb * [3]i64{PRIME_X, PRIME_Y, PRIME_Z}
|
||||||
|
|
||||||
|
// Loop: Pick an edge on each lattice copy.
|
||||||
|
a := (RSQUARED_3D - ri.x * ri.x) - (ri.y * ri.y + ri.z * ri.z)
|
||||||
|
|
||||||
|
l := 0
|
||||||
|
for {
|
||||||
|
defer l += 1
|
||||||
|
|
||||||
|
// Closest point on cube.
|
||||||
|
if a > 0 {
|
||||||
|
a2 := a * a; a4 := a2 * a2
|
||||||
|
value += a4 * grad(seed, rbp, ri)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second-closest point.
|
||||||
|
if a0.x >= a0.y && a0.x >= a0.z {
|
||||||
|
b := a + a0.x + a0.x
|
||||||
|
if b > 1 {
|
||||||
|
b -= 1
|
||||||
|
b2 := b * b; b4 := b2 * b2
|
||||||
|
value += b4 * grad(seed, [3]i64{rbp.x - i_sign.x * PRIME_X, rbp.y, rbp.z}, [3]f32{ri.x + f_sign.x, ri.y, ri.z})
|
||||||
|
}
|
||||||
|
} else if a0.y > a0.x && a0.y >= a0.z {
|
||||||
|
b := a + a0.y + a0.y
|
||||||
|
if b > 1 {
|
||||||
|
b -= 1
|
||||||
|
b2 := b * b; b4 := b2 * b2
|
||||||
|
value += b4 * grad(seed, [3]i64{rbp.x, rbp.y - i_sign.y * PRIME_Y, rbp.z}, [3]f32{ri.x, ri.y + f_sign.y, ri.z})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b := a + a0.z + a0.z
|
||||||
|
if b > 1 {
|
||||||
|
b -= 1
|
||||||
|
b2 := b * b; b4 := b2 * b2
|
||||||
|
value += b4 * grad(seed, [3]i64{rbp.x, rbp.y, rbp.z - i_sign.z * PRIME_Z}, [3]f32{ri.x, ri.y, ri.z + f_sign.z})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break from loop if we're done, skipping updates below.
|
||||||
|
if l == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update absolute value.
|
||||||
|
a0 = 0.5 - a0
|
||||||
|
|
||||||
|
// Update relative coordinate.
|
||||||
|
ri = a0 * f_sign
|
||||||
|
|
||||||
|
// Update falloff.
|
||||||
|
a += (0.75 - a0.x) - (a0.y + a0.z)
|
||||||
|
|
||||||
|
// Update prime for hash.
|
||||||
|
rbp += [3]i64{i_sign.x >> 1, i_sign.y >> 1, i_sign.z >> 1} & {PRIME_X, PRIME_Y, PRIME_Z}
|
||||||
|
|
||||||
|
// Update the reverse sign indicators.
|
||||||
|
i_sign = -i_sign
|
||||||
|
f_sign = -f_sign
|
||||||
|
|
||||||
|
// And finally update the seed for the other lattice copy.
|
||||||
|
seed ~= SEED_FLIP_3D
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
4D OpenSimplex2 noise base.
|
||||||
|
*/
|
||||||
|
_internal_noise_4d_unskewed_base :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||||
|
seed := seed
|
||||||
|
|
||||||
|
// Get base points and offsets
|
||||||
|
base := [4]i64{fast_floor(coord.x), fast_floor(coord.y), fast_floor(coord.z), fast_floor(coord.w)}
|
||||||
|
si := [4]f32{f32(coord.x - f64(base.x)), f32(coord.y - f64(base.y)), f32(coord.z - f64(base.z)), f32(coord.w - f64(base.w))}
|
||||||
|
|
||||||
|
// Determine which lattice we can be confident has a contributing point its corresponding cell's base simplex.
|
||||||
|
// We only look at the spaces between the diagonal planes. This proved effective in all of my tests.
|
||||||
|
si_sum := (si.x + si.y) + (si.z + si.w)
|
||||||
|
starting_lattice := i64(si_sum * 1.25)
|
||||||
|
|
||||||
|
// Offset for seed based on first lattice copy.
|
||||||
|
seed += starting_lattice * SEED_OFFSET_4D
|
||||||
|
|
||||||
|
// Offset for lattice point relative positions (skewed)
|
||||||
|
starting_lattice_offset := f32(starting_lattice) * -LATTICE_STEP_4D
|
||||||
|
si += starting_lattice_offset
|
||||||
|
|
||||||
|
// Prep for vertex contributions.
|
||||||
|
ssi := (si_sum + starting_lattice_offset * 4) * UNSKEW_4D
|
||||||
|
|
||||||
|
// Prime pre-multiplication for hash.
|
||||||
|
svp := base * [4]i64{PRIME_X, PRIME_Y, PRIME_Z, PRIME_W}
|
||||||
|
|
||||||
|
// Five points to add, total, from five copies of the A4 lattice.
|
||||||
|
for i : i64 = 0; ; i += 1 {
|
||||||
|
|
||||||
|
// Next point is the closest vertex on the 4-simplex whose base vertex is the aforementioned vertex.
|
||||||
|
score := 1.0 + ssi * (-1.0 / UNSKEW_4D) // Seems slightly faster than 1.0-xsi-ysi-zsi-wsi
|
||||||
|
if si.x >= si.x && si.x >= si.z && si.x >= si.w && si.x >= score {
|
||||||
|
svp.x += PRIME_X
|
||||||
|
si.x -= 1
|
||||||
|
ssi -= UNSKEW_4D
|
||||||
|
}
|
||||||
|
else if si.y > si.x && si.y >= si.z && si.y >= si.w && si.y >= score {
|
||||||
|
svp.y += PRIME_Y
|
||||||
|
si.y -= 1
|
||||||
|
ssi -= UNSKEW_4D
|
||||||
|
}
|
||||||
|
else if si.z > si.x && si.z > si.y && si.z >= si.w && si.z >= score {
|
||||||
|
svp.z += PRIME_Z
|
||||||
|
si.z -= 1
|
||||||
|
ssi -= UNSKEW_4D
|
||||||
|
}
|
||||||
|
else if si.w > si.x && si.w > si.y && si.w > si.z && si.w >= score {
|
||||||
|
svp.w += PRIME_W
|
||||||
|
si.w -= 1
|
||||||
|
ssi -= UNSKEW_4D
|
||||||
|
}
|
||||||
|
|
||||||
|
// gradient contribution with falloff.
|
||||||
|
d := si + ssi
|
||||||
|
a := (d.x * d.x + d.y * d.y) + (d.z * d.z + d.w * d.w)
|
||||||
|
|
||||||
|
if a < RSQUARED_4D {
|
||||||
|
a -= RSQUARED_4D
|
||||||
|
a *= a; a4 := a * a
|
||||||
|
value += a4 * grad(seed, svp, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break from loop if we're done, skipping updates below.
|
||||||
|
if i == 4 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update for next lattice copy shifted down by <-0.2, -0.2, -0.2, -0.2>.
|
||||||
|
si += LATTICE_STEP_4D
|
||||||
|
ssi += LATTICE_STEP_4D * 4 * UNSKEW_4D
|
||||||
|
seed -= SEED_OFFSET_4D
|
||||||
|
|
||||||
|
// Because we don't always start on the same lattice copy, there's a special reset case.
|
||||||
|
if i == starting_lattice {
|
||||||
|
svp -= {PRIME_X, PRIME_Y, PRIME_Z, PRIME_W}
|
||||||
|
seed += SEED_OFFSET_4D * 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Utility functions
|
||||||
|
*/
|
||||||
|
@(optimization_mode="speed")
|
||||||
|
grad_2d :: proc(seed: i64, svp: [2]i64, delta: [2]f32) -> (value: f32) {
|
||||||
|
hash := seed ~ svp.x ~ svp.y
|
||||||
|
hash *= HASH_MULTIPLIER
|
||||||
|
hash ~= hash >> (64 - N_GRADS_2D_EXPONENT + 1)
|
||||||
|
|
||||||
|
gi := hash & ((N_GRADS_2D - 1) << 1)
|
||||||
|
return GRADIENTS_2D[gi] * delta.x + GRADIENTS_2D[gi | 1] * delta.y
|
||||||
|
}
|
||||||
|
|
||||||
|
@(optimization_mode="speed")
|
||||||
|
grad_3d :: proc(seed: i64, rvp: [3]i64, delta: [3]f32) -> (value: f32) {
|
||||||
|
hash := (seed ~ rvp.x) ~ (rvp.y ~ rvp.z)
|
||||||
|
hash *= HASH_MULTIPLIER
|
||||||
|
hash ~= hash >> (64 - N_GRADS_3D_EXPONENT + 2)
|
||||||
|
|
||||||
|
gi := hash & ((N_GRADS_3D - 1) << 2)
|
||||||
|
return GRADIENTS_3D[gi] * delta.x + GRADIENTS_3D[gi | 1] * delta.y + GRADIENTS_3D[gi | 2] * delta.z
|
||||||
|
}
|
||||||
|
|
||||||
|
@(optimization_mode="speed")
|
||||||
|
grad_4d :: proc(seed: i64, svp: [4]i64, delta: [4]f32) -> (value: f32) {
|
||||||
|
hash := seed ~ (svp.x ~ svp.y) ~ (svp.z ~ svp.w)
|
||||||
|
hash *= HASH_MULTIPLIER
|
||||||
|
hash ~= hash >> (64 - N_GRADS_4D_EXPONENT + 2)
|
||||||
|
|
||||||
|
gi := hash & ((N_GRADS_4D - 1) << 2)
|
||||||
|
return (GRADIENTS_4D[gi] * delta.x + GRADIENTS_4D[gi | 1] * delta.y) + (GRADIENTS_4D[gi | 2] * delta.z + GRADIENTS_4D[gi | 3] * delta.w)
|
||||||
|
}
|
||||||
|
|
||||||
|
grad :: proc {grad_2d, grad_3d, grad_4d}
|
||||||
|
|
||||||
|
@(optimization_mode="speed")
|
||||||
|
fast_floor :: proc(x: f64) -> (floored: i64) {
|
||||||
|
xi := i64(x)
|
||||||
|
return x < f64(xi) ? xi - 1 : xi
|
||||||
|
}
|
||||||
|
|
||||||
|
@(optimization_mode="speed")
|
||||||
|
fast_round :: proc(x: f64) -> (rounded: i64) {
|
||||||
|
return x < 0 ? i64(x - 0.5) : i64(x + 0.5)
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
OpenSimplex2 noise implementation.
|
||||||
|
|
||||||
|
Ported from https://github.com/KdotJPG/OpenSimplex2.
|
||||||
|
Copyright 2022 Yuki2 (https://github.com/NoahR02)
|
||||||
|
*/
|
||||||
|
package math_noise
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input coordinate vectors
|
||||||
|
*/
|
||||||
|
Vec2 :: [2]f64
|
||||||
|
Vec3 :: [3]f64
|
||||||
|
Vec4 :: [4]f64
|
||||||
|
|
||||||
|
/*
|
||||||
|
Noise Evaluators
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
2D Simplex noise, standard lattice orientation.
|
||||||
|
*/
|
||||||
|
noise_2d :: proc(seed: i64, coord: Vec2) -> (value: f32) {
|
||||||
|
// Get points for A2* lattice
|
||||||
|
skew := SKEW_2D * (coord.x + coord.y)
|
||||||
|
skewed := coord + skew
|
||||||
|
|
||||||
|
return _internal_noise_2d_unskewed_base(seed, skewed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
2D Simplex noise, with Y pointing down the main diagonal.
|
||||||
|
Might be better for a 2D sandbox style game, where Y is vertical.
|
||||||
|
Probably slightly less optimal for heightmaps or continent maps,
|
||||||
|
unless your map is centered around an equator. It's a subtle
|
||||||
|
difference, but the option is here to make it an easy choice.
|
||||||
|
*/
|
||||||
|
noise_2d_improve_x :: proc(seed: i64, coord: Vec2) -> (value: f32) {
|
||||||
|
// Skew transform and rotation baked into one.
|
||||||
|
xx := coord.x * ROOT_2_OVER_2
|
||||||
|
yy := coord.y * (ROOT_2_OVER_2 * (1 + 2 * SKEW_2D))
|
||||||
|
return _internal_noise_2d_unskewed_base(seed, Vec2{yy + xx, yy - xx})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
3D OpenSimplex2 noise, with better visual isotropy in (X, Y).
|
||||||
|
Recommended for 3D terrain and time-varied animations.
|
||||||
|
The Z coordinate should always be the "different" coordinate in whatever your use case is.
|
||||||
|
If Y is vertical in world coordinates, call `noise_3d_improve_xz(x, z, Y)` or use `noise_3d_xz_before_y`.
|
||||||
|
If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, y, Z)`.
|
||||||
|
For a time varied animation, call `noise_3d_improve_xz(x, y, T)`.
|
||||||
|
*/
|
||||||
|
noise_3d_improve_xy :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||||
|
/*
|
||||||
|
Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal,
|
||||||
|
and the planes formed by XY are moved far out of alignment with the cube faces.
|
||||||
|
Orthonormal rotation. Not a skew transform.
|
||||||
|
*/
|
||||||
|
xy := coord.x + coord.y
|
||||||
|
s2 := xy * ROTATE_3D_ORTHOGONALIZER
|
||||||
|
zz := coord.z * ROOT_3_OVER_3
|
||||||
|
|
||||||
|
r := Vec3{coord.x + s2 + zz, coord.y + s2 + zz, xy * -ROOT_3_OVER_3 + zz}
|
||||||
|
|
||||||
|
// Evaluate both lattices to form a BCC lattice.
|
||||||
|
return _internal_noise_3d_unrotated_base(seed, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
3D OpenSimplex2 noise, with better visual isotropy in (X, Z).
|
||||||
|
Recommended for 3D terrain and time-varied animations.
|
||||||
|
The Y coordinate should always be the "different" coordinate in whatever your use case is.
|
||||||
|
If Y is vertical in world coordinates, call `noise_3d_improve_xz(x, Y, z)`.
|
||||||
|
If Z is vertical in world coordinates, call `noise_3d_improve_xz(x, Z, y)` or use `noise_3d_improve_xy`.
|
||||||
|
For a time varied animation, call `noise_3d_improve_xz(x, T, y)` or use `noise_3d_improve_xy`.
|
||||||
|
*/
|
||||||
|
noise_3d_improve_xz :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||||
|
/*
|
||||||
|
Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal,
|
||||||
|
and the planes formed by XZ are moved far out of alignment with the cube faces.
|
||||||
|
Orthonormal rotation. Not a skew transform.
|
||||||
|
*/
|
||||||
|
xz := coord.x + coord.z
|
||||||
|
s2 := xz * ROTATE_3D_ORTHOGONALIZER
|
||||||
|
yy := coord.y * ROOT_3_OVER_3
|
||||||
|
|
||||||
|
r := Vec3{coord.x + s2 + yy, xz * -ROOT_3_OVER_3 + yy, coord.z + s2 + yy}
|
||||||
|
|
||||||
|
// Evaluate both lattices to form a BCC lattice.
|
||||||
|
return _internal_noise_3d_unrotated_base(seed, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
3D OpenSimplex2 noise, fallback rotation option
|
||||||
|
Use `noise_3d_improve_xy` or `noise_3d_improve_xz` instead, wherever appropriate.
|
||||||
|
They have less diagonal bias. This function's best use is as a fallback.
|
||||||
|
*/
|
||||||
|
noise_3d_fallback :: proc(seed: i64, coord: Vec3) -> (value: f32) {
|
||||||
|
/*
|
||||||
|
Re-orient the cubic lattices via rotation, to produce a familiar look.
|
||||||
|
Orthonormal rotation. Not a skew transform.
|
||||||
|
*/
|
||||||
|
bias := FALLBACK_ROTATE_3D * (coord.x + coord.y + coord.z)
|
||||||
|
biased := bias - coord
|
||||||
|
// Evaluate both lattices to form a BCC lattice.
|
||||||
|
return _internal_noise_3d_unrotated_base(seed, biased)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_improve_xy`
|
||||||
|
and W for an extra degree of freedom. W repeats eventually.
|
||||||
|
Recommended for time-varied animations which texture a 3D object (W=time)
|
||||||
|
in a space where Z is vertical.
|
||||||
|
*/
|
||||||
|
noise_4d_improve_xyz_improve_xy :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||||
|
xy := coord.x + coord.y
|
||||||
|
s2 := xy * -0.21132486540518699998
|
||||||
|
zz := coord.z * 0.28867513459481294226
|
||||||
|
ww := coord.w * 0.2236067977499788
|
||||||
|
|
||||||
|
xr, yr : f64 = coord.x + (zz + ww + s2), coord.y + (zz + ww + s2)
|
||||||
|
zr : f64 = xy * -0.57735026918962599998 + (zz + ww)
|
||||||
|
wr : f64 = coord.z * -0.866025403784439 + ww
|
||||||
|
|
||||||
|
return _internal_noise_4d_unskewed_base(seed, Vec4{xr, yr, zr, wr})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_improve_xz`
|
||||||
|
and W for an extra degree of freedom. W repeats eventually.
|
||||||
|
Recommended for time-varied animations which texture a 3D object (W=time)
|
||||||
|
in a space where Y is vertical.
|
||||||
|
*/
|
||||||
|
noise_4d_improve_xyz_improve_xz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||||
|
xz := coord.x + coord.z
|
||||||
|
s2 := xz * -0.21132486540518699998
|
||||||
|
yy := coord.y * 0.28867513459481294226
|
||||||
|
ww := coord.w * 0.2236067977499788
|
||||||
|
|
||||||
|
xr, zr : f64 = coord.x + (yy + ww + s2), coord.z + (yy + ww + s2)
|
||||||
|
yr := xz * -0.57735026918962599998 + (yy + ww)
|
||||||
|
wr := coord.y * -0.866025403784439 + ww
|
||||||
|
|
||||||
|
return _internal_noise_4d_unskewed_base(seed, Vec4{xr, yr, zr, wr})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
4D OpenSimplex2 noise, with XYZ oriented like `noise_3d_fallback`
|
||||||
|
and W for an extra degree of freedom. W repeats eventually.
|
||||||
|
Recommended for time-varied animations which texture a 3D object (W=time)
|
||||||
|
where there isn't a clear distinction between horizontal and vertical
|
||||||
|
*/
|
||||||
|
noise_4d_improve_xyz :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||||
|
xyz := coord.x + coord.y + coord.z
|
||||||
|
ww := coord.w * 0.2236067977499788
|
||||||
|
s2 := xyz * -0.16666666666666666 + ww
|
||||||
|
|
||||||
|
skewed := Vec4{coord.x + s2, coord.y + s2, coord.z + s2, -0.5 * xyz + ww}
|
||||||
|
return _internal_noise_4d_unskewed_base(seed, skewed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
4D OpenSimplex2 noise, fallback lattice orientation.
|
||||||
|
*/
|
||||||
|
noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) {
|
||||||
|
// Get points for A4 lattice
|
||||||
|
skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w)
|
||||||
|
return _internal_noise_4d_unskewed_base(seed, coord + skew)
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package rand
|
package rand
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
Rand :: struct {
|
Rand :: struct {
|
||||||
state: u64,
|
state: u64,
|
||||||
inc: u64,
|
inc: u64,
|
||||||
@@ -7,9 +9,7 @@ Rand :: struct {
|
|||||||
|
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
_GLOBAL_SEED_DATA := 1234567890
|
global_rand := create(u64(intrinsics.read_cycle_counter()))
|
||||||
@(private)
|
|
||||||
global_rand := create(u64(uintptr(&_GLOBAL_SEED_DATA)))
|
|
||||||
|
|
||||||
set_global_seed :: proc(seed: u64) {
|
set_global_seed :: proc(seed: u64) {
|
||||||
init(&global_rand, seed)
|
init(&global_rand, seed)
|
||||||
|
|||||||
@@ -6,7 +6,24 @@ import "core:runtime"
|
|||||||
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||||
return nil, nil
|
switch mode {
|
||||||
|
case .Alloc:
|
||||||
|
return nil, .Out_Of_Memory
|
||||||
|
case .Free:
|
||||||
|
return nil, .None
|
||||||
|
case .Free_All:
|
||||||
|
return nil, .Mode_Not_Implemented
|
||||||
|
case .Resize:
|
||||||
|
if size == 0 {
|
||||||
|
return nil, .None
|
||||||
|
}
|
||||||
|
return nil, .Out_Of_Memory
|
||||||
|
case .Query_Features:
|
||||||
|
return nil, .Mode_Not_Implemented
|
||||||
|
case .Query_Info:
|
||||||
|
return nil, .Mode_Not_Implemented
|
||||||
|
}
|
||||||
|
return nil, .None
|
||||||
}
|
}
|
||||||
|
|
||||||
nil_allocator :: proc() -> Allocator {
|
nil_allocator :: proc() -> Allocator {
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
package mem implements various types of allocators.
|
||||||
|
|
||||||
|
|
||||||
|
An example of how to use the `Tracking_Allocator` to track subsequent allocations
|
||||||
|
in your program and report leaks and bad frees:
|
||||||
|
|
||||||
|
```odin
|
||||||
|
package foo
|
||||||
|
|
||||||
|
import "core:mem"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
_main :: proc() {
|
||||||
|
do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
track: mem.Tracking_Allocator
|
||||||
|
mem.tracking_allocator_init(&track, context.allocator)
|
||||||
|
context.allocator = mem.tracking_allocator(&track)
|
||||||
|
|
||||||
|
_main()
|
||||||
|
|
||||||
|
for _, leak in track.allocation_map {
|
||||||
|
fmt.printf("%v leaked %v bytes\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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
package mem
|
||||||
+1
-1
@@ -16,7 +16,7 @@ zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr {
|
|||||||
// equivalent semantics to those provided by the C11 Annex K 3.7.4.1
|
// equivalent semantics to those provided by the C11 Annex K 3.7.4.1
|
||||||
// memset_s call.
|
// memset_s call.
|
||||||
intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero
|
intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero
|
||||||
intrinsics.atomic_fence() // Prevent reordering
|
intrinsics.atomic_thread_fence(.Seq_Cst) // Prevent reordering
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
zero_item :: proc "contextless" (item: $P/^$T) {
|
zero_item :: proc "contextless" (item: $P/^$T) {
|
||||||
|
|||||||
@@ -6,25 +6,25 @@ DEFAULT_PAGE_SIZE := uint(4096)
|
|||||||
|
|
||||||
Allocator_Error :: mem.Allocator_Error
|
Allocator_Error :: mem.Allocator_Error
|
||||||
|
|
||||||
reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
return _reserve(size)
|
return _reserve(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||||
return _commit(data, size)
|
return _commit(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
reserve_and_commit :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
data = reserve(size) or_return
|
data = reserve(size) or_return
|
||||||
commit(raw_data(data), size) or_return
|
commit(raw_data(data), size) or_return
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
decommit :: proc(data: rawptr, size: uint) {
|
decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
_decommit(data, size)
|
_decommit(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
release :: proc(data: rawptr, size: uint) {
|
release :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
_release(data, size)
|
_release(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ Protect_Flag :: enum u32 {
|
|||||||
Protect_Flags :: distinct bit_set[Protect_Flag; u32]
|
Protect_Flags :: distinct bit_set[Protect_Flag; u32]
|
||||||
Protect_No_Access :: Protect_Flags{}
|
Protect_No_Access :: Protect_Flags{}
|
||||||
|
|
||||||
protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||||
return _protect(data, size, flags)
|
return _protect(data, size, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,11 +82,13 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
|||||||
pmblock := platform_memory_alloc(0, total_size) or_return
|
pmblock := platform_memory_alloc(0, total_size) or_return
|
||||||
|
|
||||||
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset)
|
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset)
|
||||||
commit(pmblock.block.base, committed) or_return
|
commit_err := platform_memory_commit(pmblock, uint(base_offset) + committed)
|
||||||
|
assert(commit_err == nil)
|
||||||
|
|
||||||
// Should be zeroed
|
// Should be zeroed
|
||||||
assert(pmblock.block.used == 0)
|
assert(pmblock.block.used == 0)
|
||||||
assert(pmblock.block.prev == nil)
|
assert(pmblock.block.prev == nil)
|
||||||
if (do_protection) {
|
if do_protection {
|
||||||
protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access)
|
protect(rawptr(uintptr(pmblock) + protect_offset), page_size, Protect_No_Access)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +107,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
|
||||||
calc_alignment_offset :: proc(block: ^Memory_Block, alignment: uintptr) -> uint {
|
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||||
alignment_offset := uint(0)
|
alignment_offset := uint(0)
|
||||||
ptr := uintptr(block.base[block.used:])
|
ptr := uintptr(block.base[block.used:])
|
||||||
mask := alignment-1
|
mask := alignment-1
|
||||||
@@ -115,23 +117,37 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
|
|||||||
return alignment_offset
|
return alignment_offset
|
||||||
|
|
||||||
}
|
}
|
||||||
|
do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint) -> (err: Allocator_Error) {
|
||||||
|
if block.committed - block.used < size {
|
||||||
|
pmblock := (^Platform_Memory_Block)(block)
|
||||||
|
base_offset := uint(uintptr(block) - uintptr(pmblock))
|
||||||
|
platform_total_commit := base_offset + block.used + size
|
||||||
|
|
||||||
|
assert(pmblock.committed <= pmblock.reserved)
|
||||||
|
assert(pmblock.committed < platform_total_commit)
|
||||||
|
|
||||||
|
platform_memory_commit(pmblock, platform_total_commit) or_return
|
||||||
|
|
||||||
|
pmblock.committed = platform_total_commit
|
||||||
|
block.committed = pmblock.committed - base_offset
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
alignment_offset := calc_alignment_offset(block, uintptr(alignment))
|
||||||
|
|
||||||
size := uint(min_size) + alignment_offset
|
size := uint(min_size) + alignment_offset
|
||||||
|
|
||||||
if block.used + size > block.reserved {
|
if block.used + size > block.reserved {
|
||||||
err = .Out_Of_Memory
|
err = .Out_Of_Memory
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
assert(block.committed <= block.reserved)
|
||||||
ptr := block.base[block.used:]
|
do_commit_if_necessary(block, size) or_return
|
||||||
ptr = ptr[alignment_offset:]
|
|
||||||
|
data = block.base[block.used+alignment_offset:][:min_size]
|
||||||
block.used += size
|
block.used += size
|
||||||
assert(block.used <= block.reserved)
|
return
|
||||||
|
|
||||||
return ptr[:min_size], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.i
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
MAP_FAILED := rawptr(~uintptr(0))
|
MAP_FAILED := rawptr(~uintptr(0))
|
||||||
result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
|
result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
|
||||||
if result == MAP_FAILED {
|
if result == MAP_FAILED {
|
||||||
@@ -67,7 +67,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
|||||||
return ([^]byte)(result)[:size], nil
|
return ([^]byte)(result)[:size], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||||
result := mprotect(data, size, PROT_READ|PROT_WRITE)
|
result := mprotect(data, size, PROT_READ|PROT_WRITE)
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
// TODO(bill): Handle error value correctly
|
// TODO(bill): Handle error value correctly
|
||||||
@@ -75,14 +75,14 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_decommit :: proc(data: rawptr, size: uint) {
|
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
mprotect(data, size, PROT_NONE)
|
mprotect(data, size, PROT_NONE)
|
||||||
madvise(data, size, MADV_FREE)
|
madvise(data, size, MADV_FREE)
|
||||||
}
|
}
|
||||||
_release :: proc(data: rawptr, size: uint) {
|
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
munmap(data, size)
|
munmap(data, size)
|
||||||
}
|
}
|
||||||
_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||||
pflags: c.int
|
pflags: c.int
|
||||||
pflags = PROT_NONE
|
pflags = PROT_NONE
|
||||||
if .Read in flags { pflags |= PROT_READ }
|
if .Read in flags { pflags |= PROT_READ }
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
//+private
|
//+private
|
||||||
package mem_virtual
|
package mem_virtual
|
||||||
|
|
||||||
import sync "core:sync/sync2"
|
import "core:sync"
|
||||||
|
|
||||||
Platform_Memory_Block :: struct {
|
Platform_Memory_Block :: struct {
|
||||||
block: Memory_Block,
|
block: Memory_Block,
|
||||||
reserved: uint,
|
committed: uint,
|
||||||
|
reserved: uint,
|
||||||
prev, next: ^Platform_Memory_Block,
|
prev, next: ^Platform_Memory_Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
|
||||||
to_commit, to_reserve := to_commit, to_reserve
|
to_commit, to_reserve := to_commit, to_reserve
|
||||||
to_reserve = max(to_commit, to_reserve)
|
to_reserve = max(to_commit, to_reserve)
|
||||||
|
|
||||||
@@ -20,12 +21,13 @@ platform_memory_alloc :: proc(to_commit, to_reserve: uint) -> (block: ^Platform_
|
|||||||
commit(raw_data(data), to_commit)
|
commit(raw_data(data), to_commit)
|
||||||
|
|
||||||
block = (^Platform_Memory_Block)(raw_data(data))
|
block = (^Platform_Memory_Block)(raw_data(data))
|
||||||
block.reserved = to_reserve
|
block.committed = to_commit
|
||||||
|
block.reserved = to_reserve
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
platform_memory_free :: proc(block: ^Platform_Memory_Block) {
|
platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) {
|
||||||
if block != nil {
|
if block != nil {
|
||||||
release(block, block.reserved)
|
release(block, block.reserved)
|
||||||
}
|
}
|
||||||
@@ -52,3 +54,17 @@ platform_memory_init :: proc() {
|
|||||||
global_platform_memory_block_sentinel_set = true
|
global_platform_memory_block_sentinel_set = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
|
||||||
|
if to_commit < block.committed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if to_commit > block.reserved {
|
||||||
|
return .Out_Of_Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
commit(block, to_commit) or_return
|
||||||
|
block.committed = to_commit
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ foreign Kernel32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
|
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
err = .Out_Of_Memory
|
err = .Out_Of_Memory
|
||||||
@@ -72,7 +72,7 @@ _reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||||
result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
|
result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
switch err := GetLastError(); err {
|
switch err := GetLastError(); err {
|
||||||
@@ -85,13 +85,13 @@ _commit :: proc(data: rawptr, size: uint) -> Allocator_Error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_decommit :: proc(data: rawptr, size: uint) {
|
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
VirtualFree(data, size, MEM_DECOMMIT)
|
VirtualFree(data, size, MEM_DECOMMIT)
|
||||||
}
|
}
|
||||||
_release :: proc(data: rawptr, size: uint) {
|
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||||
VirtualFree(data, 0, MEM_RELEASE)
|
VirtualFree(data, 0, MEM_RELEASE)
|
||||||
}
|
}
|
||||||
_protect :: proc(data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||||
pflags: u32
|
pflags: u32
|
||||||
pflags = PAGE_NOACCESS
|
pflags = PAGE_NOACCESS
|
||||||
switch flags {
|
switch flags {
|
||||||
|
|||||||
+183
-5
@@ -34,7 +34,7 @@ Node :: struct {
|
|||||||
pos: tokenizer.Pos,
|
pos: tokenizer.Pos,
|
||||||
end: tokenizer.Pos,
|
end: tokenizer.Pos,
|
||||||
state_flags: Node_State_Flags,
|
state_flags: Node_State_Flags,
|
||||||
derived: any,
|
derived: Any_Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
Comment_Group :: struct {
|
Comment_Group :: struct {
|
||||||
@@ -88,9 +88,11 @@ File :: struct {
|
|||||||
|
|
||||||
Expr :: struct {
|
Expr :: struct {
|
||||||
using expr_base: Node,
|
using expr_base: Node,
|
||||||
|
derived_expr: Any_Expr,
|
||||||
}
|
}
|
||||||
Stmt :: struct {
|
Stmt :: struct {
|
||||||
using stmt_base: Node,
|
using stmt_base: Node,
|
||||||
|
derived_stmt: Any_Stmt,
|
||||||
}
|
}
|
||||||
Decl :: struct {
|
Decl :: struct {
|
||||||
using decl_base: Stmt,
|
using decl_base: Stmt,
|
||||||
@@ -151,6 +153,7 @@ Comp_Lit :: struct {
|
|||||||
open: tokenizer.Pos,
|
open: tokenizer.Pos,
|
||||||
elems: []^Expr,
|
elems: []^Expr,
|
||||||
close: tokenizer.Pos,
|
close: tokenizer.Pos,
|
||||||
|
tag: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -540,7 +543,7 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
e, ok := val.derived.(Paren_Expr)
|
e, ok := val.derived.(^Paren_Expr)
|
||||||
if !ok || e.expr == nil {
|
if !ok || e.expr == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -705,13 +708,19 @@ Struct_Type :: struct {
|
|||||||
name_count: int,
|
name_count: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Union_Type_Kind :: enum u8 {
|
||||||
|
Normal,
|
||||||
|
maybe,
|
||||||
|
no_nil,
|
||||||
|
shared_nil,
|
||||||
|
}
|
||||||
|
|
||||||
Union_Type :: struct {
|
Union_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: tokenizer.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
poly_params: ^Field_List,
|
poly_params: ^Field_List,
|
||||||
align: ^Expr,
|
align: ^Expr,
|
||||||
is_maybe: bool,
|
kind: Union_Type_Kind,
|
||||||
is_no_nil: bool,
|
|
||||||
where_token: tokenizer.Token,
|
where_token: tokenizer.Token,
|
||||||
where_clauses: []^Expr,
|
where_clauses: []^Expr,
|
||||||
variants: []^Expr,
|
variants: []^Expr,
|
||||||
@@ -757,4 +766,173 @@ Matrix_Type :: struct {
|
|||||||
row_count: ^Expr,
|
row_count: ^Expr,
|
||||||
column_count: ^Expr,
|
column_count: ^Expr,
|
||||||
elem: ^Expr,
|
elem: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Any_Node :: union {
|
||||||
|
^Package,
|
||||||
|
^File,
|
||||||
|
^Comment_Group,
|
||||||
|
|
||||||
|
^Bad_Expr,
|
||||||
|
^Ident,
|
||||||
|
^Implicit,
|
||||||
|
^Undef,
|
||||||
|
^Basic_Lit,
|
||||||
|
^Basic_Directive,
|
||||||
|
^Ellipsis,
|
||||||
|
^Proc_Lit,
|
||||||
|
^Comp_Lit,
|
||||||
|
^Tag_Expr,
|
||||||
|
^Unary_Expr,
|
||||||
|
^Binary_Expr,
|
||||||
|
^Paren_Expr,
|
||||||
|
^Selector_Expr,
|
||||||
|
^Implicit_Selector_Expr,
|
||||||
|
^Selector_Call_Expr,
|
||||||
|
^Index_Expr,
|
||||||
|
^Deref_Expr,
|
||||||
|
^Slice_Expr,
|
||||||
|
^Matrix_Index_Expr,
|
||||||
|
^Call_Expr,
|
||||||
|
^Field_Value,
|
||||||
|
^Ternary_If_Expr,
|
||||||
|
^Ternary_When_Expr,
|
||||||
|
^Or_Else_Expr,
|
||||||
|
^Or_Return_Expr,
|
||||||
|
^Type_Assertion,
|
||||||
|
^Type_Cast,
|
||||||
|
^Auto_Cast,
|
||||||
|
^Inline_Asm_Expr,
|
||||||
|
|
||||||
|
^Proc_Group,
|
||||||
|
|
||||||
|
^Typeid_Type,
|
||||||
|
^Helper_Type,
|
||||||
|
^Distinct_Type,
|
||||||
|
^Poly_Type,
|
||||||
|
^Proc_Type,
|
||||||
|
^Pointer_Type,
|
||||||
|
^Multi_Pointer_Type,
|
||||||
|
^Array_Type,
|
||||||
|
^Dynamic_Array_Type,
|
||||||
|
^Struct_Type,
|
||||||
|
^Union_Type,
|
||||||
|
^Enum_Type,
|
||||||
|
^Bit_Set_Type,
|
||||||
|
^Map_Type,
|
||||||
|
^Relative_Type,
|
||||||
|
^Matrix_Type,
|
||||||
|
|
||||||
|
^Bad_Stmt,
|
||||||
|
^Empty_Stmt,
|
||||||
|
^Expr_Stmt,
|
||||||
|
^Tag_Stmt,
|
||||||
|
^Assign_Stmt,
|
||||||
|
^Block_Stmt,
|
||||||
|
^If_Stmt,
|
||||||
|
^When_Stmt,
|
||||||
|
^Return_Stmt,
|
||||||
|
^Defer_Stmt,
|
||||||
|
^For_Stmt,
|
||||||
|
^Range_Stmt,
|
||||||
|
^Inline_Range_Stmt,
|
||||||
|
^Case_Clause,
|
||||||
|
^Switch_Stmt,
|
||||||
|
^Type_Switch_Stmt,
|
||||||
|
^Branch_Stmt,
|
||||||
|
^Using_Stmt,
|
||||||
|
|
||||||
|
^Bad_Decl,
|
||||||
|
^Value_Decl,
|
||||||
|
^Package_Decl,
|
||||||
|
^Import_Decl,
|
||||||
|
^Foreign_Block_Decl,
|
||||||
|
^Foreign_Import_Decl,
|
||||||
|
|
||||||
|
^Attribute,
|
||||||
|
^Field,
|
||||||
|
^Field_List,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Any_Expr :: union {
|
||||||
|
^Bad_Expr,
|
||||||
|
^Ident,
|
||||||
|
^Implicit,
|
||||||
|
^Undef,
|
||||||
|
^Basic_Lit,
|
||||||
|
^Basic_Directive,
|
||||||
|
^Ellipsis,
|
||||||
|
^Proc_Lit,
|
||||||
|
^Comp_Lit,
|
||||||
|
^Tag_Expr,
|
||||||
|
^Unary_Expr,
|
||||||
|
^Binary_Expr,
|
||||||
|
^Paren_Expr,
|
||||||
|
^Selector_Expr,
|
||||||
|
^Implicit_Selector_Expr,
|
||||||
|
^Selector_Call_Expr,
|
||||||
|
^Index_Expr,
|
||||||
|
^Deref_Expr,
|
||||||
|
^Slice_Expr,
|
||||||
|
^Matrix_Index_Expr,
|
||||||
|
^Call_Expr,
|
||||||
|
^Field_Value,
|
||||||
|
^Ternary_If_Expr,
|
||||||
|
^Ternary_When_Expr,
|
||||||
|
^Or_Else_Expr,
|
||||||
|
^Or_Return_Expr,
|
||||||
|
^Type_Assertion,
|
||||||
|
^Type_Cast,
|
||||||
|
^Auto_Cast,
|
||||||
|
^Inline_Asm_Expr,
|
||||||
|
|
||||||
|
^Proc_Group,
|
||||||
|
|
||||||
|
^Typeid_Type,
|
||||||
|
^Helper_Type,
|
||||||
|
^Distinct_Type,
|
||||||
|
^Poly_Type,
|
||||||
|
^Proc_Type,
|
||||||
|
^Pointer_Type,
|
||||||
|
^Multi_Pointer_Type,
|
||||||
|
^Array_Type,
|
||||||
|
^Dynamic_Array_Type,
|
||||||
|
^Struct_Type,
|
||||||
|
^Union_Type,
|
||||||
|
^Enum_Type,
|
||||||
|
^Bit_Set_Type,
|
||||||
|
^Map_Type,
|
||||||
|
^Relative_Type,
|
||||||
|
^Matrix_Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Any_Stmt :: union {
|
||||||
|
^Bad_Stmt,
|
||||||
|
^Empty_Stmt,
|
||||||
|
^Expr_Stmt,
|
||||||
|
^Tag_Stmt,
|
||||||
|
^Assign_Stmt,
|
||||||
|
^Block_Stmt,
|
||||||
|
^If_Stmt,
|
||||||
|
^When_Stmt,
|
||||||
|
^Return_Stmt,
|
||||||
|
^Defer_Stmt,
|
||||||
|
^For_Stmt,
|
||||||
|
^Range_Stmt,
|
||||||
|
^Inline_Range_Stmt,
|
||||||
|
^Case_Clause,
|
||||||
|
^Switch_Stmt,
|
||||||
|
^Type_Switch_Stmt,
|
||||||
|
^Branch_Stmt,
|
||||||
|
^Using_Stmt,
|
||||||
|
|
||||||
|
^Bad_Decl,
|
||||||
|
^Value_Decl,
|
||||||
|
^Package_Decl,
|
||||||
|
^Import_Decl,
|
||||||
|
^Foreign_Block_Decl,
|
||||||
|
^Foreign_Import_Decl,
|
||||||
|
}
|
||||||
|
|||||||
+117
-83
@@ -1,16 +1,25 @@
|
|||||||
package odin_ast
|
package odin_ast
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
import "core:reflect"
|
||||||
import "core:odin/tokenizer"
|
import "core:odin/tokenizer"
|
||||||
|
_ :: intrinsics
|
||||||
|
|
||||||
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
|
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
|
||||||
n, _ := mem.new(T)
|
n, _ := mem.new(T)
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.end = end
|
n.end = end
|
||||||
n.derived = n^
|
n.derived = n
|
||||||
base: ^Node = n // dummy check
|
base: ^Node = n // dummy check
|
||||||
_ = base // "Use" type to make -vet happy
|
_ = base // "Use" type to make -vet happy
|
||||||
|
when intrinsics.type_has_field(T, "derived_expr") {
|
||||||
|
n.derived_expr = n
|
||||||
|
}
|
||||||
|
when intrinsics.type_has_field(T, "derived_stmt") {
|
||||||
|
n.derived_stmt = n
|
||||||
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,232 +68,257 @@ clone_node :: proc(node: ^Node) -> ^Node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
size := size_of(Node)
|
size := size_of(Node)
|
||||||
align := align_of(Node)
|
align := align_of(Node)
|
||||||
ti := type_info_of(node.derived.id)
|
ti := reflect.union_variant_type_info(node.derived)
|
||||||
if ti != nil {
|
if ti != nil {
|
||||||
size = ti.size
|
elem := ti.variant.(reflect.Type_Info_Pointer).elem
|
||||||
align = ti.align
|
size = elem.size
|
||||||
|
align = elem.align
|
||||||
}
|
}
|
||||||
|
|
||||||
switch in node.derived {
|
#partial switch in node.derived {
|
||||||
case Package, File:
|
case ^Package, ^File:
|
||||||
panic("Cannot clone this node type")
|
panic("Cannot clone this node type")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := cast(^Node)mem.alloc(size, align)
|
res := cast(^Node)mem.alloc(size, align)
|
||||||
src: rawptr = node
|
src: rawptr = node
|
||||||
if node.derived != nil {
|
if node.derived != nil {
|
||||||
src = node.derived.data
|
src = (^rawptr)(&node.derived)^
|
||||||
}
|
}
|
||||||
mem.copy(res, src, size)
|
mem.copy(res, src, size)
|
||||||
res.derived.data = rawptr(res)
|
res_ptr_any: any
|
||||||
res.derived.id = node.derived.id
|
res_ptr_any.data = &res
|
||||||
|
res_ptr_any.id = ti.id
|
||||||
|
|
||||||
switch r in &res.derived {
|
reflect.set_union_value(res.derived, res_ptr_any)
|
||||||
case Bad_Expr:
|
|
||||||
case Ident:
|
|
||||||
case Implicit:
|
|
||||||
case Undef:
|
|
||||||
case Basic_Lit:
|
|
||||||
|
|
||||||
case Ellipsis:
|
res_ptr := reflect.deref(res_ptr_any)
|
||||||
|
|
||||||
|
if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); de != nil {
|
||||||
|
reflect.set_union_value(de, res_ptr_any)
|
||||||
|
}
|
||||||
|
if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); ds != nil {
|
||||||
|
reflect.set_union_value(ds, res_ptr_any)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.derived != nil do switch r in res.derived {
|
||||||
|
case ^Package, ^File:
|
||||||
|
case ^Bad_Expr:
|
||||||
|
case ^Ident:
|
||||||
|
case ^Implicit:
|
||||||
|
case ^Undef:
|
||||||
|
case ^Basic_Lit:
|
||||||
|
case ^Basic_Directive:
|
||||||
|
case ^Comment_Group:
|
||||||
|
|
||||||
|
case ^Ellipsis:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Proc_Lit:
|
case ^Proc_Lit:
|
||||||
r.type = auto_cast clone(r.type)
|
r.type = auto_cast clone(r.type)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Comp_Lit:
|
case ^Comp_Lit:
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
r.elems = clone(r.elems)
|
r.elems = clone(r.elems)
|
||||||
|
|
||||||
case Tag_Expr:
|
case ^Tag_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Unary_Expr:
|
case ^Unary_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Binary_Expr:
|
case ^Binary_Expr:
|
||||||
r.left = clone(r.left)
|
r.left = clone(r.left)
|
||||||
r.right = clone(r.right)
|
r.right = clone(r.right)
|
||||||
case Paren_Expr:
|
case ^Paren_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Selector_Expr:
|
case ^Selector_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.field = auto_cast clone(r.field)
|
r.field = auto_cast clone(r.field)
|
||||||
case Implicit_Selector_Expr:
|
case ^Implicit_Selector_Expr:
|
||||||
r.field = auto_cast clone(r.field)
|
r.field = auto_cast clone(r.field)
|
||||||
case Selector_Call_Expr:
|
case ^Selector_Call_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.call = auto_cast clone(r.call)
|
r.call = auto_cast clone(r.call)
|
||||||
case Index_Expr:
|
case ^Index_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.index = clone(r.index)
|
r.index = clone(r.index)
|
||||||
case Matrix_Index_Expr:
|
case ^Matrix_Index_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.row_index = clone(r.row_index)
|
r.row_index = clone(r.row_index)
|
||||||
r.column_index = clone(r.column_index)
|
r.column_index = clone(r.column_index)
|
||||||
case Deref_Expr:
|
case ^Deref_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Slice_Expr:
|
case ^Slice_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.low = clone(r.low)
|
r.low = clone(r.low)
|
||||||
r.high = clone(r.high)
|
r.high = clone(r.high)
|
||||||
case Call_Expr:
|
case ^Call_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.args = clone(r.args)
|
r.args = clone(r.args)
|
||||||
case Field_Value:
|
case ^Field_Value:
|
||||||
r.field = clone(r.field)
|
r.field = clone(r.field)
|
||||||
r.value = clone(r.value)
|
r.value = clone(r.value)
|
||||||
case Ternary_If_Expr:
|
case ^Ternary_If_Expr:
|
||||||
r.x = clone(r.x)
|
r.x = clone(r.x)
|
||||||
r.cond = clone(r.cond)
|
r.cond = clone(r.cond)
|
||||||
r.y = clone(r.y)
|
r.y = clone(r.y)
|
||||||
case Ternary_When_Expr:
|
case ^Ternary_When_Expr:
|
||||||
r.x = clone(r.x)
|
r.x = clone(r.x)
|
||||||
r.cond = clone(r.cond)
|
r.cond = clone(r.cond)
|
||||||
r.y = clone(r.y)
|
r.y = clone(r.y)
|
||||||
case Or_Else_Expr:
|
case ^Or_Else_Expr:
|
||||||
r.x = clone(r.x)
|
r.x = clone(r.x)
|
||||||
r.y = clone(r.y)
|
r.y = clone(r.y)
|
||||||
case Or_Return_Expr:
|
case ^Or_Return_Expr:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Type_Assertion:
|
case ^Type_Assertion:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
case Type_Cast:
|
case ^Type_Cast:
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Auto_Cast:
|
case ^Auto_Cast:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Inline_Asm_Expr:
|
case ^Inline_Asm_Expr:
|
||||||
r.param_types = clone(r.param_types)
|
r.param_types = clone(r.param_types)
|
||||||
r.return_type = clone(r.return_type)
|
r.return_type = clone(r.return_type)
|
||||||
r.constraints_string = clone(r.constraints_string)
|
r.constraints_string = clone(r.constraints_string)
|
||||||
r.asm_string = clone(r.asm_string)
|
r.asm_string = clone(r.asm_string)
|
||||||
|
|
||||||
case Bad_Stmt:
|
case ^Bad_Stmt:
|
||||||
// empty
|
// empty
|
||||||
case Empty_Stmt:
|
case ^Empty_Stmt:
|
||||||
// empty
|
// empty
|
||||||
case Expr_Stmt:
|
case ^Expr_Stmt:
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
case Tag_Stmt:
|
case ^Tag_Stmt:
|
||||||
r.stmt = clone(r.stmt)
|
r.stmt = clone(r.stmt)
|
||||||
|
|
||||||
case Assign_Stmt:
|
case ^Assign_Stmt:
|
||||||
r.lhs = clone(r.lhs)
|
r.lhs = clone(r.lhs)
|
||||||
r.rhs = clone(r.rhs)
|
r.rhs = clone(r.rhs)
|
||||||
case Block_Stmt:
|
case ^Block_Stmt:
|
||||||
r.label = clone(r.label)
|
r.label = clone(r.label)
|
||||||
r.stmts = clone(r.stmts)
|
r.stmts = clone(r.stmts)
|
||||||
case If_Stmt:
|
case ^If_Stmt:
|
||||||
r.label = clone(r.label)
|
r.label = clone(r.label)
|
||||||
r.init = clone(r.init)
|
r.init = clone(r.init)
|
||||||
r.cond = clone(r.cond)
|
r.cond = clone(r.cond)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
r.else_stmt = clone(r.else_stmt)
|
r.else_stmt = clone(r.else_stmt)
|
||||||
case When_Stmt:
|
case ^When_Stmt:
|
||||||
r.cond = clone(r.cond)
|
r.cond = clone(r.cond)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
r.else_stmt = clone(r.else_stmt)
|
r.else_stmt = clone(r.else_stmt)
|
||||||
case Return_Stmt:
|
case ^Return_Stmt:
|
||||||
r.results = clone(r.results)
|
r.results = clone(r.results)
|
||||||
case Defer_Stmt:
|
case ^Defer_Stmt:
|
||||||
r.stmt = clone(r.stmt)
|
r.stmt = clone(r.stmt)
|
||||||
case For_Stmt:
|
case ^For_Stmt:
|
||||||
r.label = clone(r.label)
|
r.label = clone(r.label)
|
||||||
r.init = clone(r.init)
|
r.init = clone(r.init)
|
||||||
r.cond = clone(r.cond)
|
r.cond = clone(r.cond)
|
||||||
r.post = clone(r.post)
|
r.post = clone(r.post)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Range_Stmt:
|
case ^Range_Stmt:
|
||||||
r.label = clone(r.label)
|
r.label = clone(r.label)
|
||||||
r.vals = clone(r.vals)
|
r.vals = clone(r.vals)
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Case_Clause:
|
case ^Inline_Range_Stmt:
|
||||||
|
r.label = clone(r.label)
|
||||||
|
r.val0 = clone(r.val0)
|
||||||
|
r.val1 = clone(r.val1)
|
||||||
|
r.expr = clone(r.expr)
|
||||||
|
r.body = clone(r.body)
|
||||||
|
case ^Case_Clause:
|
||||||
r.list = clone(r.list)
|
r.list = clone(r.list)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Switch_Stmt:
|
case ^Switch_Stmt:
|
||||||
r.label = clone(r.label)
|
r.label = clone(r.label)
|
||||||
r.init = clone(r.init)
|
r.init = clone(r.init)
|
||||||
r.cond = clone(r.cond)
|
r.cond = clone(r.cond)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Type_Switch_Stmt:
|
case ^Type_Switch_Stmt:
|
||||||
r.label = clone(r.label)
|
r.label = clone(r.label)
|
||||||
r.tag = clone(r.tag)
|
r.tag = clone(r.tag)
|
||||||
r.expr = clone(r.expr)
|
r.expr = clone(r.expr)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Branch_Stmt:
|
case ^Branch_Stmt:
|
||||||
r.label = auto_cast clone(r.label)
|
r.label = auto_cast clone(r.label)
|
||||||
case Using_Stmt:
|
case ^Using_Stmt:
|
||||||
r.list = clone(r.list)
|
r.list = clone(r.list)
|
||||||
case Bad_Decl:
|
case ^Bad_Decl:
|
||||||
case Value_Decl:
|
case ^Value_Decl:
|
||||||
r.attributes = clone(r.attributes)
|
r.attributes = clone(r.attributes)
|
||||||
r.names = clone(r.names)
|
r.names = clone(r.names)
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
r.values = clone(r.values)
|
r.values = clone(r.values)
|
||||||
case Package_Decl:
|
case ^Package_Decl:
|
||||||
case Import_Decl:
|
case ^Import_Decl:
|
||||||
case Foreign_Block_Decl:
|
case ^Foreign_Block_Decl:
|
||||||
r.attributes = clone(r.attributes)
|
r.attributes = clone(r.attributes)
|
||||||
r.foreign_library = clone(r.foreign_library)
|
r.foreign_library = clone(r.foreign_library)
|
||||||
r.body = clone(r.body)
|
r.body = clone(r.body)
|
||||||
case Foreign_Import_Decl:
|
case ^Foreign_Import_Decl:
|
||||||
r.name = auto_cast clone(r.name)
|
r.name = auto_cast clone(r.name)
|
||||||
case Proc_Group:
|
case ^Proc_Group:
|
||||||
r.args = clone(r.args)
|
r.args = clone(r.args)
|
||||||
case Attribute:
|
case ^Attribute:
|
||||||
r.elems = clone(r.elems)
|
r.elems = clone(r.elems)
|
||||||
case Field:
|
case ^Field:
|
||||||
r.names = clone(r.names)
|
r.names = clone(r.names)
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
r.default_value = clone(r.default_value)
|
r.default_value = clone(r.default_value)
|
||||||
case Field_List:
|
case ^Field_List:
|
||||||
r.list = clone(r.list)
|
r.list = clone(r.list)
|
||||||
case Typeid_Type:
|
case ^Typeid_Type:
|
||||||
r.specialization = clone(r.specialization)
|
r.specialization = clone(r.specialization)
|
||||||
case Helper_Type:
|
case ^Helper_Type:
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
case Distinct_Type:
|
case ^Distinct_Type:
|
||||||
r.type = clone(r.type)
|
r.type = clone(r.type)
|
||||||
case Poly_Type:
|
case ^Poly_Type:
|
||||||
r.type = auto_cast clone(r.type)
|
r.type = auto_cast clone(r.type)
|
||||||
r.specialization = clone(r.specialization)
|
r.specialization = clone(r.specialization)
|
||||||
case Proc_Type:
|
case ^Proc_Type:
|
||||||
r.params = auto_cast clone(r.params)
|
r.params = auto_cast clone(r.params)
|
||||||
r.results = auto_cast clone(r.results)
|
r.results = auto_cast clone(r.results)
|
||||||
case Pointer_Type:
|
case ^Pointer_Type:
|
||||||
r.elem = clone(r.elem)
|
r.elem = clone(r.elem)
|
||||||
case Multi_Pointer_Type:
|
case ^Multi_Pointer_Type:
|
||||||
r.elem = clone(r.elem)
|
r.elem = clone(r.elem)
|
||||||
case Array_Type:
|
case ^Array_Type:
|
||||||
r.len = clone(r.len)
|
r.len = clone(r.len)
|
||||||
r.elem = clone(r.elem)
|
r.elem = clone(r.elem)
|
||||||
case Dynamic_Array_Type:
|
case ^Dynamic_Array_Type:
|
||||||
r.elem = clone(r.elem)
|
r.elem = clone(r.elem)
|
||||||
case Struct_Type:
|
case ^Struct_Type:
|
||||||
r.poly_params = auto_cast clone(r.poly_params)
|
r.poly_params = auto_cast clone(r.poly_params)
|
||||||
r.align = clone(r.align)
|
r.align = clone(r.align)
|
||||||
r.fields = auto_cast clone(r.fields)
|
r.fields = auto_cast clone(r.fields)
|
||||||
case Union_Type:
|
case ^Union_Type:
|
||||||
r.poly_params = auto_cast clone(r.poly_params)
|
r.poly_params = auto_cast clone(r.poly_params)
|
||||||
r.align = clone(r.align)
|
r.align = clone(r.align)
|
||||||
r.variants = clone(r.variants)
|
r.variants = clone(r.variants)
|
||||||
case Enum_Type:
|
case ^Enum_Type:
|
||||||
r.base_type = clone(r.base_type)
|
r.base_type = clone(r.base_type)
|
||||||
r.fields = clone(r.fields)
|
r.fields = clone(r.fields)
|
||||||
case Bit_Set_Type:
|
case ^Bit_Set_Type:
|
||||||
r.elem = clone(r.elem)
|
r.elem = clone(r.elem)
|
||||||
r.underlying = clone(r.underlying)
|
r.underlying = clone(r.underlying)
|
||||||
case Map_Type:
|
case ^Map_Type:
|
||||||
r.key = clone(r.key)
|
r.key = clone(r.key)
|
||||||
r.value = clone(r.value)
|
r.value = clone(r.value)
|
||||||
case Matrix_Type:
|
case ^Matrix_Type:
|
||||||
r.row_count = clone(r.row_count)
|
r.row_count = clone(r.row_count)
|
||||||
r.column_count = clone(r.column_count)
|
r.column_count = clone(r.column_count)
|
||||||
r.elem = clone(r.elem)
|
r.elem = clone(r.elem)
|
||||||
|
case ^Relative_Type:
|
||||||
|
r.tag = clone(r.tag)
|
||||||
|
r.type = clone(r.type)
|
||||||
case:
|
case:
|
||||||
fmt.panicf("Unhandled node kind: %T", r)
|
fmt.panicf("Unhandled node kind: %v", r)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|||||||
+81
-78
@@ -52,71 +52,74 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
v := v
|
v := v
|
||||||
|
if v == nil || node == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if v = v->visit(node); v == nil {
|
if v = v->visit(node); v == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n in &node.derived {
|
switch n in &node.derived {
|
||||||
case File:
|
case ^File:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
walk_stmt_list(v, n.decls[:])
|
walk_stmt_list(v, n.decls[:])
|
||||||
case Package:
|
case ^Package:
|
||||||
for _, f in n.files {
|
for _, f in n.files {
|
||||||
walk(v, f)
|
walk(v, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Comment_Group:
|
case ^Comment_Group:
|
||||||
// empty
|
// empty
|
||||||
case Bad_Expr:
|
case ^Bad_Expr:
|
||||||
case Ident:
|
case ^Ident:
|
||||||
case Implicit:
|
case ^Implicit:
|
||||||
case Undef:
|
case ^Undef:
|
||||||
case Basic_Lit:
|
case ^Basic_Lit:
|
||||||
case Basic_Directive:
|
case ^Basic_Directive:
|
||||||
case Ellipsis:
|
case ^Ellipsis:
|
||||||
if n.expr != nil {
|
if n.expr != nil {
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
}
|
}
|
||||||
case Proc_Lit:
|
case ^Proc_Lit:
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
walk_expr_list(v, n.where_clauses)
|
walk_expr_list(v, n.where_clauses)
|
||||||
case Comp_Lit:
|
case ^Comp_Lit:
|
||||||
if n.type != nil {
|
if n.type != nil {
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
}
|
}
|
||||||
walk_expr_list(v, n.elems)
|
walk_expr_list(v, n.elems)
|
||||||
case Tag_Expr:
|
case ^Tag_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Unary_Expr:
|
case ^Unary_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Binary_Expr:
|
case ^Binary_Expr:
|
||||||
walk(v, n.left)
|
walk(v, n.left)
|
||||||
walk(v, n.right)
|
walk(v, n.right)
|
||||||
case Paren_Expr:
|
case ^Paren_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Selector_Expr:
|
case ^Selector_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk(v, n.field)
|
walk(v, n.field)
|
||||||
case Implicit_Selector_Expr:
|
case ^Implicit_Selector_Expr:
|
||||||
walk(v, n.field)
|
walk(v, n.field)
|
||||||
case Selector_Call_Expr:
|
case ^Selector_Call_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk(v, n.call)
|
walk(v, n.call)
|
||||||
case Index_Expr:
|
case ^Index_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk(v, n.index)
|
walk(v, n.index)
|
||||||
case Matrix_Index_Expr:
|
case ^Matrix_Index_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk(v, n.row_index)
|
walk(v, n.row_index)
|
||||||
walk(v, n.column_index)
|
walk(v, n.column_index)
|
||||||
case Deref_Expr:
|
case ^Deref_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Slice_Expr:
|
case ^Slice_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
if n.low != nil {
|
if n.low != nil {
|
||||||
walk(v, n.low)
|
walk(v, n.low)
|
||||||
@@ -124,57 +127,57 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
if n.high != nil {
|
if n.high != nil {
|
||||||
walk(v, n.high)
|
walk(v, n.high)
|
||||||
}
|
}
|
||||||
case Call_Expr:
|
case ^Call_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk_expr_list(v, n.args)
|
walk_expr_list(v, n.args)
|
||||||
case Field_Value:
|
case ^Field_Value:
|
||||||
walk(v, n.field)
|
walk(v, n.field)
|
||||||
walk(v, n.value)
|
walk(v, n.value)
|
||||||
case Ternary_If_Expr:
|
case ^Ternary_If_Expr:
|
||||||
walk(v, n.x)
|
walk(v, n.x)
|
||||||
walk(v, n.cond)
|
walk(v, n.cond)
|
||||||
walk(v, n.y)
|
walk(v, n.y)
|
||||||
case Ternary_When_Expr:
|
case ^Ternary_When_Expr:
|
||||||
walk(v, n.x)
|
walk(v, n.x)
|
||||||
walk(v, n.cond)
|
walk(v, n.cond)
|
||||||
walk(v, n.y)
|
walk(v, n.y)
|
||||||
case Or_Else_Expr:
|
case ^Or_Else_Expr:
|
||||||
walk(v, n.x)
|
walk(v, n.x)
|
||||||
walk(v, n.y)
|
walk(v, n.y)
|
||||||
case Or_Return_Expr:
|
case ^Or_Return_Expr:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Type_Assertion:
|
case ^Type_Assertion:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
if n.type != nil {
|
if n.type != nil {
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
}
|
}
|
||||||
case Type_Cast:
|
case ^Type_Cast:
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Auto_Cast:
|
case ^Auto_Cast:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Inline_Asm_Expr:
|
case ^Inline_Asm_Expr:
|
||||||
walk_expr_list(v, n.param_types)
|
walk_expr_list(v, n.param_types)
|
||||||
walk(v, n.return_type)
|
walk(v, n.return_type)
|
||||||
walk(v, n.constraints_string)
|
walk(v, n.constraints_string)
|
||||||
walk(v, n.asm_string)
|
walk(v, n.asm_string)
|
||||||
|
|
||||||
|
|
||||||
case Bad_Stmt:
|
case ^Bad_Stmt:
|
||||||
case Empty_Stmt:
|
case ^Empty_Stmt:
|
||||||
case Expr_Stmt:
|
case ^Expr_Stmt:
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
case Tag_Stmt:
|
case ^Tag_Stmt:
|
||||||
walk(v, n.stmt)
|
walk(v, n.stmt)
|
||||||
case Assign_Stmt:
|
case ^Assign_Stmt:
|
||||||
walk_expr_list(v, n.lhs)
|
walk_expr_list(v, n.lhs)
|
||||||
walk_expr_list(v, n.rhs)
|
walk_expr_list(v, n.rhs)
|
||||||
case Block_Stmt:
|
case ^Block_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
walk_stmt_list(v, n.stmts)
|
walk_stmt_list(v, n.stmts)
|
||||||
case If_Stmt:
|
case ^If_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
@@ -186,17 +189,17 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
if n.else_stmt != nil {
|
if n.else_stmt != nil {
|
||||||
walk(v, n.else_stmt)
|
walk(v, n.else_stmt)
|
||||||
}
|
}
|
||||||
case When_Stmt:
|
case ^When_Stmt:
|
||||||
walk(v, n.cond)
|
walk(v, n.cond)
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
if n.else_stmt != nil {
|
if n.else_stmt != nil {
|
||||||
walk(v, n.else_stmt)
|
walk(v, n.else_stmt)
|
||||||
}
|
}
|
||||||
case Return_Stmt:
|
case ^Return_Stmt:
|
||||||
walk_expr_list(v, n.results)
|
walk_expr_list(v, n.results)
|
||||||
case Defer_Stmt:
|
case ^Defer_Stmt:
|
||||||
walk(v, n.stmt)
|
walk(v, n.stmt)
|
||||||
case For_Stmt:
|
case ^For_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
@@ -210,7 +213,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.post)
|
walk(v, n.post)
|
||||||
}
|
}
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
case Range_Stmt:
|
case ^Range_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
@@ -221,7 +224,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
}
|
}
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
case Inline_Range_Stmt:
|
case ^Inline_Range_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
@@ -233,10 +236,10 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
}
|
}
|
||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
case Case_Clause:
|
case ^Case_Clause:
|
||||||
walk_expr_list(v, n.list)
|
walk_expr_list(v, n.list)
|
||||||
walk_stmt_list(v, n.body)
|
walk_stmt_list(v, n.body)
|
||||||
case Switch_Stmt:
|
case ^Switch_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
@@ -247,7 +250,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.cond)
|
walk(v, n.cond)
|
||||||
}
|
}
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
case Type_Switch_Stmt:
|
case ^Type_Switch_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
@@ -258,16 +261,16 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.expr)
|
walk(v, n.expr)
|
||||||
}
|
}
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
case Branch_Stmt:
|
case ^Branch_Stmt:
|
||||||
if n.label != nil {
|
if n.label != nil {
|
||||||
walk(v, n.label)
|
walk(v, n.label)
|
||||||
}
|
}
|
||||||
case Using_Stmt:
|
case ^Using_Stmt:
|
||||||
walk_expr_list(v, n.list)
|
walk_expr_list(v, n.list)
|
||||||
|
|
||||||
|
|
||||||
case Bad_Decl:
|
case ^Bad_Decl:
|
||||||
case Value_Decl:
|
case ^Value_Decl:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
@@ -280,21 +283,21 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
if n.comment != nil {
|
if n.comment != nil {
|
||||||
walk(v, n.comment)
|
walk(v, n.comment)
|
||||||
}
|
}
|
||||||
case Package_Decl:
|
case ^Package_Decl:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
if n.comment != nil {
|
if n.comment != nil {
|
||||||
walk(v, n.comment)
|
walk(v, n.comment)
|
||||||
}
|
}
|
||||||
case Import_Decl:
|
case ^Import_Decl:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
if n.comment != nil {
|
if n.comment != nil {
|
||||||
walk(v, n.comment)
|
walk(v, n.comment)
|
||||||
}
|
}
|
||||||
case Foreign_Block_Decl:
|
case ^Foreign_Block_Decl:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
@@ -303,7 +306,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.foreign_library)
|
walk(v, n.foreign_library)
|
||||||
}
|
}
|
||||||
walk(v, n.body)
|
walk(v, n.body)
|
||||||
case Foreign_Import_Decl:
|
case ^Foreign_Import_Decl:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
@@ -313,11 +316,11 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.comment)
|
walk(v, n.comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Proc_Group:
|
case ^Proc_Group:
|
||||||
walk_expr_list(v, n.args)
|
walk_expr_list(v, n.args)
|
||||||
case Attribute:
|
case ^Attribute:
|
||||||
walk_expr_list(v, n.elems)
|
walk_expr_list(v, n.elems)
|
||||||
case Field:
|
case ^Field:
|
||||||
if n.docs != nil {
|
if n.docs != nil {
|
||||||
walk(v, n.docs)
|
walk(v, n.docs)
|
||||||
}
|
}
|
||||||
@@ -331,31 +334,31 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
if n.comment != nil {
|
if n.comment != nil {
|
||||||
walk(v, n.comment)
|
walk(v, n.comment)
|
||||||
}
|
}
|
||||||
case Field_List:
|
case ^Field_List:
|
||||||
for x in n.list {
|
for x in n.list {
|
||||||
walk(v, x)
|
walk(v, x)
|
||||||
}
|
}
|
||||||
case Typeid_Type:
|
case ^Typeid_Type:
|
||||||
if n.specialization != nil {
|
if n.specialization != nil {
|
||||||
walk(v, n.specialization)
|
walk(v, n.specialization)
|
||||||
}
|
}
|
||||||
case Helper_Type:
|
case ^Helper_Type:
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
case Distinct_Type:
|
case ^Distinct_Type:
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
case Poly_Type:
|
case ^Poly_Type:
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
if n.specialization != nil {
|
if n.specialization != nil {
|
||||||
walk(v, n.specialization)
|
walk(v, n.specialization)
|
||||||
}
|
}
|
||||||
case Proc_Type:
|
case ^Proc_Type:
|
||||||
walk(v, n.params)
|
walk(v, n.params)
|
||||||
walk(v, n.results)
|
walk(v, n.results)
|
||||||
case Pointer_Type:
|
case ^Pointer_Type:
|
||||||
walk(v, n.elem)
|
walk(v, n.elem)
|
||||||
case Multi_Pointer_Type:
|
case ^Multi_Pointer_Type:
|
||||||
walk(v, n.elem)
|
walk(v, n.elem)
|
||||||
case Array_Type:
|
case ^Array_Type:
|
||||||
if n.tag != nil {
|
if n.tag != nil {
|
||||||
walk(v, n.tag)
|
walk(v, n.tag)
|
||||||
}
|
}
|
||||||
@@ -363,12 +366,12 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
walk(v, n.len)
|
walk(v, n.len)
|
||||||
}
|
}
|
||||||
walk(v, n.elem)
|
walk(v, n.elem)
|
||||||
case Dynamic_Array_Type:
|
case ^Dynamic_Array_Type:
|
||||||
if n.tag != nil {
|
if n.tag != nil {
|
||||||
walk(v, n.tag)
|
walk(v, n.tag)
|
||||||
}
|
}
|
||||||
walk(v, n.elem)
|
walk(v, n.elem)
|
||||||
case Struct_Type:
|
case ^Struct_Type:
|
||||||
if n.poly_params != nil {
|
if n.poly_params != nil {
|
||||||
walk(v, n.poly_params)
|
walk(v, n.poly_params)
|
||||||
}
|
}
|
||||||
@@ -377,7 +380,7 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
}
|
}
|
||||||
walk_expr_list(v, n.where_clauses)
|
walk_expr_list(v, n.where_clauses)
|
||||||
walk(v, n.fields)
|
walk(v, n.fields)
|
||||||
case Union_Type:
|
case ^Union_Type:
|
||||||
if n.poly_params != nil {
|
if n.poly_params != nil {
|
||||||
walk(v, n.poly_params)
|
walk(v, n.poly_params)
|
||||||
}
|
}
|
||||||
@@ -386,23 +389,23 @@ walk :: proc(v: ^Visitor, node: ^Node) {
|
|||||||
}
|
}
|
||||||
walk_expr_list(v, n.where_clauses)
|
walk_expr_list(v, n.where_clauses)
|
||||||
walk_expr_list(v, n.variants)
|
walk_expr_list(v, n.variants)
|
||||||
case Enum_Type:
|
case ^Enum_Type:
|
||||||
if n.base_type != nil {
|
if n.base_type != nil {
|
||||||
walk(v, n.base_type)
|
walk(v, n.base_type)
|
||||||
}
|
}
|
||||||
walk_expr_list(v, n.fields)
|
walk_expr_list(v, n.fields)
|
||||||
case Bit_Set_Type:
|
case ^Bit_Set_Type:
|
||||||
walk(v, n.elem)
|
walk(v, n.elem)
|
||||||
if n.underlying != nil {
|
if n.underlying != nil {
|
||||||
walk(v, n.underlying)
|
walk(v, n.underlying)
|
||||||
}
|
}
|
||||||
case Map_Type:
|
case ^Map_Type:
|
||||||
walk(v, n.key)
|
walk(v, n.key)
|
||||||
walk(v, n.value)
|
walk(v, n.value)
|
||||||
case Relative_Type:
|
case ^Relative_Type:
|
||||||
walk(v, n.tag)
|
walk(v, n.tag)
|
||||||
walk(v, n.type)
|
walk(v, n.type)
|
||||||
case Matrix_Type:
|
case ^Matrix_Type:
|
||||||
walk(v, n.row_count)
|
walk(v, n.row_count)
|
||||||
walk(v, n.column_count)
|
walk(v, n.column_count)
|
||||||
walk(v, n.elem)
|
walk(v, n.elem)
|
||||||
|
|||||||
+148
-94
@@ -195,10 +195,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
|
|||||||
for p.curr_tok.kind != .EOF {
|
for p.curr_tok.kind != .EOF {
|
||||||
stmt := parse_stmt(p)
|
stmt := parse_stmt(p)
|
||||||
if stmt != nil {
|
if stmt != nil {
|
||||||
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
|
if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok {
|
||||||
append(&p.file.decls, stmt)
|
append(&p.file.decls, stmt)
|
||||||
if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil {
|
if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil {
|
||||||
if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok {
|
if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok {
|
||||||
error(p, stmt.pos, "procedure literal evaluated but not used")
|
error(p, stmt.pos, "procedure literal evaluated but not used")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,9 +428,21 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token {
|
|||||||
str := tokenizer.token_to_string(token)
|
str := tokenizer.token_to_string(token)
|
||||||
error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str)
|
error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str)
|
||||||
}
|
}
|
||||||
return expect_token(p, .Close_Brace)
|
expect_brace := expect_token(p, .Close_Brace)
|
||||||
|
|
||||||
|
if expect_brace.kind != .Close_Brace {
|
||||||
|
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) {
|
||||||
|
advance_token(p)
|
||||||
|
}
|
||||||
|
return p.curr_tok
|
||||||
|
}
|
||||||
|
|
||||||
|
return expect_brace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_non_inserted_semicolon :: proc(tok: tokenizer.Token) -> bool {
|
||||||
|
return tok.kind == .Semicolon && tok.text != "\n"
|
||||||
|
}
|
||||||
|
|
||||||
is_blank_ident :: proc{
|
is_blank_ident :: proc{
|
||||||
is_blank_ident_string,
|
is_blank_ident_string,
|
||||||
@@ -447,7 +459,7 @@ is_blank_ident_token :: proc(tok: tokenizer.Token) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
is_blank_ident_node :: proc(node: ^ast.Node) -> bool {
|
is_blank_ident_node :: proc(node: ^ast.Node) -> bool {
|
||||||
if ident, ok := node.derived.(ast.Ident); ok {
|
if ident, ok := node.derived.(^ast.Ident); ok {
|
||||||
return is_blank_ident(ident.name)
|
return is_blank_ident(ident.name)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -490,34 +502,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n in node.derived {
|
#partial switch n in node.derived {
|
||||||
case ast.Empty_Stmt, ast.Block_Stmt:
|
case ^ast.Empty_Stmt, ^ast.Block_Stmt:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ast.If_Stmt, ast.When_Stmt,
|
case ^ast.If_Stmt, ^ast.When_Stmt,
|
||||||
ast.For_Stmt, ast.Range_Stmt, ast.Inline_Range_Stmt,
|
^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt,
|
||||||
ast.Switch_Stmt, ast.Type_Switch_Stmt:
|
^ast.Switch_Stmt, ^ast.Type_Switch_Stmt:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ast.Helper_Type:
|
case ^ast.Helper_Type:
|
||||||
return is_semicolon_optional_for_node(p, n.type)
|
return is_semicolon_optional_for_node(p, n.type)
|
||||||
case ast.Distinct_Type:
|
case ^ast.Distinct_Type:
|
||||||
return is_semicolon_optional_for_node(p, n.type)
|
return is_semicolon_optional_for_node(p, n.type)
|
||||||
case ast.Pointer_Type:
|
case ^ast.Pointer_Type:
|
||||||
return is_semicolon_optional_for_node(p, n.elem)
|
return is_semicolon_optional_for_node(p, n.elem)
|
||||||
case ast.Struct_Type, ast.Union_Type, ast.Enum_Type:
|
case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type:
|
||||||
// Require semicolon within a procedure body
|
// Require semicolon within a procedure body
|
||||||
return p.curr_proc == nil
|
return p.curr_proc == nil
|
||||||
case ast.Proc_Lit:
|
case ^ast.Proc_Lit:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ast.Package_Decl, ast.Import_Decl, ast.Foreign_Import_Decl:
|
case ^ast.Package_Decl, ^ast.Import_Decl, ^ast.Foreign_Import_Decl:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ast.Foreign_Block_Decl:
|
case ^ast.Foreign_Block_Decl:
|
||||||
return is_semicolon_optional_for_node(p, n.body)
|
return is_semicolon_optional_for_node(p, n.body)
|
||||||
|
|
||||||
case ast.Value_Decl:
|
case ^ast.Value_Decl:
|
||||||
if n.is_mutable {
|
if n.is_mutable {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -629,10 +641,10 @@ parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt {
|
|||||||
p.curr_tok.kind != .EOF {
|
p.curr_tok.kind != .EOF {
|
||||||
stmt := parse_stmt(p)
|
stmt := parse_stmt(p)
|
||||||
if stmt != nil {
|
if stmt != nil {
|
||||||
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
|
if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok {
|
||||||
append(&list, stmt)
|
append(&list, stmt)
|
||||||
if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil {
|
if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil {
|
||||||
if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok {
|
if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok {
|
||||||
error(p, stmt.pos, "procedure literal evaluated but not used")
|
error(p, stmt.pos, "procedure literal evaluated but not used")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -710,7 +722,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast.
|
|||||||
if stmt == nil {
|
if stmt == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if es, ok := stmt.derived.(ast.Expr_Stmt); ok {
|
if es, ok := stmt.derived.(^ast.Expr_Stmt); ok {
|
||||||
return es.expr
|
return es.expr
|
||||||
}
|
}
|
||||||
error(p, stmt.pos, "expected %s, found a simple statement", kind)
|
error(p, stmt.pos, "expected %s, found a simple statement", kind)
|
||||||
@@ -852,7 +864,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
|
|
||||||
if p.curr_tok.kind != .Semicolon {
|
if p.curr_tok.kind != .Semicolon {
|
||||||
cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
|
cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
|
||||||
if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
|
if as, ok := cond.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In {
|
||||||
is_range = true
|
is_range = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -894,7 +906,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
|
|
||||||
|
|
||||||
if is_range {
|
if is_range {
|
||||||
assign_stmt := cond.derived.(ast.Assign_Stmt)
|
assign_stmt := cond.derived.(^ast.Assign_Stmt)
|
||||||
vals := assign_stmt.lhs[:]
|
vals := assign_stmt.lhs[:]
|
||||||
|
|
||||||
rhs: ^ast.Expr
|
rhs: ^ast.Expr
|
||||||
@@ -975,7 +987,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
tag = as
|
tag = as
|
||||||
} else {
|
} else {
|
||||||
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
|
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In})
|
||||||
if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
|
if as, ok := tag.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In {
|
||||||
is_type_switch = true
|
is_type_switch = true
|
||||||
} else if parse_control_statement_semicolon_separator(p) {
|
} else if parse_control_statement_semicolon_separator(p) {
|
||||||
init = tag
|
init = tag
|
||||||
@@ -1062,14 +1074,14 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
|
|||||||
skip_possible_newline(p)
|
skip_possible_newline(p)
|
||||||
|
|
||||||
decl := parse_stmt(p)
|
decl := parse_stmt(p)
|
||||||
switch d in &decl.derived {
|
#partial switch d in decl.derived_stmt {
|
||||||
case ast.Value_Decl:
|
case ^ast.Value_Decl:
|
||||||
if d.docs == nil { d.docs = docs }
|
if d.docs == nil { d.docs = docs }
|
||||||
append(&d.attributes, attribute)
|
append(&d.attributes, attribute)
|
||||||
case ast.Foreign_Block_Decl:
|
case ^ast.Foreign_Block_Decl:
|
||||||
if d.docs == nil { d.docs = docs }
|
if d.docs == nil { d.docs = docs }
|
||||||
append(&d.attributes, attribute)
|
append(&d.attributes, attribute)
|
||||||
case ast.Foreign_Import_Decl:
|
case ^ast.Foreign_Import_Decl:
|
||||||
if d.docs == nil { d.docs = docs }
|
if d.docs == nil { d.docs = docs }
|
||||||
append(&d.attributes, attribute)
|
append(&d.attributes, attribute)
|
||||||
case:
|
case:
|
||||||
@@ -1083,11 +1095,11 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
|
|||||||
|
|
||||||
parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
|
parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||||
decl := parse_stmt(p)
|
decl := parse_stmt(p)
|
||||||
switch in decl.derived {
|
#partial switch in decl.derived_stmt {
|
||||||
case ast.Empty_Stmt, ast.Bad_Stmt, ast.Bad_Decl:
|
case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl:
|
||||||
// Ignore
|
// Ignore
|
||||||
return nil
|
return nil
|
||||||
case ast.When_Stmt, ast.Value_Decl:
|
case ^ast.When_Stmt, ^ast.Value_Decl:
|
||||||
return decl
|
return decl
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1291,13 +1303,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
case .Defer:
|
case .Defer:
|
||||||
tok := advance_token(p)
|
tok := advance_token(p)
|
||||||
stmt := parse_stmt(p)
|
stmt := parse_stmt(p)
|
||||||
switch s in stmt.derived {
|
#partial switch s in stmt.derived_stmt {
|
||||||
case ast.Empty_Stmt:
|
case ^ast.Empty_Stmt:
|
||||||
error(p, s.pos, "empty statement after defer (e.g. ';')")
|
error(p, s.pos, "empty statement after defer (e.g. ';')")
|
||||||
case ast.Defer_Stmt:
|
case ^ast.Defer_Stmt:
|
||||||
error(p, s.pos, "you cannot defer a defer statement")
|
error(p, s.pos, "you cannot defer a defer statement")
|
||||||
stmt = s.stmt
|
stmt = s.stmt
|
||||||
case ast.Return_Stmt:
|
case ^ast.Return_Stmt:
|
||||||
error(p, s.pos, "you cannot defer a return statement")
|
error(p, s.pos, "you cannot defer a return statement")
|
||||||
}
|
}
|
||||||
ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end)
|
ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end)
|
||||||
@@ -1312,7 +1324,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
results: [dynamic]^ast.Expr
|
results: [dynamic]^ast.Expr
|
||||||
for p.curr_tok.kind != .Semicolon {
|
for p.curr_tok.kind != .Semicolon && p.curr_tok.kind != .Close_Brace {
|
||||||
result := parse_expr(p, false)
|
result := parse_expr(p, false)
|
||||||
append(&results, result)
|
append(&results, result)
|
||||||
if p.curr_tok.kind != .Comma ||
|
if p.curr_tok.kind != .Comma ||
|
||||||
@@ -1369,8 +1381,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
expect_token_after(p, .Colon, "identifier list")
|
expect_token_after(p, .Colon, "identifier list")
|
||||||
decl := parse_value_decl(p, list, docs)
|
decl := parse_value_decl(p, list, docs)
|
||||||
if decl != nil {
|
if decl != nil {
|
||||||
switch d in &decl.derived {
|
#partial switch d in decl.derived_stmt {
|
||||||
case ast.Value_Decl:
|
case ^ast.Value_Decl:
|
||||||
d.is_using = true
|
d.is_using = true
|
||||||
return decl
|
return decl
|
||||||
}
|
}
|
||||||
@@ -1401,9 +1413,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
return stmt
|
return stmt
|
||||||
case "partial":
|
case "partial":
|
||||||
stmt := parse_stmt(p)
|
stmt := parse_stmt(p)
|
||||||
switch s in &stmt.derived {
|
#partial switch s in stmt.derived_stmt {
|
||||||
case ast.Switch_Stmt: s.partial = true
|
case ^ast.Switch_Stmt: s.partial = true
|
||||||
case ast.Type_Switch_Stmt: s.partial = true
|
case ^ast.Type_Switch_Stmt: s.partial = true
|
||||||
case: error(p, stmt.pos, "#partial can only be applied to a switch statement")
|
case: error(p, stmt.pos, "#partial can only be applied to a switch statement")
|
||||||
}
|
}
|
||||||
return stmt
|
return stmt
|
||||||
@@ -1548,11 +1560,11 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
|
convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
|
||||||
switch s in stmt.derived {
|
#partial switch s in stmt.derived_stmt {
|
||||||
case ast.Block_Stmt:
|
case ^ast.Block_Stmt:
|
||||||
error(p, stmt.pos, "expected a normal statement rather than a block statement")
|
error(p, stmt.pos, "expected a normal statement rather than a block statement")
|
||||||
return stmt
|
return stmt
|
||||||
case ast.Empty_Stmt:
|
case ^ast.Empty_Stmt:
|
||||||
error(p, stmt.pos, "expected a non-empty statement")
|
error(p, stmt.pos, "expected a non-empty statement")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1629,10 +1641,10 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
|
|||||||
|
|
||||||
id: ^ast.Expr = ident.expr
|
id: ^ast.Expr = ident.expr
|
||||||
|
|
||||||
switch n in ident.expr.derived {
|
#partial switch n in ident.expr.derived_expr {
|
||||||
case ast.Ident:
|
case ^ast.Ident:
|
||||||
case ast.Bad_Expr:
|
case ^ast.Bad_Expr:
|
||||||
case ast.Poly_Type:
|
case ^ast.Poly_Type:
|
||||||
if allow_poly_names {
|
if allow_poly_names {
|
||||||
if n.specialization == nil {
|
if n.specialization == nil {
|
||||||
break
|
break
|
||||||
@@ -1794,21 +1806,21 @@ check_procedure_name_list :: proc(p: ^Parser, names: []^ast.Expr) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
_, first_is_polymorphic := names[0].derived.(ast.Poly_Type)
|
_, first_is_polymorphic := names[0].derived.(^ast.Poly_Type)
|
||||||
any_polymorphic_names := first_is_polymorphic
|
any_polymorphic_names := first_is_polymorphic
|
||||||
|
|
||||||
for i := 1; i < len(names); i += 1 {
|
for i := 1; i < len(names); i += 1 {
|
||||||
name := names[i]
|
name := names[i]
|
||||||
|
|
||||||
if first_is_polymorphic {
|
if first_is_polymorphic {
|
||||||
if _, ok := name.derived.(ast.Poly_Type); ok {
|
if _, ok := name.derived.(^ast.Poly_Type); ok {
|
||||||
any_polymorphic_names = true
|
any_polymorphic_names = true
|
||||||
} else {
|
} else {
|
||||||
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
|
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
|
||||||
return any_polymorphic_names
|
return any_polymorphic_names
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if _, ok := name.derived.(ast.Poly_Type); ok {
|
if _, ok := name.derived.(^ast.Poly_Type); ok {
|
||||||
any_polymorphic_names = true
|
any_polymorphic_names = true
|
||||||
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
|
error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers")
|
||||||
return any_polymorphic_names
|
return any_polymorphic_names
|
||||||
@@ -1873,7 +1885,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
|||||||
if type == nil {
|
if type == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, ok := type.derived.(ast.Ellipsis)
|
_, ok := type.derived.(^ast.Ellipsis)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1891,7 +1903,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
|||||||
type = parse_var_type(p, allowed_flags)
|
type = parse_var_type(p, allowed_flags)
|
||||||
tt := ast.unparen_expr(type)
|
tt := ast.unparen_expr(type)
|
||||||
if is_signature && !any_polymorphic_names {
|
if is_signature && !any_polymorphic_names {
|
||||||
if ti, ok := tt.derived.(ast.Typeid_Type); ok && ti.specialization != nil {
|
if ti, ok := tt.derived.(^ast.Typeid_Type); ok && ti.specialization != nil {
|
||||||
error(p, tt.pos, "specialization of typeid is not allowed without polymorphic names")
|
error(p, tt.pos, "specialization of typeid is not allowed without polymorphic names")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1967,7 +1979,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
|||||||
p.curr_tok.kind != .EOF {
|
p.curr_tok.kind != .EOF {
|
||||||
prefix_flags := parse_field_prefixes(p)
|
prefix_flags := parse_field_prefixes(p)
|
||||||
param := parse_var_type(p, allowed_flags & {.Typeid_Token, .Ellipsis})
|
param := parse_var_type(p, allowed_flags & {.Typeid_Token, .Ellipsis})
|
||||||
if _, ok := param.derived.(ast.Ellipsis); ok {
|
if _, ok := param.derived.(^ast.Ellipsis); ok {
|
||||||
if seen_ellipsis {
|
if seen_ellipsis {
|
||||||
error(p, param.pos, "extra variadic parameter after ellipsis")
|
error(p, param.pos, "extra variadic parameter after ellipsis")
|
||||||
}
|
}
|
||||||
@@ -1994,8 +2006,8 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags
|
|||||||
|
|
||||||
names := make([]^ast.Expr, 1)
|
names := make([]^ast.Expr, 1)
|
||||||
names[0] = ast.new(ast.Ident, tok.pos, end_pos(tok))
|
names[0] = ast.new(ast.Ident, tok.pos, end_pos(tok))
|
||||||
switch ident in &names[0].derived {
|
#partial switch ident in names[0].derived_expr {
|
||||||
case ast.Ident:
|
case ^ast.Ident:
|
||||||
ident.name = tok.text
|
ident.name = tok.text
|
||||||
case:
|
case:
|
||||||
unreachable()
|
unreachable()
|
||||||
@@ -2125,12 +2137,12 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type {
|
|||||||
|
|
||||||
loop: for param in params.list {
|
loop: for param in params.list {
|
||||||
if param.type != nil {
|
if param.type != nil {
|
||||||
if _, ok := param.type.derived.(ast.Poly_Type); ok {
|
if _, ok := param.type.derived.(^ast.Poly_Type); ok {
|
||||||
is_generic = true
|
is_generic = true
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
for name in param.names {
|
for name in param.names {
|
||||||
if _, ok := name.derived.(ast.Poly_Type); ok {
|
if _, ok := name.derived.(^ast.Poly_Type); ok {
|
||||||
is_generic = true
|
is_generic = true
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
@@ -2167,13 +2179,13 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch e in &ast.unparen_expr(expr).derived {
|
#partial switch e in ast.unparen_expr(expr).derived_expr {
|
||||||
case ast.Proc_Lit:
|
case ^ast.Proc_Lit:
|
||||||
if e.inlining != .None && e.inlining != pi {
|
if e.inlining != .None && e.inlining != pi {
|
||||||
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal")
|
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal")
|
||||||
}
|
}
|
||||||
e.inlining = pi
|
e.inlining = pi
|
||||||
case ast.Call_Expr:
|
case ^ast.Call_Expr:
|
||||||
if e.inlining != .None && e.inlining != pi {
|
if e.inlining != .None && e.inlining != pi {
|
||||||
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call")
|
error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call")
|
||||||
}
|
}
|
||||||
@@ -2264,22 +2276,40 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
bd.name = name.text
|
bd.name = name.text
|
||||||
original_type := parse_type(p)
|
original_type := parse_type(p)
|
||||||
type := ast.unparen_expr(original_type)
|
type := ast.unparen_expr(original_type)
|
||||||
switch t in &type.derived {
|
#partial switch t in type.derived_expr {
|
||||||
case ast.Array_Type: t.tag = bd
|
case ^ast.Array_Type: t.tag = bd
|
||||||
case ast.Dynamic_Array_Type: t.tag = bd
|
case ^ast.Dynamic_Array_Type: t.tag = bd
|
||||||
case:
|
case:
|
||||||
error(p, original_type.pos, "expected an array type after #%s", name.text)
|
error(p, original_type.pos, "expected an array type after #%s", name.text)
|
||||||
}
|
}
|
||||||
return original_type
|
return original_type
|
||||||
|
|
||||||
case "partial":
|
case "partial":
|
||||||
|
tag := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
|
||||||
|
tag.tok = tok
|
||||||
|
tag.name = name.text
|
||||||
|
original_expr := parse_expr(p, lhs)
|
||||||
|
expr := ast.unparen_expr(original_expr)
|
||||||
|
#partial switch t in expr.derived_expr {
|
||||||
|
case ^ast.Comp_Lit:
|
||||||
|
t.tag = tag
|
||||||
|
case ^ast.Array_Type:
|
||||||
|
t.tag = tag
|
||||||
|
error(p, tok.pos, "#%s has been replaced with #sparse for non-contiguous enumerated array types", name.text)
|
||||||
|
case:
|
||||||
|
error(p, tok.pos, "expected a compound literal after #%s", name.text)
|
||||||
|
|
||||||
|
}
|
||||||
|
return original_expr
|
||||||
|
|
||||||
|
case "sparse":
|
||||||
tag := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
|
tag := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
|
||||||
tag.tok = tok
|
tag.tok = tok
|
||||||
tag.name = name.text
|
tag.name = name.text
|
||||||
original_type := parse_type(p)
|
original_type := parse_type(p)
|
||||||
type := ast.unparen_expr(original_type)
|
type := ast.unparen_expr(original_type)
|
||||||
switch t in &type.derived {
|
#partial switch t in type.derived_expr {
|
||||||
case ast.Array_Type:
|
case ^ast.Array_Type:
|
||||||
t.tag = tag
|
t.tag = tag
|
||||||
case:
|
case:
|
||||||
error(p, tok.pos, "expected an enumerated array type after #%s", name.text)
|
error(p, tok.pos, "expected an enumerated array type after #%s", name.text)
|
||||||
@@ -2319,7 +2349,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
return rt
|
return rt
|
||||||
|
|
||||||
case "force_inline", "force_no_inline":
|
case "force_inline", "force_no_inline":
|
||||||
return parse_inlining_operand(p, lhs, tok)
|
return parse_inlining_operand(p, lhs, name)
|
||||||
case:
|
case:
|
||||||
expr := parse_expr(p, lhs)
|
expr := parse_expr(p, lhs)
|
||||||
te := ast.new(ast.Tag_Expr, tok.pos, expr.pos)
|
te := ast.new(ast.Tag_Expr, tok.pos, expr.pos)
|
||||||
@@ -2600,8 +2630,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
tok := expect_token(p, .Union)
|
tok := expect_token(p, .Union)
|
||||||
poly_params: ^ast.Field_List
|
poly_params: ^ast.Field_List
|
||||||
align: ^ast.Expr
|
align: ^ast.Expr
|
||||||
is_maybe: bool
|
is_maybe: bool
|
||||||
is_no_nil: bool
|
is_no_nil: bool
|
||||||
|
is_shared_nil: bool
|
||||||
|
|
||||||
if allow_token(p, .Open_Paren) {
|
if allow_token(p, .Open_Paren) {
|
||||||
param_count: int
|
param_count: int
|
||||||
@@ -2633,12 +2664,34 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
|
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
|
||||||
}
|
}
|
||||||
is_no_nil = true
|
is_no_nil = true
|
||||||
|
case "shared_nil":
|
||||||
|
if is_shared_nil {
|
||||||
|
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
|
||||||
|
}
|
||||||
|
is_shared_nil = true
|
||||||
case:
|
case:
|
||||||
error(p, tag.pos, "invalid union tag '#%s", tag.text)
|
error(p, tag.pos, "invalid union tag '#%s", tag.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expr_level = prev_level
|
p.expr_level = prev_level
|
||||||
|
|
||||||
|
if is_no_nil && is_maybe {
|
||||||
|
error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together")
|
||||||
|
}
|
||||||
|
if is_no_nil && is_shared_nil {
|
||||||
|
error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together")
|
||||||
|
}
|
||||||
|
if is_shared_nil && is_maybe {
|
||||||
|
error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together")
|
||||||
|
}
|
||||||
|
|
||||||
|
union_kind := ast.Union_Type_Kind.Normal
|
||||||
|
switch {
|
||||||
|
case is_maybe: union_kind = .maybe
|
||||||
|
case is_no_nil: union_kind = .no_nil
|
||||||
|
case is_shared_nil: union_kind = .shared_nil
|
||||||
|
}
|
||||||
|
|
||||||
where_token: tokenizer.Token
|
where_token: tokenizer.Token
|
||||||
where_clauses: []^ast.Expr
|
where_clauses: []^ast.Expr
|
||||||
|
|
||||||
@@ -2659,7 +2712,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
variants: [dynamic]^ast.Expr
|
variants: [dynamic]^ast.Expr
|
||||||
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
|
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
|
||||||
type := parse_type(p)
|
type := parse_type(p)
|
||||||
if _, ok := type.derived.(ast.Bad_Expr); !ok {
|
if _, ok := type.derived.(^ast.Bad_Expr); !ok {
|
||||||
append(&variants, type)
|
append(&variants, type)
|
||||||
}
|
}
|
||||||
if !allow_token(p, .Comma) {
|
if !allow_token(p, .Comma) {
|
||||||
@@ -2669,14 +2722,15 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
|
|
||||||
close := expect_closing_brace_of_field_list(p)
|
close := expect_closing_brace_of_field_list(p)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ut := ast.new(ast.Union_Type, tok.pos, end_pos(close))
|
ut := ast.new(ast.Union_Type, tok.pos, end_pos(close))
|
||||||
ut.poly_params = poly_params
|
ut.poly_params = poly_params
|
||||||
ut.variants = variants[:]
|
ut.variants = variants[:]
|
||||||
ut.align = align
|
ut.align = align
|
||||||
ut.where_token = where_token
|
ut.where_token = where_token
|
||||||
ut.where_clauses = where_clauses
|
ut.where_clauses = where_clauses
|
||||||
ut.is_maybe = is_maybe
|
ut.kind = union_kind
|
||||||
ut.is_no_nil = is_no_nil
|
|
||||||
|
|
||||||
return ut
|
return ut
|
||||||
|
|
||||||
@@ -2834,19 +2888,19 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
|
|||||||
if val == nil {
|
if val == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
switch _ in val.derived {
|
#partial switch _ in val.derived_expr {
|
||||||
case ast.Bad_Expr,
|
case ^ast.Bad_Expr,
|
||||||
ast.Ident,
|
^ast.Ident,
|
||||||
ast.Selector_Expr,
|
^ast.Selector_Expr,
|
||||||
ast.Array_Type,
|
^ast.Array_Type,
|
||||||
ast.Struct_Type,
|
^ast.Struct_Type,
|
||||||
ast.Union_Type,
|
^ast.Union_Type,
|
||||||
ast.Enum_Type,
|
^ast.Enum_Type,
|
||||||
ast.Dynamic_Array_Type,
|
^ast.Dynamic_Array_Type,
|
||||||
ast.Map_Type,
|
^ast.Map_Type,
|
||||||
ast.Bit_Set_Type,
|
^ast.Bit_Set_Type,
|
||||||
ast.Matrix_Type,
|
^ast.Matrix_Type,
|
||||||
ast.Call_Expr:
|
^ast.Call_Expr:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -2968,7 +3022,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
|
|||||||
ce.close = close.pos
|
ce.close = close.pos
|
||||||
|
|
||||||
o := ast.unparen_expr(operand)
|
o := ast.unparen_expr(operand)
|
||||||
if se, ok := o.derived.(ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
|
if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
|
||||||
sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end)
|
sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end)
|
||||||
sce.expr = o
|
sce.expr = o
|
||||||
sce.call = ce
|
sce.call = ce
|
||||||
@@ -3398,13 +3452,13 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
|
|||||||
stmt := parse_stmt(p)
|
stmt := parse_stmt(p)
|
||||||
|
|
||||||
if stmt != nil {
|
if stmt != nil {
|
||||||
switch n in &stmt.derived {
|
#partial switch n in stmt.derived_stmt {
|
||||||
case ast.Block_Stmt: n.label = label
|
case ^ast.Block_Stmt: n.label = label
|
||||||
case ast.If_Stmt: n.label = label
|
case ^ast.If_Stmt: n.label = label
|
||||||
case ast.For_Stmt: n.label = label
|
case ^ast.For_Stmt: n.label = label
|
||||||
case ast.Switch_Stmt: n.label = label
|
case ^ast.Switch_Stmt: n.label = label
|
||||||
case ast.Type_Switch_Stmt: n.label = label
|
case ^ast.Type_Switch_Stmt: n.label = label
|
||||||
case ast.Range_Stmt: n.label = label
|
case ^ast.Range_Stmt: n.label = label
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+137
-96
@@ -342,16 +342,16 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v in &decl.derived {
|
#partial switch v in decl.derived_stmt {
|
||||||
case Expr_Stmt:
|
case ^Expr_Stmt:
|
||||||
move_line(p, decl.pos)
|
move_line(p, decl.pos)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
if p.config.semicolons {
|
if p.config.semicolons {
|
||||||
push_generic_token(p, .Semicolon, 0)
|
push_generic_token(p, .Semicolon, 0)
|
||||||
}
|
}
|
||||||
case When_Stmt:
|
case ^When_Stmt:
|
||||||
visit_stmt(p, cast(^Stmt)decl)
|
visit_stmt(p, cast(^Stmt)decl)
|
||||||
case Foreign_Import_Decl:
|
case ^Foreign_Import_Decl:
|
||||||
if len(v.attributes) > 0 {
|
if len(v.attributes) > 0 {
|
||||||
sort.sort(sort_attribute(&v.attributes))
|
sort.sort(sort_attribute(&v.attributes))
|
||||||
move_line(p, v.attributes[0].pos)
|
move_line(p, v.attributes[0].pos)
|
||||||
@@ -370,7 +370,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
|
|||||||
for path in v.fullpaths {
|
for path in v.fullpaths {
|
||||||
push_ident_token(p, path, 0)
|
push_ident_token(p, path, 0)
|
||||||
}
|
}
|
||||||
case Foreign_Block_Decl:
|
case ^Foreign_Block_Decl:
|
||||||
if len(v.attributes) > 0 {
|
if len(v.attributes) > 0 {
|
||||||
sort.sort(sort_attribute(&v.attributes))
|
sort.sort(sort_attribute(&v.attributes))
|
||||||
move_line(p, v.attributes[0].pos)
|
move_line(p, v.attributes[0].pos)
|
||||||
@@ -383,7 +383,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
|
|||||||
|
|
||||||
visit_expr(p, v.foreign_library)
|
visit_expr(p, v.foreign_library)
|
||||||
visit_stmt(p, v.body)
|
visit_stmt(p, v.body)
|
||||||
case Import_Decl:
|
case ^Import_Decl:
|
||||||
move_line(p, decl.pos)
|
move_line(p, decl.pos)
|
||||||
|
|
||||||
if v.name.text != "" {
|
if v.name.text != "" {
|
||||||
@@ -395,7 +395,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
|
|||||||
push_ident_token(p, v.fullpath, 1)
|
push_ident_token(p, v.fullpath, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Value_Decl:
|
case ^Value_Decl:
|
||||||
if len(v.attributes) > 0 {
|
if len(v.attributes) > 0 {
|
||||||
sort.sort(sort_attribute(&v.attributes))
|
sort.sort(sort_attribute(&v.attributes))
|
||||||
move_line(p, v.attributes[0].pos)
|
move_line(p, v.attributes[0].pos)
|
||||||
@@ -446,10 +446,10 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {
|
|||||||
add_semicolon := true
|
add_semicolon := true
|
||||||
|
|
||||||
for value in v.values {
|
for value in v.values {
|
||||||
switch a in value.derived {
|
#partial switch a in value.derived {
|
||||||
case Union_Type, Enum_Type, Struct_Type:
|
case ^Union_Type, ^Enum_Type, ^Struct_Type:
|
||||||
add_semicolon = false || called_in_stmt
|
add_semicolon = false || called_in_stmt
|
||||||
case Proc_Lit:
|
case ^Proc_Lit:
|
||||||
add_semicolon = false
|
add_semicolon = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,23 +516,34 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v in stmt.derived {
|
|
||||||
case Import_Decl:
|
|
||||||
visit_decl(p, cast(^Decl)stmt, true)
|
|
||||||
return
|
|
||||||
case Value_Decl:
|
|
||||||
visit_decl(p, cast(^Decl)stmt, true)
|
|
||||||
return
|
|
||||||
case Foreign_Import_Decl:
|
|
||||||
visit_decl(p, cast(^Decl)stmt, true)
|
|
||||||
return
|
|
||||||
case Foreign_Block_Decl:
|
|
||||||
visit_decl(p, cast(^Decl)stmt, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v in stmt.derived {
|
switch v in stmt.derived_stmt {
|
||||||
case Using_Stmt:
|
case ^Bad_Stmt:
|
||||||
|
case ^Bad_Decl:
|
||||||
|
case ^Package_Decl:
|
||||||
|
|
||||||
|
case ^Empty_Stmt:
|
||||||
|
push_generic_token(p, .Semicolon, 0)
|
||||||
|
case ^Tag_Stmt:
|
||||||
|
push_generic_token(p, .Hash, 1)
|
||||||
|
push_generic_token(p, v.op.kind, 1, v.op.text)
|
||||||
|
visit_stmt(p, v.stmt)
|
||||||
|
|
||||||
|
|
||||||
|
case ^Import_Decl:
|
||||||
|
visit_decl(p, cast(^Decl)stmt, true)
|
||||||
|
return
|
||||||
|
case ^Value_Decl:
|
||||||
|
visit_decl(p, cast(^Decl)stmt, true)
|
||||||
|
return
|
||||||
|
case ^Foreign_Import_Decl:
|
||||||
|
visit_decl(p, cast(^Decl)stmt, true)
|
||||||
|
return
|
||||||
|
case ^Foreign_Block_Decl:
|
||||||
|
visit_decl(p, cast(^Decl)stmt, true)
|
||||||
|
return
|
||||||
|
|
||||||
|
case ^Using_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
push_generic_token(p, .Using, 1)
|
push_generic_token(p, .Using, 1)
|
||||||
@@ -542,7 +553,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
if p.config.semicolons {
|
if p.config.semicolons {
|
||||||
push_generic_token(p, .Semicolon, 0)
|
push_generic_token(p, .Semicolon, 0)
|
||||||
}
|
}
|
||||||
case Block_Stmt:
|
case ^Block_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
if v.pos.line == v.end.line {
|
if v.pos.line == v.end.line {
|
||||||
@@ -572,7 +583,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
visit_end_brace(p, v.end)
|
visit_end_brace(p, v.end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case If_Stmt:
|
case ^If_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
if v.label != nil {
|
if v.label != nil {
|
||||||
@@ -595,7 +606,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
|
|
||||||
uses_do := false
|
uses_do := false
|
||||||
|
|
||||||
if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do {
|
if check_stmt, ok := v.body.derived.(^Block_Stmt); ok && check_stmt.uses_do {
|
||||||
uses_do = true
|
uses_do = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,7 +637,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
|
|
||||||
visit_stmt(p, v.else_stmt)
|
visit_stmt(p, v.else_stmt)
|
||||||
}
|
}
|
||||||
case Switch_Stmt:
|
case ^Switch_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
if v.label != nil {
|
if v.label != nil {
|
||||||
@@ -654,7 +665,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
|
|
||||||
visit_expr(p, v.cond)
|
visit_expr(p, v.cond)
|
||||||
visit_stmt(p, v.body)
|
visit_stmt(p, v.body)
|
||||||
case Case_Clause:
|
case ^Case_Clause:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
if !p.config.indent_cases {
|
if !p.config.indent_cases {
|
||||||
@@ -678,7 +689,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
if !p.config.indent_cases {
|
if !p.config.indent_cases {
|
||||||
indent(p)
|
indent(p)
|
||||||
}
|
}
|
||||||
case Type_Switch_Stmt:
|
case ^Type_Switch_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
hint_current_line(p, {.Switch_Stmt})
|
hint_current_line(p, {.Switch_Stmt})
|
||||||
@@ -696,7 +707,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
|
|
||||||
visit_stmt(p, v.tag)
|
visit_stmt(p, v.tag)
|
||||||
visit_stmt(p, v.body)
|
visit_stmt(p, v.body)
|
||||||
case Assign_Stmt:
|
case ^Assign_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
hint_current_line(p, {.Assign})
|
hint_current_line(p, {.Assign})
|
||||||
@@ -710,13 +721,13 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
if block_stmt && p.config.semicolons {
|
if block_stmt && p.config.semicolons {
|
||||||
push_generic_token(p, .Semicolon, 0)
|
push_generic_token(p, .Semicolon, 0)
|
||||||
}
|
}
|
||||||
case Expr_Stmt:
|
case ^Expr_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
if block_stmt && p.config.semicolons {
|
if block_stmt && p.config.semicolons {
|
||||||
push_generic_token(p, .Semicolon, 0)
|
push_generic_token(p, .Semicolon, 0)
|
||||||
}
|
}
|
||||||
case For_Stmt:
|
case ^For_Stmt:
|
||||||
// this should be simplified
|
// this should be simplified
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
@@ -753,7 +764,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
|
|
||||||
visit_stmt(p, v.body)
|
visit_stmt(p, v.body)
|
||||||
|
|
||||||
case Inline_Range_Stmt:
|
case ^Inline_Range_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
if v.label != nil {
|
if v.label != nil {
|
||||||
@@ -779,7 +790,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
visit_stmt(p, v.body)
|
visit_stmt(p, v.body)
|
||||||
|
|
||||||
case Range_Stmt:
|
case ^Range_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
if v.label != nil {
|
if v.label != nil {
|
||||||
@@ -805,7 +816,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
|
|
||||||
visit_stmt(p, v.body)
|
visit_stmt(p, v.body)
|
||||||
case Return_Stmt:
|
case ^Return_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
push_generic_token(p, .Return, 1)
|
push_generic_token(p, .Return, 1)
|
||||||
@@ -817,7 +828,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
if block_stmt && p.config.semicolons {
|
if block_stmt && p.config.semicolons {
|
||||||
push_generic_token(p, .Semicolon, 0)
|
push_generic_token(p, .Semicolon, 0)
|
||||||
}
|
}
|
||||||
case Defer_Stmt:
|
case ^Defer_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
push_generic_token(p, .Defer, 0)
|
push_generic_token(p, .Defer, 0)
|
||||||
|
|
||||||
@@ -826,7 +837,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
if p.config.semicolons {
|
if p.config.semicolons {
|
||||||
push_generic_token(p, .Semicolon, 0)
|
push_generic_token(p, .Semicolon, 0)
|
||||||
}
|
}
|
||||||
case When_Stmt:
|
case ^When_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
push_generic_token(p, .When, 1)
|
push_generic_token(p, .When, 1)
|
||||||
visit_expr(p, v.cond)
|
visit_expr(p, v.cond)
|
||||||
@@ -846,7 +857,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener
|
|||||||
visit_stmt(p, v.else_stmt)
|
visit_stmt(p, v.else_stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Branch_Stmt:
|
case ^Branch_Stmt:
|
||||||
move_line(p, v.pos)
|
move_line(p, v.pos)
|
||||||
|
|
||||||
push_generic_token(p, v.tok.kind, 0)
|
push_generic_token(p, v.tok.kind, 0)
|
||||||
@@ -918,8 +929,15 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
|
|
||||||
set_source_position(p, expr.pos)
|
set_source_position(p, expr.pos)
|
||||||
|
|
||||||
switch v in expr.derived {
|
switch v in expr.derived_expr {
|
||||||
case Inline_Asm_Expr:
|
case ^Bad_Expr:
|
||||||
|
|
||||||
|
case ^Tag_Expr:
|
||||||
|
push_generic_token(p, .Hash, 1)
|
||||||
|
push_generic_token(p, v.op.kind, 1, v.op.text)
|
||||||
|
visit_expr(p, v.expr)
|
||||||
|
|
||||||
|
case ^Inline_Asm_Expr:
|
||||||
push_generic_token(p, v.tok.kind, 1, v.tok.text)
|
push_generic_token(p, v.tok.kind, 1, v.tok.text)
|
||||||
|
|
||||||
push_generic_token(p, .Open_Paren, 1)
|
push_generic_token(p, .Open_Paren, 1)
|
||||||
@@ -936,42 +954,42 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
push_generic_token(p, .Comma, 0)
|
push_generic_token(p, .Comma, 0)
|
||||||
visit_expr(p, v.constraints_string)
|
visit_expr(p, v.constraints_string)
|
||||||
push_generic_token(p, .Close_Brace, 0)
|
push_generic_token(p, .Close_Brace, 0)
|
||||||
case Undef:
|
case ^Undef:
|
||||||
push_generic_token(p, .Undef, 1)
|
push_generic_token(p, .Undef, 1)
|
||||||
case Auto_Cast:
|
case ^Auto_Cast:
|
||||||
push_generic_token(p, v.op.kind, 1)
|
push_generic_token(p, v.op.kind, 1)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
case Ternary_If_Expr:
|
case ^Ternary_If_Expr:
|
||||||
visit_expr(p, v.x)
|
visit_expr(p, v.x)
|
||||||
push_generic_token(p, v.op1.kind, 1)
|
push_generic_token(p, v.op1.kind, 1)
|
||||||
visit_expr(p, v.cond)
|
visit_expr(p, v.cond)
|
||||||
push_generic_token(p, v.op2.kind, 1)
|
push_generic_token(p, v.op2.kind, 1)
|
||||||
visit_expr(p, v.y)
|
visit_expr(p, v.y)
|
||||||
case Ternary_When_Expr:
|
case ^Ternary_When_Expr:
|
||||||
visit_expr(p, v.x)
|
visit_expr(p, v.x)
|
||||||
push_generic_token(p, v.op1.kind, 1)
|
push_generic_token(p, v.op1.kind, 1)
|
||||||
visit_expr(p, v.cond)
|
visit_expr(p, v.cond)
|
||||||
push_generic_token(p, v.op2.kind, 1)
|
push_generic_token(p, v.op2.kind, 1)
|
||||||
visit_expr(p, v.y)
|
visit_expr(p, v.y)
|
||||||
case Or_Else_Expr:
|
case ^Or_Else_Expr:
|
||||||
visit_expr(p, v.x)
|
visit_expr(p, v.x)
|
||||||
push_generic_token(p, v.token.kind, 1)
|
push_generic_token(p, v.token.kind, 1)
|
||||||
visit_expr(p, v.y)
|
visit_expr(p, v.y)
|
||||||
case Or_Return_Expr:
|
case ^Or_Return_Expr:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
push_generic_token(p, v.token.kind, 1)
|
push_generic_token(p, v.token.kind, 1)
|
||||||
case Selector_Call_Expr:
|
case ^Selector_Call_Expr:
|
||||||
visit_expr(p, v.call.expr)
|
visit_expr(p, v.call.expr)
|
||||||
push_generic_token(p, .Open_Paren, 1)
|
push_generic_token(p, .Open_Paren, 1)
|
||||||
visit_exprs(p, v.call.args, {.Add_Comma})
|
visit_exprs(p, v.call.args, {.Add_Comma})
|
||||||
push_generic_token(p, .Close_Paren, 0)
|
push_generic_token(p, .Close_Paren, 0)
|
||||||
case Ellipsis:
|
case ^Ellipsis:
|
||||||
push_generic_token(p, .Ellipsis, 1)
|
push_generic_token(p, .Ellipsis, 1)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
case Relative_Type:
|
case ^Relative_Type:
|
||||||
visit_expr(p, v.tag)
|
visit_expr(p, v.tag)
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
case Slice_Expr:
|
case ^Slice_Expr:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
push_generic_token(p, .Open_Bracket, 0)
|
push_generic_token(p, .Open_Bracket, 0)
|
||||||
visit_expr(p, v.low)
|
visit_expr(p, v.low)
|
||||||
@@ -981,37 +999,37 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
visit_expr(p, v.high)
|
visit_expr(p, v.high)
|
||||||
}
|
}
|
||||||
push_generic_token(p, .Close_Bracket, 0)
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
case Ident:
|
case ^Ident:
|
||||||
if .Enforce_Poly_Names in options {
|
if .Enforce_Poly_Names in options {
|
||||||
push_generic_token(p, .Dollar, 1)
|
push_generic_token(p, .Dollar, 1)
|
||||||
push_ident_token(p, v.name, 0)
|
push_ident_token(p, v.name, 0)
|
||||||
} else {
|
} else {
|
||||||
push_ident_token(p, v.name, 1)
|
push_ident_token(p, v.name, 1)
|
||||||
}
|
}
|
||||||
case Deref_Expr:
|
case ^Deref_Expr:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
push_generic_token(p, v.op.kind, 0)
|
push_generic_token(p, v.op.kind, 0)
|
||||||
case Type_Cast:
|
case ^Type_Cast:
|
||||||
push_generic_token(p, v.tok.kind, 1)
|
push_generic_token(p, v.tok.kind, 1)
|
||||||
push_generic_token(p, .Open_Paren, 0)
|
push_generic_token(p, .Open_Paren, 0)
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
push_generic_token(p, .Close_Paren, 0)
|
push_generic_token(p, .Close_Paren, 0)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
case Basic_Directive:
|
case ^Basic_Directive:
|
||||||
push_generic_token(p, v.tok.kind, 1)
|
push_generic_token(p, v.tok.kind, 1)
|
||||||
push_ident_token(p, v.name, 0)
|
push_ident_token(p, v.name, 0)
|
||||||
case Distinct_Type:
|
case ^Distinct_Type:
|
||||||
push_generic_token(p, .Distinct, 1)
|
push_generic_token(p, .Distinct, 1)
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
case Dynamic_Array_Type:
|
case ^Dynamic_Array_Type:
|
||||||
visit_expr(p, v.tag)
|
visit_expr(p, v.tag)
|
||||||
push_generic_token(p, .Open_Bracket, 1)
|
push_generic_token(p, .Open_Bracket, 1)
|
||||||
push_generic_token(p, .Dynamic, 0)
|
push_generic_token(p, .Dynamic, 0)
|
||||||
push_generic_token(p, .Close_Bracket, 0)
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.elem)
|
visit_expr(p, v.elem)
|
||||||
case Bit_Set_Type:
|
case ^Bit_Set_Type:
|
||||||
push_generic_token(p, .Bit_Set, 1)
|
push_generic_token(p, .Bit_Set, 1)
|
||||||
push_generic_token(p, .Open_Bracket, 0)
|
push_generic_token(p, .Open_Bracket, 0)
|
||||||
|
|
||||||
@@ -1023,13 +1041,16 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
push_generic_token(p, .Close_Bracket, 0)
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
case Union_Type:
|
case ^Union_Type:
|
||||||
push_generic_token(p, .Union, 1)
|
push_generic_token(p, .Union, 1)
|
||||||
|
|
||||||
push_poly_params(p, v.poly_params)
|
push_poly_params(p, v.poly_params)
|
||||||
|
|
||||||
if v.is_maybe {
|
switch v.kind {
|
||||||
push_ident_token(p, "#maybe", 1)
|
case .Normal:
|
||||||
|
case .maybe: push_ident_token(p, "#maybe", 1)
|
||||||
|
case .no_nil: push_ident_token(p, "#no_nil", 1)
|
||||||
|
case .shared_nil: push_ident_token(p, "#shared_nil", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
push_where_clauses(p, v.where_clauses)
|
push_where_clauses(p, v.where_clauses)
|
||||||
@@ -1045,7 +1066,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
visit_exprs(p, v.variants, {.Add_Comma, .Trailing})
|
visit_exprs(p, v.variants, {.Add_Comma, .Trailing})
|
||||||
visit_end_brace(p, v.end)
|
visit_end_brace(p, v.end)
|
||||||
}
|
}
|
||||||
case Enum_Type:
|
case ^Enum_Type:
|
||||||
push_generic_token(p, .Enum, 1)
|
push_generic_token(p, .Enum, 1)
|
||||||
|
|
||||||
hint_current_line(p, {.Enum})
|
hint_current_line(p, {.Enum})
|
||||||
@@ -1068,7 +1089,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_source_position(p, v.end)
|
set_source_position(p, v.end)
|
||||||
case Struct_Type:
|
case ^Struct_Type:
|
||||||
push_generic_token(p, .Struct, 1)
|
push_generic_token(p, .Struct, 1)
|
||||||
|
|
||||||
hint_current_line(p, {.Struct})
|
hint_current_line(p, {.Struct})
|
||||||
@@ -1103,7 +1124,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_source_position(p, v.end)
|
set_source_position(p, v.end)
|
||||||
case Proc_Lit:
|
case ^Proc_Lit:
|
||||||
switch v.inlining {
|
switch v.inlining {
|
||||||
case .None:
|
case .None:
|
||||||
case .Inline:
|
case .Inline:
|
||||||
@@ -1112,7 +1133,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
push_ident_token(p, "#force_no_inline", 0)
|
push_ident_token(p, "#force_no_inline", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_proc_type(p, v.type^, true)
|
visit_proc_type(p, v.type, true)
|
||||||
|
|
||||||
push_where_clauses(p, v.where_clauses)
|
push_where_clauses(p, v.where_clauses)
|
||||||
|
|
||||||
@@ -1122,16 +1143,16 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
} else {
|
} else {
|
||||||
push_generic_token(p, .Undef, 1)
|
push_generic_token(p, .Undef, 1)
|
||||||
}
|
}
|
||||||
case Proc_Type:
|
case ^Proc_Type:
|
||||||
visit_proc_type(p, v)
|
visit_proc_type(p, v)
|
||||||
case Basic_Lit:
|
case ^Basic_Lit:
|
||||||
push_generic_token(p, v.tok.kind, 1, v.tok.text)
|
push_generic_token(p, v.tok.kind, 1, v.tok.text)
|
||||||
case Binary_Expr:
|
case ^Binary_Expr:
|
||||||
visit_binary_expr(p, v)
|
visit_binary_expr(p, v)
|
||||||
case Implicit_Selector_Expr:
|
case ^Implicit_Selector_Expr:
|
||||||
push_generic_token(p, .Period, 1)
|
push_generic_token(p, .Period, 1)
|
||||||
push_ident_token(p, v.field.name, 0)
|
push_ident_token(p, v.field.name, 0)
|
||||||
case Call_Expr:
|
case ^Call_Expr:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
|
|
||||||
push_format_token(p,
|
push_format_token(p,
|
||||||
@@ -1146,27 +1167,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
|
|
||||||
visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis)
|
visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis)
|
||||||
push_generic_token(p, .Close_Paren, 0)
|
push_generic_token(p, .Close_Paren, 0)
|
||||||
case Typeid_Type:
|
case ^Typeid_Type:
|
||||||
push_generic_token(p, .Typeid, 1)
|
push_generic_token(p, .Typeid, 1)
|
||||||
|
|
||||||
if v.specialization != nil {
|
if v.specialization != nil {
|
||||||
push_generic_token(p, .Quo, 0)
|
push_generic_token(p, .Quo, 0)
|
||||||
visit_expr(p, v.specialization)
|
visit_expr(p, v.specialization)
|
||||||
}
|
}
|
||||||
case Selector_Expr:
|
case ^Selector_Expr:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
push_generic_token(p, v.op.kind, 0)
|
push_generic_token(p, v.op.kind, 0)
|
||||||
visit_expr(p, v.field)
|
visit_expr(p, v.field)
|
||||||
case Paren_Expr:
|
case ^Paren_Expr:
|
||||||
push_generic_token(p, .Open_Paren, 1)
|
push_generic_token(p, .Open_Paren, 1)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
push_generic_token(p, .Close_Paren, 0)
|
push_generic_token(p, .Close_Paren, 0)
|
||||||
case Index_Expr:
|
case ^Index_Expr:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
push_generic_token(p, .Open_Bracket, 0)
|
push_generic_token(p, .Open_Bracket, 0)
|
||||||
visit_expr(p, v.index)
|
visit_expr(p, v.index)
|
||||||
push_generic_token(p, .Close_Bracket, 0)
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
case Proc_Group:
|
case ^Matrix_Index_Expr:
|
||||||
|
visit_expr(p, v.expr)
|
||||||
|
push_generic_token(p, .Open_Bracket, 0)
|
||||||
|
visit_expr(p, v.row_index)
|
||||||
|
push_generic_token(p, .Comma, 0)
|
||||||
|
visit_expr(p, v.column_index)
|
||||||
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
|
case ^Proc_Group:
|
||||||
push_generic_token(p, v.tok.kind, 1)
|
push_generic_token(p, v.tok.kind, 1)
|
||||||
|
|
||||||
if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line {
|
if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line {
|
||||||
@@ -1181,7 +1209,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
push_generic_token(p, .Close_Brace, 0)
|
push_generic_token(p, .Close_Brace, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Comp_Lit:
|
case ^Comp_Lit:
|
||||||
if v.type != nil {
|
if v.type != nil {
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
}
|
}
|
||||||
@@ -1198,18 +1226,18 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
push_generic_token(p, .Close_Brace, 0)
|
push_generic_token(p, .Close_Brace, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Unary_Expr:
|
case ^Unary_Expr:
|
||||||
push_generic_token(p, v.op.kind, 1)
|
push_generic_token(p, v.op.kind, 1)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
case Field_Value:
|
case ^Field_Value:
|
||||||
visit_expr(p, v.field)
|
visit_expr(p, v.field)
|
||||||
push_generic_token(p, .Eq, 1)
|
push_generic_token(p, .Eq, 1)
|
||||||
visit_expr(p, v.value)
|
visit_expr(p, v.value)
|
||||||
case Type_Assertion:
|
case ^Type_Assertion:
|
||||||
visit_expr(p, v.expr)
|
visit_expr(p, v.expr)
|
||||||
|
|
||||||
if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" {
|
if unary, ok := v.type.derived.(^Unary_Expr); ok && unary.op.text == "?" {
|
||||||
push_generic_token(p, .Period, 0)
|
push_generic_token(p, .Period, 0)
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
} else {
|
} else {
|
||||||
@@ -1219,13 +1247,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
push_generic_token(p, .Close_Paren, 0)
|
push_generic_token(p, .Close_Paren, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Pointer_Type:
|
case ^Pointer_Type:
|
||||||
push_generic_token(p, .Pointer, 1)
|
push_generic_token(p, .Pointer, 1)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.elem)
|
visit_expr(p, v.elem)
|
||||||
case Implicit:
|
case ^Implicit:
|
||||||
push_generic_token(p, v.tok.kind, 1)
|
push_generic_token(p, v.tok.kind, 1)
|
||||||
case Poly_Type:
|
case ^Poly_Type:
|
||||||
push_generic_token(p, .Dollar, 1)
|
push_generic_token(p, .Dollar, 1)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
@@ -1235,22 +1263,35 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) {
|
|||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.specialization)
|
visit_expr(p, v.specialization)
|
||||||
}
|
}
|
||||||
case Array_Type:
|
case ^Array_Type:
|
||||||
visit_expr(p, v.tag)
|
visit_expr(p, v.tag)
|
||||||
push_generic_token(p, .Open_Bracket, 1)
|
push_generic_token(p, .Open_Bracket, 1)
|
||||||
visit_expr(p, v.len)
|
visit_expr(p, v.len)
|
||||||
push_generic_token(p, .Close_Bracket, 0)
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.elem)
|
visit_expr(p, v.elem)
|
||||||
case Map_Type:
|
case ^Map_Type:
|
||||||
push_generic_token(p, .Map, 1)
|
push_generic_token(p, .Map, 1)
|
||||||
push_generic_token(p, .Open_Bracket, 0)
|
push_generic_token(p, .Open_Bracket, 0)
|
||||||
visit_expr(p, v.key)
|
visit_expr(p, v.key)
|
||||||
push_generic_token(p, .Close_Bracket, 0)
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
merge_next_token(p)
|
merge_next_token(p)
|
||||||
visit_expr(p, v.value)
|
visit_expr(p, v.value)
|
||||||
case Helper_Type:
|
case ^Helper_Type:
|
||||||
visit_expr(p, v.type)
|
visit_expr(p, v.type)
|
||||||
|
case ^Multi_Pointer_Type:
|
||||||
|
push_generic_token(p, .Open_Bracket, 1)
|
||||||
|
push_generic_token(p, .Pointer, 0)
|
||||||
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
|
visit_expr(p, v.elem)
|
||||||
|
case ^Matrix_Type:
|
||||||
|
push_generic_token(p, .Matrix, 1)
|
||||||
|
push_generic_token(p, .Open_Bracket, 0)
|
||||||
|
visit_expr(p, v.row_count)
|
||||||
|
push_generic_token(p, .Comma, 0)
|
||||||
|
visit_expr(p, v.column_count)
|
||||||
|
push_generic_token(p, .Close_Bracket, 0)
|
||||||
|
visit_expr(p, v.elem)
|
||||||
case:
|
case:
|
||||||
panic(fmt.aprint(expr.derived))
|
panic(fmt.aprint(expr.derived))
|
||||||
}
|
}
|
||||||
@@ -1348,7 +1389,7 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := List_Opt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := false) {
|
visit_proc_type :: proc(p: ^Printer, proc_type: ^ast.Proc_Type, is_proc_lit := false) {
|
||||||
if is_proc_lit {
|
if is_proc_lit {
|
||||||
push_format_token(p, Format_Token {
|
push_format_token(p, Format_Token {
|
||||||
kind = .Proc,
|
kind = .Proc,
|
||||||
@@ -1392,7 +1433,7 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa
|
|||||||
} else if len(proc_type.results.list) == 1 {
|
} else if len(proc_type.results.list) == 1 {
|
||||||
|
|
||||||
for name in proc_type.results.list[0].names {
|
for name in proc_type.results.list[0].names {
|
||||||
if ident, ok := name.derived.(ast.Ident); ok {
|
if ident, ok := name.derived.(^ast.Ident); ok {
|
||||||
if ident.name != "_" {
|
if ident.name != "_" {
|
||||||
use_parens = true
|
use_parens = true
|
||||||
}
|
}
|
||||||
@@ -1410,19 +1451,19 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) {
|
visit_binary_expr :: proc(p: ^Printer, binary: ^ast.Binary_Expr) {
|
||||||
move_line(p, binary.left.pos)
|
move_line(p, binary.left.pos)
|
||||||
|
|
||||||
if v, ok := binary.left.derived.(ast.Binary_Expr); ok {
|
if v, ok := binary.left.derived.(^ast.Binary_Expr); ok {
|
||||||
visit_binary_expr(p, v)
|
visit_binary_expr(p, v)
|
||||||
} else {
|
} else {
|
||||||
visit_expr(p, binary.left)
|
visit_expr(p, binary.left)
|
||||||
}
|
}
|
||||||
|
|
||||||
either_implicit_selector := false
|
either_implicit_selector := false
|
||||||
if _, ok := binary.left.derived.(ast.Implicit_Selector_Expr); ok {
|
if _, ok := binary.left.derived.(^ast.Implicit_Selector_Expr); ok {
|
||||||
either_implicit_selector = true
|
either_implicit_selector = true
|
||||||
} else if _, ok := binary.right.derived.(ast.Implicit_Selector_Expr); ok {
|
} else if _, ok := binary.right.derived.(^ast.Implicit_Selector_Expr); ok {
|
||||||
either_implicit_selector = true
|
either_implicit_selector = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1439,7 +1480,7 @@ visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) {
|
|||||||
move_line(p, binary.right.pos)
|
move_line(p, binary.right.pos)
|
||||||
|
|
||||||
|
|
||||||
if v, ok := binary.right.derived.(ast.Binary_Expr); ok {
|
if v, ok := binary.right.derived.(^ast.Binary_Expr); ok {
|
||||||
visit_binary_expr(p, v)
|
visit_binary_expr(p, v)
|
||||||
} else {
|
} else {
|
||||||
visit_expr(p, binary.right)
|
visit_expr(p, binary.right)
|
||||||
@@ -1499,7 +1540,7 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank :=
|
|||||||
named := false
|
named := false
|
||||||
|
|
||||||
for name in field.names {
|
for name in field.names {
|
||||||
if ident, ok := name.derived.(ast.Ident); ok {
|
if ident, ok := name.derived.(^ast.Ident); ok {
|
||||||
//for some reason the parser uses _ to mean empty
|
//for some reason the parser uses _ to mean empty
|
||||||
if ident.name != "_" || !remove_blank {
|
if ident.name != "_" || !remove_blank {
|
||||||
named = true
|
named = true
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
|
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||||
|
dirp: Dir
|
||||||
|
dirp, err = _fdopendir(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer _closedir(dirp)
|
||||||
|
|
||||||
|
dirpath: string
|
||||||
|
dirpath, err = absolute_path_from_handle(fd)
|
||||||
|
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer delete(dirpath)
|
||||||
|
|
||||||
|
n := n
|
||||||
|
size := n
|
||||||
|
if n <= 0 {
|
||||||
|
n = -1
|
||||||
|
size = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
dfi := make([dynamic]File_Info, 0, size, allocator)
|
||||||
|
|
||||||
|
for {
|
||||||
|
entry: Dirent
|
||||||
|
end_of_stream: bool
|
||||||
|
entry, err, end_of_stream = _readdir(dirp)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
for fi_ in dfi {
|
||||||
|
file_info_delete(fi_, allocator)
|
||||||
|
}
|
||||||
|
delete(dfi)
|
||||||
|
return
|
||||||
|
} else if end_of_stream {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fi_: File_Info
|
||||||
|
filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] })
|
||||||
|
|
||||||
|
if filename == "." || filename == ".." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
|
||||||
|
defer delete(fullpath, context.temp_allocator)
|
||||||
|
|
||||||
|
fi_, err = stat(fullpath, allocator)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
for fi__ in dfi {
|
||||||
|
file_info_delete(fi__, allocator)
|
||||||
|
}
|
||||||
|
delete(dfi)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
append(&dfi, fi_)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dfi[:], ERROR_NONE
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
|
import "core:mem"
|
||||||
|
|
||||||
|
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||||
|
dirp: Dir
|
||||||
|
dirp, err = _fdopendir(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer _closedir(dirp)
|
||||||
|
|
||||||
|
// XXX OpenBSD
|
||||||
|
dirpath: string
|
||||||
|
dirpath, err = absolute_path_from_handle(fd)
|
||||||
|
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer delete(dirpath)
|
||||||
|
|
||||||
|
n := n
|
||||||
|
size := n
|
||||||
|
if n <= 0 {
|
||||||
|
n = -1
|
||||||
|
size = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
dfi := make([dynamic]File_Info, 0, size, allocator)
|
||||||
|
|
||||||
|
for {
|
||||||
|
entry: Dirent
|
||||||
|
end_of_stream: bool
|
||||||
|
entry, err, end_of_stream = _readdir(dirp)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
for fi_ in dfi {
|
||||||
|
file_info_delete(fi_, allocator)
|
||||||
|
}
|
||||||
|
delete(dfi)
|
||||||
|
return
|
||||||
|
} else if end_of_stream {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fi_: File_Info
|
||||||
|
filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] })
|
||||||
|
|
||||||
|
if filename == "." || filename == ".." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
|
||||||
|
defer delete(fullpath, context.temp_allocator)
|
||||||
|
|
||||||
|
fi_, err = stat(fullpath, allocator)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
for fi__ in dfi {
|
||||||
|
file_info_delete(fi__, allocator)
|
||||||
|
}
|
||||||
|
delete(dfi)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
append(&dfi, fi_)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dfi[:], ERROR_NONE
|
||||||
|
}
|
||||||
@@ -82,6 +82,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
|||||||
wpath_search[len(wpath)+2] = 0
|
wpath_search[len(wpath)+2] = 0
|
||||||
|
|
||||||
path := cleanpath_from_buf(wpath)
|
path := cleanpath_from_buf(wpath)
|
||||||
|
defer delete(path)
|
||||||
|
|
||||||
find_data := &win32.WIN32_FIND_DATAW{}
|
find_data := &win32.WIN32_FIND_DATAW{}
|
||||||
find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data)
|
find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data)
|
||||||
|
|||||||
@@ -106,19 +106,23 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
|
|||||||
BUF_SIZE :: 386
|
BUF_SIZE :: 386
|
||||||
buf16: [BUF_SIZE]u16
|
buf16: [BUF_SIZE]u16
|
||||||
buf8: [4*BUF_SIZE]u8
|
buf8: [4*BUF_SIZE]u8
|
||||||
|
|
||||||
for n < len(b) && err == 0 {
|
for n < len(b) && err == 0 {
|
||||||
max_read := u32(min(BUF_SIZE, len(b)/4))
|
min_read := max(len(b)/4, 1 if len(b) > 0 else 0)
|
||||||
|
max_read := u32(min(BUF_SIZE, min_read))
|
||||||
|
if max_read == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
single_read_length: u32
|
single_read_length: u32
|
||||||
ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
|
ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
|
||||||
if !ok {
|
if !ok {
|
||||||
err = Errno(win32.GetLastError())
|
err = Errno(win32.GetLastError())
|
||||||
}
|
}
|
||||||
|
|
||||||
buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length])
|
buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length])
|
||||||
src := buf8[:buf8_len]
|
src := buf8[:buf8_len]
|
||||||
|
|
||||||
ctrl_z := false
|
ctrl_z := false
|
||||||
for i := 0; i < len(src) && n+i < len(b); i += 1 {
|
for i := 0; i < len(src) && n+i < len(b); i += 1 {
|
||||||
x := src[i]
|
x := src[i]
|
||||||
@@ -129,9 +133,16 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
|
|||||||
b[n] = x
|
b[n] = x
|
||||||
n += 1
|
n += 1
|
||||||
}
|
}
|
||||||
if ctrl_z || single_read_length < len(buf16) {
|
if ctrl_z || single_read_length < max_read {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): if the last two values were a newline, then it is expected that
|
||||||
|
// this is the end of the input
|
||||||
|
if n >= 2 && single_read_length == max_read && string(b[n-2:n]) == "\r\n" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -399,7 +410,7 @@ is_abs :: proc(path: string) -> bool {
|
|||||||
if len(path) > 0 && path[0] == '/' {
|
if len(path) > 0 && path[0] == '/' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
if len(path) > 2 {
|
if len(path) > 2 {
|
||||||
switch path[0] {
|
switch path[0] {
|
||||||
case 'A'..='Z', 'a'..='z':
|
case 'A'..='Z', 'a'..='z':
|
||||||
|
|||||||
+11
-3
@@ -139,7 +139,7 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode: int = 0
|
mode: int = 0
|
||||||
when OS == "linux" || OS == "darwin" {
|
when OS == .Linux || OS == .Darwin {
|
||||||
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
// NOTE(justasd): 644 (owner read, write; group read; others read)
|
||||||
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||||
}
|
}
|
||||||
@@ -206,11 +206,19 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) {
|
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> (new_memory: []byte, err: mem.Allocator_Error) {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return aligned_alloc(new_size, new_alignment, p)
|
|
||||||
|
new_memory = aligned_alloc(new_size, new_alignment, p) or_return
|
||||||
|
|
||||||
|
// NOTE: heap_resize does not zero the new memory, so we do it
|
||||||
|
if new_size > old_size {
|
||||||
|
new_region := mem.raw_data(new_memory[old_size:])
|
||||||
|
mem.zero(new_region, new_size - old_size)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package os2
|
package os2
|
||||||
|
|
||||||
import sync "core:sync/sync2"
|
import "core:sync"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package os2
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
|
user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
|
||||||
switch ODIN_OS {
|
#partial switch ODIN_OS {
|
||||||
case "windows":
|
case .Windows:
|
||||||
dir = get_env("LocalAppData")
|
dir = get_env("LocalAppData")
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.clone(dir, allocator)
|
dir = strings.clone(dir, allocator)
|
||||||
}
|
}
|
||||||
case "darwin":
|
case .Darwin:
|
||||||
dir = get_env("HOME")
|
dir = get_env("HOME")
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.concatenate({dir, "/Library/Caches"}, allocator)
|
dir = strings.concatenate({dir, "/Library/Caches"}, allocator)
|
||||||
@@ -29,13 +29,13 @@ user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defin
|
|||||||
}
|
}
|
||||||
|
|
||||||
user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
|
user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
|
||||||
switch ODIN_OS {
|
#partial switch ODIN_OS {
|
||||||
case "windows":
|
case .Windows:
|
||||||
dir = get_env("AppData")
|
dir = get_env("AppData")
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.clone(dir, allocator)
|
dir = strings.clone(dir, allocator)
|
||||||
}
|
}
|
||||||
case "darwin":
|
case .Darwin:
|
||||||
dir = get_env("HOME")
|
dir = get_env("HOME")
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
dir = strings.concatenate({dir, "/Library/Application Support"}, allocator)
|
dir = strings.concatenate({dir, "/Library/Application Support"}, allocator)
|
||||||
@@ -56,8 +56,8 @@ user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defi
|
|||||||
|
|
||||||
user_home_dir :: proc() -> (dir: string, is_defined: bool) {
|
user_home_dir :: proc() -> (dir: string, is_defined: bool) {
|
||||||
env := "HOME"
|
env := "HOME"
|
||||||
switch ODIN_OS {
|
#partial switch ODIN_OS {
|
||||||
case "windows":
|
case .Windows:
|
||||||
env = "USERPROFILE"
|
env = "USERPROFILE"
|
||||||
}
|
}
|
||||||
if v := get_env(env); v != "" {
|
if v := get_env(env); v != "" {
|
||||||
|
|||||||
+99
-12
@@ -260,13 +260,13 @@ S_ISUID :: 0o4000 // Set user id on execution
|
|||||||
S_ISGID :: 0o2000 // Set group id on execution
|
S_ISGID :: 0o2000 // Set group id on execution
|
||||||
S_ISVTX :: 0o1000 // Directory restrcted delete
|
S_ISVTX :: 0o1000 // Directory restrcted delete
|
||||||
|
|
||||||
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
|
S_ISLNK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFLNK }
|
||||||
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
|
S_ISREG :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFREG }
|
||||||
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
|
S_ISDIR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFDIR }
|
||||||
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
|
S_ISCHR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFCHR }
|
||||||
S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
|
S_ISBLK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFBLK }
|
||||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
|
S_ISFIFO :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFIFO }
|
||||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
S_ISSOCK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
||||||
|
|
||||||
R_OK :: 4 // Test for read permission
|
R_OK :: 4 // Test for read permission
|
||||||
W_OK :: 2 // Test for write permission
|
W_OK :: 2 // Test for write permission
|
||||||
@@ -290,12 +290,20 @@ foreign libc {
|
|||||||
@(link_name="fstat64") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
|
@(link_name="fstat64") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
|
||||||
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
||||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---
|
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---
|
||||||
@(link_name="fdopendir$INODE64") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
|
||||||
|
@(link_name="fdopendir$INODE64") _unix_fdopendir_amd64 :: proc(fd: Handle) -> Dir ---
|
||||||
|
@(link_name="readdir_r$INODE64") _unix_readdir_r_amd64 :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||||
|
@(link_name="fdopendir") _unix_fdopendir_arm64 :: proc(fd: Handle) -> Dir ---
|
||||||
|
@(link_name="readdir_r") _unix_readdir_r_arm64 :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||||
|
|
||||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
@(link_name="readdir_r$INODE64") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
|
||||||
@(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int ---
|
@(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int ---
|
||||||
|
|
||||||
|
@(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int ---
|
||||||
|
@(link_name="remove") _unix_remove :: proc(path: cstring) -> c.int ---
|
||||||
|
|
||||||
@(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int ---
|
@(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int ---
|
||||||
|
|
||||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---
|
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---
|
||||||
@@ -305,6 +313,7 @@ foreign libc {
|
|||||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||||
|
@(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u16) -> c.int ---
|
||||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||||
|
|
||||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||||
@@ -312,6 +321,14 @@ foreign libc {
|
|||||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when ODIN_ARCH != .arm64 {
|
||||||
|
_unix_fdopendir :: proc {_unix_fdopendir_amd64}
|
||||||
|
_unix_readdir_r :: proc {_unix_readdir_r_amd64}
|
||||||
|
} else {
|
||||||
|
_unix_fdopendir :: proc {_unix_fdopendir_arm64}
|
||||||
|
_unix_readdir_r :: proc {_unix_readdir_r_arm64}
|
||||||
|
}
|
||||||
|
|
||||||
foreign dl {
|
foreign dl {
|
||||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---
|
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---
|
||||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
||||||
@@ -328,14 +345,13 @@ get_last_error_string :: proc() -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||||
delete(cstr)
|
|
||||||
if handle == -1 {
|
if handle == -1 {
|
||||||
return INVALID_HANDLE, 1
|
return INVALID_HANDLE, 1
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == "darwin" && ODIN_ARCH == "arm64" {
|
when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
|
||||||
if mode != 0 {
|
if mode != 0 {
|
||||||
err := fchmod(handle, cast(u16)mode)
|
err := fchmod(handle, cast(u16)mode)
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
@@ -412,6 +428,65 @@ is_path_separator :: proc(r: rune) -> bool {
|
|||||||
return r == '/'
|
return r == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_file_handle :: proc(fd: Handle) -> bool {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISREG(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||||
|
s: OS_Stat
|
||||||
|
err: Errno
|
||||||
|
if follow_links {
|
||||||
|
s, err = _stat(path)
|
||||||
|
} else {
|
||||||
|
s, err = _lstat(path)
|
||||||
|
}
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISREG(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
is_dir_handle :: proc(fd: Handle) -> bool {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISDIR(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||||
|
s: OS_Stat
|
||||||
|
err: Errno
|
||||||
|
if follow_links {
|
||||||
|
s, err = _stat(path)
|
||||||
|
} else {
|
||||||
|
s, err = _lstat(path)
|
||||||
|
}
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISDIR(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file :: proc {is_file_path, is_file_handle}
|
||||||
|
is_dir :: proc {is_dir_path, is_dir_handle}
|
||||||
|
|
||||||
|
|
||||||
|
rename :: proc(old: string, new: string) -> bool {
|
||||||
|
old_cstr := strings.clone_to_cstring(old, context.temp_allocator)
|
||||||
|
new_cstr := strings.clone_to_cstring(new, context.temp_allocator)
|
||||||
|
return _unix_rename(old_cstr, new_cstr) != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
remove :: proc(path: string) -> bool {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
return _unix_remove(path_cstr) != -1
|
||||||
|
}
|
||||||
|
|
||||||
@private
|
@private
|
||||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
@@ -553,6 +628,8 @@ heap_alloc :: proc(size: int) -> rawptr {
|
|||||||
return _unix_calloc(1, size)
|
return _unix_calloc(1, size)
|
||||||
}
|
}
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
|
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||||
|
// POSIX platforms. Ensure your caller takes this into account.
|
||||||
return _unix_realloc(ptr, new_size)
|
return _unix_realloc(ptr, new_size)
|
||||||
}
|
}
|
||||||
heap_free :: proc(ptr: rawptr) {
|
heap_free :: proc(ptr: rawptr) {
|
||||||
@@ -593,7 +670,17 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
|||||||
return ERROR_NONE
|
return ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_mkdir(path_cstr, mode)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
|
runtime._cleanup_runtime_contextless()
|
||||||
_unix_exit(i32(code))
|
_unix_exit(i32(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+532
-299
@@ -7,465 +7,698 @@ import "core:runtime"
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:c"
|
import "core:c"
|
||||||
|
|
||||||
Handle :: distinct i32;
|
Handle :: distinct i32
|
||||||
File_Time :: distinct u64;
|
File_Time :: distinct u64
|
||||||
Errno :: distinct i32;
|
Errno :: distinct i32
|
||||||
Syscall :: distinct i32;
|
|
||||||
|
|
||||||
INVALID_HANDLE :: ~Handle(0);
|
INVALID_HANDLE :: ~Handle(0)
|
||||||
|
|
||||||
ERROR_NONE: Errno : 0;
|
ERROR_NONE: Errno : 0
|
||||||
EPERM: Errno : 1;
|
EPERM: Errno : 1
|
||||||
ENOENT: Errno : 2;
|
ENOENT: Errno : 2
|
||||||
ESRCH: Errno : 3;
|
ESRCH: Errno : 3
|
||||||
EINTR: Errno : 4;
|
EINTR: Errno : 4
|
||||||
EIO: Errno : 5;
|
EIO: Errno : 5
|
||||||
ENXIO: Errno : 6;
|
ENXIO: Errno : 6
|
||||||
E2BIG: Errno : 7;
|
E2BIG: Errno : 7
|
||||||
ENOEXEC: Errno : 8;
|
ENOEXEC: Errno : 8
|
||||||
EBADF: Errno : 9;
|
EBADF: Errno : 9
|
||||||
ECHILD: Errno : 10;
|
ECHILD: Errno : 10
|
||||||
EBEADLK: Errno : 11;
|
EBEADLK: Errno : 11
|
||||||
ENOMEM: Errno : 12;
|
ENOMEM: Errno : 12
|
||||||
EACCESS: Errno : 13;
|
EACCESS: Errno : 13
|
||||||
EFAULT: Errno : 14;
|
EFAULT: Errno : 14
|
||||||
ENOTBLK: Errno : 15;
|
ENOTBLK: Errno : 15
|
||||||
EBUSY: Errno : 16;
|
EBUSY: Errno : 16
|
||||||
EEXIST: Errno : 17;
|
EEXIST: Errno : 17
|
||||||
EXDEV: Errno : 18;
|
EXDEV: Errno : 18
|
||||||
ENODEV: Errno : 19;
|
ENODEV: Errno : 19
|
||||||
ENOTDIR: Errno : 20;
|
ENOTDIR: Errno : 20
|
||||||
EISDIR: Errno : 21;
|
EISDIR: Errno : 21
|
||||||
EINVAL: Errno : 22;
|
EINVAL: Errno : 22
|
||||||
ENFILE: Errno : 23;
|
ENFILE: Errno : 23
|
||||||
EMFILE: Errno : 24;
|
EMFILE: Errno : 24
|
||||||
ENOTTY: Errno : 25;
|
ENOTTY: Errno : 25
|
||||||
ETXTBSY: Errno : 26;
|
ETXTBSY: Errno : 26
|
||||||
EFBIG: Errno : 27;
|
EFBIG: Errno : 27
|
||||||
ENOSPC: Errno : 28;
|
ENOSPC: Errno : 28
|
||||||
ESPIPE: Errno : 29;
|
ESPIPE: Errno : 29
|
||||||
EROFS: Errno : 30;
|
EROFS: Errno : 30
|
||||||
EMLINK: Errno : 31;
|
EMLINK: Errno : 31
|
||||||
EPIPE: Errno : 32;
|
EPIPE: Errno : 32
|
||||||
EDOM: Errno : 33;
|
EDOM: Errno : 33
|
||||||
ERANGE: Errno : 34; /* Result too large */
|
ERANGE: Errno : 34 /* Result too large */
|
||||||
EAGAIN: Errno : 35;
|
EAGAIN: Errno : 35
|
||||||
EINPROGRESS: Errno : 36;
|
EINPROGRESS: Errno : 36
|
||||||
EALREADY: Errno : 37;
|
EALREADY: Errno : 37
|
||||||
ENOTSOCK: Errno : 38;
|
ENOTSOCK: Errno : 38
|
||||||
EDESTADDRREQ: Errno : 39;
|
EDESTADDRREQ: Errno : 39
|
||||||
EMSGSIZE: Errno : 40;
|
EMSGSIZE: Errno : 40
|
||||||
EPROTOTYPE: Errno : 41;
|
EPROTOTYPE: Errno : 41
|
||||||
ENOPROTOOPT: Errno : 42;
|
ENOPROTOOPT: Errno : 42
|
||||||
EPROTONOSUPPORT: Errno : 43;
|
EPROTONOSUPPORT: Errno : 43
|
||||||
ESOCKTNOSUPPORT: Errno : 44;
|
ESOCKTNOSUPPORT: Errno : 44
|
||||||
EOPNOTSUPP: Errno : 45;
|
EOPNOTSUPP: Errno : 45
|
||||||
EPFNOSUPPORT: Errno : 46;
|
EPFNOSUPPORT: Errno : 46
|
||||||
EAFNOSUPPORT: Errno : 47;
|
EAFNOSUPPORT: Errno : 47
|
||||||
EADDRINUSE: Errno : 48;
|
EADDRINUSE: Errno : 48
|
||||||
EADDRNOTAVAIL: Errno : 49;
|
EADDRNOTAVAIL: Errno : 49
|
||||||
ENETDOWN: Errno : 50;
|
ENETDOWN: Errno : 50
|
||||||
ENETUNREACH: Errno : 51;
|
ENETUNREACH: Errno : 51
|
||||||
ENETRESET: Errno : 52;
|
ENETRESET: Errno : 52
|
||||||
ECONNABORTED: Errno : 53;
|
ECONNABORTED: Errno : 53
|
||||||
ECONNRESET: Errno : 54;
|
ECONNRESET: Errno : 54
|
||||||
ENOBUFS: Errno : 55;
|
ENOBUFS: Errno : 55
|
||||||
EISCONN: Errno : 56;
|
EISCONN: Errno : 56
|
||||||
ENOTCONN: Errno : 57;
|
ENOTCONN: Errno : 57
|
||||||
ESHUTDOWN: Errno : 58;
|
ESHUTDOWN: Errno : 58
|
||||||
ETIMEDOUT: Errno : 60;
|
ETIMEDOUT: Errno : 60
|
||||||
ECONNREFUSED: Errno : 61;
|
ECONNREFUSED: Errno : 61
|
||||||
ELOOP: Errno : 62;
|
ELOOP: Errno : 62
|
||||||
ENAMETOOLING: Errno : 63;
|
ENAMETOOLING: Errno : 63
|
||||||
EHOSTDOWN: Errno : 64;
|
EHOSTDOWN: Errno : 64
|
||||||
EHOSTUNREACH: Errno : 65;
|
EHOSTUNREACH: Errno : 65
|
||||||
ENOTEMPTY: Errno : 66;
|
ENOTEMPTY: Errno : 66
|
||||||
EPROCLIM: Errno : 67;
|
EPROCLIM: Errno : 67
|
||||||
EUSERS: Errno : 68;
|
EUSERS: Errno : 68
|
||||||
EDQUOT: Errno : 69;
|
EDQUOT: Errno : 69
|
||||||
ESTALE: Errno : 70;
|
ESTALE: Errno : 70
|
||||||
EBADRPC: Errno : 72;
|
EBADRPC: Errno : 72
|
||||||
ERPCMISMATCH: Errno : 73;
|
ERPCMISMATCH: Errno : 73
|
||||||
EPROGUNAVAIL: Errno : 74;
|
EPROGUNAVAIL: Errno : 74
|
||||||
EPROGMISMATCH: Errno : 75;
|
EPROGMISMATCH: Errno : 75
|
||||||
EPROCUNAVAIL: Errno : 76;
|
EPROCUNAVAIL: Errno : 76
|
||||||
ENOLCK: Errno : 77;
|
ENOLCK: Errno : 77
|
||||||
ENOSYS: Errno : 78;
|
ENOSYS: Errno : 78
|
||||||
EFTYPE: Errno : 79;
|
EFTYPE: Errno : 79
|
||||||
EAUTH: Errno : 80;
|
EAUTH: Errno : 80
|
||||||
ENEEDAUTH: Errno : 81;
|
ENEEDAUTH: Errno : 81
|
||||||
EIDRM: Errno : 82;
|
EIDRM: Errno : 82
|
||||||
ENOMSG: Errno : 83;
|
ENOMSG: Errno : 83
|
||||||
EOVERFLOW: Errno : 84;
|
EOVERFLOW: Errno : 84
|
||||||
ECANCELED: Errno : 85;
|
ECANCELED: Errno : 85
|
||||||
EILSEQ: Errno : 86;
|
EILSEQ: Errno : 86
|
||||||
ENOATTR: Errno : 87;
|
ENOATTR: Errno : 87
|
||||||
EDOOFUS: Errno : 88;
|
EDOOFUS: Errno : 88
|
||||||
EBADMSG: Errno : 89;
|
EBADMSG: Errno : 89
|
||||||
EMULTIHOP: Errno : 90;
|
EMULTIHOP: Errno : 90
|
||||||
ENOLINK: Errno : 91;
|
ENOLINK: Errno : 91
|
||||||
EPROTO: Errno : 92;
|
EPROTO: Errno : 92
|
||||||
ENOTCAPABLE: Errno : 93;
|
ENOTCAPABLE: Errno : 93
|
||||||
ECAPMODE: Errno : 94;
|
ECAPMODE: Errno : 94
|
||||||
ENOTRECOVERABLE: Errno : 95;
|
ENOTRECOVERABLE: Errno : 95
|
||||||
EOWNERDEAD: Errno : 96;
|
EOWNERDEAD: Errno : 96
|
||||||
|
|
||||||
O_RDONLY :: 0x00000;
|
O_RDONLY :: 0x00000
|
||||||
O_WRONLY :: 0x00001;
|
O_WRONLY :: 0x00001
|
||||||
O_RDWR :: 0x00002;
|
O_RDWR :: 0x00002
|
||||||
O_CREATE :: 0x00040;
|
O_CREATE :: 0x00040
|
||||||
O_EXCL :: 0x00080;
|
O_EXCL :: 0x00080
|
||||||
O_NOCTTY :: 0x00100;
|
O_NOCTTY :: 0x00100
|
||||||
O_TRUNC :: 0x00200;
|
O_TRUNC :: 0x00200
|
||||||
O_NONBLOCK :: 0x00800;
|
O_NONBLOCK :: 0x00800
|
||||||
O_APPEND :: 0x00400;
|
O_APPEND :: 0x00400
|
||||||
O_SYNC :: 0x01000;
|
O_SYNC :: 0x01000
|
||||||
O_ASYNC :: 0x02000;
|
O_ASYNC :: 0x02000
|
||||||
O_CLOEXEC :: 0x80000;
|
O_CLOEXEC :: 0x80000
|
||||||
|
|
||||||
|
|
||||||
SEEK_SET :: 0;
|
SEEK_SET :: 0
|
||||||
SEEK_CUR :: 1;
|
SEEK_CUR :: 1
|
||||||
SEEK_END :: 2;
|
SEEK_END :: 2
|
||||||
SEEK_DATA :: 3;
|
SEEK_DATA :: 3
|
||||||
SEEK_HOLE :: 4;
|
SEEK_HOLE :: 4
|
||||||
SEEK_MAX :: SEEK_HOLE;
|
SEEK_MAX :: SEEK_HOLE
|
||||||
|
|
||||||
// NOTE: These are OS specific!
|
// NOTE: These are OS specific!
|
||||||
// Do not mix these up!
|
// Do not mix these up!
|
||||||
RTLD_LAZY :: 0x001;
|
RTLD_LAZY :: 0x001
|
||||||
RTLD_NOW :: 0x002;
|
RTLD_NOW :: 0x002
|
||||||
//RTLD_BINDING_MASK :: 0x3; // Called MODEMASK in dlfcn.h
|
//RTLD_BINDING_MASK :: 0x3 // Called MODEMASK in dlfcn.h
|
||||||
RTLD_GLOBAL :: 0x100;
|
RTLD_GLOBAL :: 0x100
|
||||||
RTLD_LOCAL :: 0x000;
|
RTLD_LOCAL :: 0x000
|
||||||
RTLD_TRACE :: 0x200;
|
RTLD_TRACE :: 0x200
|
||||||
RTLD_NODELETE :: 0x01000;
|
RTLD_NODELETE :: 0x01000
|
||||||
RTLD_NOLOAD :: 0x02000;
|
RTLD_NOLOAD :: 0x02000
|
||||||
|
|
||||||
args := _alloc_command_line_arguments();
|
MAX_PATH :: 1024
|
||||||
|
|
||||||
|
args := _alloc_command_line_arguments()
|
||||||
|
|
||||||
Unix_File_Time :: struct {
|
Unix_File_Time :: struct {
|
||||||
seconds: i64,
|
seconds: time_t,
|
||||||
nanoseconds: c.long,
|
nanoseconds: c.long,
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t :: u32;
|
dev_t :: u64
|
||||||
|
ino_t :: u64
|
||||||
|
nlink_t :: u64
|
||||||
|
off_t :: i64
|
||||||
|
mode_t :: u16
|
||||||
|
pid_t :: u32
|
||||||
|
uid_t :: u32
|
||||||
|
gid_t :: u32
|
||||||
|
blkcnt_t :: i64
|
||||||
|
blksize_t :: i32
|
||||||
|
fflags_t :: u32
|
||||||
|
|
||||||
|
when ODIN_ARCH == .amd64 /* LP64 */ {
|
||||||
|
time_t :: i64
|
||||||
|
} else {
|
||||||
|
time_t :: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
OS_Stat :: struct {
|
OS_Stat :: struct {
|
||||||
device_id: u64,
|
device_id: dev_t,
|
||||||
serial: u64,
|
serial: ino_t,
|
||||||
nlink: u64,
|
nlink: nlink_t,
|
||||||
mode: u32,
|
mode: mode_t,
|
||||||
_padding0: i16,
|
_padding0: i16,
|
||||||
uid: u32,
|
uid: uid_t,
|
||||||
gid: u32,
|
gid: gid_t,
|
||||||
_padding1: i32,
|
_padding1: i32,
|
||||||
rdev: u64,
|
rdev: dev_t,
|
||||||
|
|
||||||
last_access: Unix_File_Time,
|
last_access: Unix_File_Time,
|
||||||
modified: Unix_File_Time,
|
modified: Unix_File_Time,
|
||||||
status_change: Unix_File_Time,
|
status_change: Unix_File_Time,
|
||||||
birthtime: Unix_File_Time,
|
birthtime: Unix_File_Time,
|
||||||
|
|
||||||
size: i64,
|
size: off_t,
|
||||||
blocks: i64,
|
blocks: blkcnt_t,
|
||||||
block_size: i32,
|
block_size: blksize_t,
|
||||||
|
|
||||||
flags: u32,
|
flags: fflags_t,
|
||||||
gen: u64,
|
gen: u64,
|
||||||
lspare: i64,
|
lspare: [10]u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// since FreeBSD v12
|
||||||
|
Dirent :: struct {
|
||||||
|
ino: ino_t,
|
||||||
|
off: off_t,
|
||||||
|
reclen: u16,
|
||||||
|
type: u8,
|
||||||
|
_pad0: u8,
|
||||||
|
namlen: u16,
|
||||||
|
_pad1: u16,
|
||||||
|
name: [256]byte,
|
||||||
|
}
|
||||||
|
|
||||||
|
Dir :: distinct rawptr // DIR*
|
||||||
|
|
||||||
// File type
|
// File type
|
||||||
S_IFMT :: 0o170000; // Type of file mask
|
S_IFMT :: 0o170000 // Type of file mask
|
||||||
S_IFIFO :: 0o010000; // Named pipe (fifo)
|
S_IFIFO :: 0o010000 // Named pipe (fifo)
|
||||||
S_IFCHR :: 0o020000; // Character special
|
S_IFCHR :: 0o020000 // Character special
|
||||||
S_IFDIR :: 0o040000; // Directory
|
S_IFDIR :: 0o040000 // Directory
|
||||||
S_IFBLK :: 0o060000; // Block special
|
S_IFBLK :: 0o060000 // Block special
|
||||||
S_IFREG :: 0o100000; // Regular
|
S_IFREG :: 0o100000 // Regular
|
||||||
S_IFLNK :: 0o120000; // Symbolic link
|
S_IFLNK :: 0o120000 // Symbolic link
|
||||||
S_IFSOCK :: 0o140000; // Socket
|
S_IFSOCK :: 0o140000 // Socket
|
||||||
//S_ISVTX :: 0o001000; // Save swapped text even after use
|
//S_ISVTX :: 0o001000 // Save swapped text even after use
|
||||||
|
|
||||||
// File mode
|
// File mode
|
||||||
// Read, write, execute/search by owner
|
// Read, write, execute/search by owner
|
||||||
S_IRWXU :: 0o0700; // RWX mask for owner
|
S_IRWXU :: 0o0700 // RWX mask for owner
|
||||||
S_IRUSR :: 0o0400; // R for owner
|
S_IRUSR :: 0o0400 // R for owner
|
||||||
S_IWUSR :: 0o0200; // W for owner
|
S_IWUSR :: 0o0200 // W for owner
|
||||||
S_IXUSR :: 0o0100; // X for owner
|
S_IXUSR :: 0o0100 // X for owner
|
||||||
|
|
||||||
// Read, write, execute/search by group
|
// Read, write, execute/search by group
|
||||||
S_IRWXG :: 0o0070; // RWX mask for group
|
S_IRWXG :: 0o0070 // RWX mask for group
|
||||||
S_IRGRP :: 0o0040; // R for group
|
S_IRGRP :: 0o0040 // R for group
|
||||||
S_IWGRP :: 0o0020; // W for group
|
S_IWGRP :: 0o0020 // W for group
|
||||||
S_IXGRP :: 0o0010; // X for group
|
S_IXGRP :: 0o0010 // X for group
|
||||||
|
|
||||||
// Read, write, execute/search by others
|
// Read, write, execute/search by others
|
||||||
S_IRWXO :: 0o0007; // RWX mask for other
|
S_IRWXO :: 0o0007 // RWX mask for other
|
||||||
S_IROTH :: 0o0004; // R for other
|
S_IROTH :: 0o0004 // R for other
|
||||||
S_IWOTH :: 0o0002; // W for other
|
S_IWOTH :: 0o0002 // W for other
|
||||||
S_IXOTH :: 0o0001; // X for other
|
S_IXOTH :: 0o0001 // X for other
|
||||||
|
|
||||||
S_ISUID :: 0o4000; // Set user id on execution
|
S_ISUID :: 0o4000 // Set user id on execution
|
||||||
S_ISGID :: 0o2000; // Set group id on execution
|
S_ISGID :: 0o2000 // Set group id on execution
|
||||||
S_ISVTX :: 0o1000; // Directory restrcted delete
|
S_ISVTX :: 0o1000 // Directory restrcted delete
|
||||||
|
|
||||||
|
|
||||||
S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK;
|
S_ISLNK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFLNK
|
||||||
S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG;
|
S_ISREG :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFREG
|
||||||
S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR;
|
S_ISDIR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFDIR
|
||||||
S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR;
|
S_ISCHR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFCHR
|
||||||
S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK;
|
S_ISBLK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFBLK
|
||||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO;
|
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFIFO
|
||||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK;
|
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFSOCK
|
||||||
|
|
||||||
F_OK :: 0; // Test for file existance
|
F_OK :: 0 // Test for file existance
|
||||||
X_OK :: 1; // Test for execute permission
|
X_OK :: 1 // Test for execute permission
|
||||||
W_OK :: 2; // Test for write permission
|
W_OK :: 2 // Test for write permission
|
||||||
R_OK :: 4; // Test for read permission
|
R_OK :: 4 // Test for read permission
|
||||||
|
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@(link_name="__error") __errno_location :: proc() -> ^int ---;
|
@(link_name="__error") __errno_location :: proc() -> ^int ---
|
||||||
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> int ---;
|
|
||||||
|
|
||||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---;
|
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---;
|
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
|
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---;
|
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---;
|
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
|
||||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---;
|
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
|
||||||
@(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---;
|
@(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
|
||||||
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---;
|
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
|
||||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---;
|
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
||||||
|
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
|
||||||
|
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||||
|
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||||
|
@(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
|
||||||
|
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
|
||||||
|
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
|
||||||
|
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||||
|
|
||||||
|
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||||
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
|
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||||
|
|
||||||
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---;
|
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
|
||||||
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---;
|
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---;
|
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
|
|
||||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---;
|
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---;
|
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||||
|
|
||||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---;
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
foreign dl {
|
foreign dl {
|
||||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---;
|
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
|
||||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
|
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
||||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---;
|
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
|
||||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
|
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||||
|
|
||||||
@(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int ---;
|
@(link_name="pthread_getthreadid_np") pthread_getthreadid_np :: proc() -> c.int ---
|
||||||
}
|
}
|
||||||
|
|
||||||
is_path_separator :: proc(r: rune) -> bool {
|
is_path_separator :: proc(r: rune) -> bool {
|
||||||
return r == '/';
|
return r == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc() -> int {
|
||||||
return __errno_location()^;
|
return __errno_location()^
|
||||||
}
|
}
|
||||||
|
|
||||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path);
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
handle := _unix_open(cstr, c.int(flags), c.int(mode));
|
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||||
delete(cstr);
|
|
||||||
if handle == -1 {
|
if handle == -1 {
|
||||||
return INVALID_HANDLE, Errno(get_last_error());
|
return INVALID_HANDLE, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return handle, ERROR_NONE;
|
return handle, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
close :: proc(fd: Handle) -> Errno {
|
close :: proc(fd: Handle) -> Errno {
|
||||||
result := _unix_close(fd);
|
result := _unix_close(fd)
|
||||||
if result == -1 {
|
if result == -1 {
|
||||||
return Errno(get_last_error());
|
return Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return ERROR_NONE;
|
return ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)));
|
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
|
||||||
if bytes_read == -1 {
|
if bytes_read == -1 {
|
||||||
return -1, Errno(get_last_error());
|
return -1, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return int(bytes_read), ERROR_NONE;
|
return int(bytes_read), ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return 0, ERROR_NONE;
|
return 0, ERROR_NONE
|
||||||
}
|
}
|
||||||
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)));
|
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
|
||||||
if bytes_written == -1 {
|
if bytes_written == -1 {
|
||||||
return -1, Errno(get_last_error());
|
return -1, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return int(bytes_written), ERROR_NONE;
|
return int(bytes_written), ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
res := _unix_seek(fd, offset, c.int(whence));
|
res := _unix_seek(fd, offset, c.int(whence))
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
return -1, Errno(get_last_error());
|
return -1, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return res, ERROR_NONE;
|
return res, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||||
s, err := fstat(fd);
|
s, err := fstat(fd)
|
||||||
if err != ERROR_NONE {
|
if err != ERROR_NONE {
|
||||||
return -1, err;
|
return -1, err
|
||||||
}
|
}
|
||||||
return s.size, ERROR_NONE;
|
return s.size, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
stdin: Handle = 0;
|
rename :: proc(old_path, new_path: string) -> Errno {
|
||||||
stdout: Handle = 1;
|
old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
|
||||||
stderr: Handle = 2;
|
new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||||
|
res := _unix_rename(old_path_cstr, new_path_cstr)
|
||||||
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
if res == -1 {
|
||||||
s, err := fstat(fd);
|
return Errno(get_last_error())
|
||||||
if err != ERROR_NONE {
|
|
||||||
return 0, err;
|
|
||||||
}
|
}
|
||||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds;
|
return ERROR_NONE
|
||||||
return File_Time(modified), ERROR_NONE;
|
}
|
||||||
|
|
||||||
|
remove :: proc(path: string) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_unlink(path_cstr)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_mkdir(path_cstr, mode)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_directory :: proc(path: string) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_rmdir(path_cstr)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file_handle :: proc(fd: Handle) -> bool {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISREG(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||||
|
s: OS_Stat
|
||||||
|
err: Errno
|
||||||
|
if follow_links {
|
||||||
|
s, err = _stat(path)
|
||||||
|
} else {
|
||||||
|
s, err = _lstat(path)
|
||||||
|
}
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISREG(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_dir_handle :: proc(fd: Handle) -> bool {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISDIR(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||||
|
s: OS_Stat
|
||||||
|
err: Errno
|
||||||
|
if follow_links {
|
||||||
|
s, err = _stat(path)
|
||||||
|
} else {
|
||||||
|
s, err = _lstat(path)
|
||||||
|
}
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISDIR(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file :: proc {is_file_path, is_file_handle}
|
||||||
|
is_dir :: proc {is_dir_path, is_dir_handle}
|
||||||
|
|
||||||
|
// NOTE(bill): Uses startup to initialize it
|
||||||
|
|
||||||
|
stdin: Handle = 0
|
||||||
|
stdout: Handle = 1
|
||||||
|
stderr: Handle = 2
|
||||||
|
|
||||||
|
/* TODO(zangent): Implement these!
|
||||||
|
last_write_time :: proc(fd: Handle) -> File_Time {}
|
||||||
|
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||||
|
*/
|
||||||
|
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||||
|
return File_Time(modified), ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||||
s, err := stat(name);
|
s, err := _stat(name)
|
||||||
if err != ERROR_NONE {
|
if err != ERROR_NONE {
|
||||||
return 0, err;
|
return 0, err
|
||||||
}
|
}
|
||||||
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds;
|
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||||
return File_Time(modified), ERROR_NONE;
|
return File_Time(modified), ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
stat :: proc(path: string) -> (OS_Stat, Errno) {
|
@private
|
||||||
cstr := strings.clone_to_cstring(path);
|
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
defer delete(cstr);
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
s: OS_Stat = ---
|
||||||
s: OS_Stat;
|
result := _unix_lstat(cstr, &s)
|
||||||
result := _unix_stat(cstr, &s);
|
|
||||||
if result == -1 {
|
if result == -1 {
|
||||||
return s, Errno(get_last_error());
|
return s, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return s, ERROR_NONE;
|
return s, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
@private
|
||||||
s: OS_Stat;
|
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
result := _unix_fstat(fd, &s);
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
if result == -1 {
|
|
||||||
return s, Errno(get_last_error());
|
// deliberately uninitialized
|
||||||
|
s: OS_Stat = ---
|
||||||
|
res := _unix_lstat(cstr, &s)
|
||||||
|
if res == -1 {
|
||||||
|
return s, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return s, ERROR_NONE;
|
return s, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||||
|
s: OS_Stat = ---
|
||||||
|
result := _unix_fstat(fd, &s)
|
||||||
|
if result == -1 {
|
||||||
|
return s, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return s, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
|
||||||
|
dirp := _unix_fdopendir(fd)
|
||||||
|
if dirp == cast(Dir)nil {
|
||||||
|
return nil, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return dirp, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_closedir :: proc(dirp: Dir) -> Errno {
|
||||||
|
rc := _unix_closedir(dirp)
|
||||||
|
if rc != 0 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_rewinddir :: proc(dirp: Dir) {
|
||||||
|
_unix_rewinddir(dirp)
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
|
||||||
|
result: ^Dirent
|
||||||
|
rc := _unix_readdir_r(dirp, &entry, &result)
|
||||||
|
|
||||||
|
if rc != 0 {
|
||||||
|
err = Errno(get_last_error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ERROR_NONE
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
end_of_stream = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_readlink :: proc(path: string) -> (string, Errno) {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
|
||||||
|
bufsz : uint = MAX_PATH
|
||||||
|
buf := make([]byte, MAX_PATH)
|
||||||
|
for {
|
||||||
|
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
|
||||||
|
if rc == -1 {
|
||||||
|
delete(buf)
|
||||||
|
return "", Errno(get_last_error())
|
||||||
|
} else if rc == int(bufsz) {
|
||||||
|
bufsz += MAX_PATH
|
||||||
|
delete(buf)
|
||||||
|
buf = make([]byte, bufsz)
|
||||||
|
} else {
|
||||||
|
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX FreeBSD
|
||||||
|
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||||
|
return "", Errno(ENOSYS)
|
||||||
|
}
|
||||||
|
|
||||||
|
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||||
|
rel := rel
|
||||||
|
if rel == "" {
|
||||||
|
rel = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||||
|
|
||||||
|
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||||
|
if path_ptr == nil {
|
||||||
|
return "", Errno(get_last_error())
|
||||||
|
}
|
||||||
|
defer _unix_free(path_ptr)
|
||||||
|
|
||||||
|
path_cstr := transmute(cstring)path_ptr
|
||||||
|
path = strings.clone( string(path_cstr) )
|
||||||
|
|
||||||
|
return path, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path);
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer delete(cstr);
|
result := _unix_access(cstr, c.int(mask))
|
||||||
result := _unix_access(cstr, c.int(mask));
|
|
||||||
if result == -1 {
|
if result == -1 {
|
||||||
return false, Errno(get_last_error());
|
return false, Errno(get_last_error())
|
||||||
}
|
}
|
||||||
return true, ERROR_NONE;
|
return true, ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_alloc :: proc(size: int) -> rawptr {
|
heap_alloc :: proc(size: int) -> rawptr {
|
||||||
assert(size >= 0);
|
assert(size >= 0)
|
||||||
return _unix_calloc(1, c.size_t(size));
|
return _unix_calloc(1, c.size_t(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
return _unix_realloc(ptr, c.size_t(new_size));
|
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||||
|
// POSIX platforms. Ensure your caller takes this into account.
|
||||||
|
return _unix_realloc(ptr, c.size_t(new_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_free :: proc(ptr: rawptr) {
|
heap_free :: proc(ptr: rawptr) {
|
||||||
_unix_free(ptr);
|
_unix_free(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
getenv :: proc(name: string) -> (string, bool) {
|
getenv :: proc(name: string) -> (string, bool) {
|
||||||
path_str := strings.clone_to_cstring(name);
|
path_str := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer delete(path_str);
|
cstr := _unix_getenv(path_str)
|
||||||
cstr := _unix_getenv(path_str);
|
|
||||||
if cstr == nil {
|
if cstr == nil {
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
return string(cstr), true;
|
return string(cstr), true
|
||||||
}
|
}
|
||||||
|
|
||||||
get_current_directory :: proc() -> string {
|
get_current_directory :: proc() -> string {
|
||||||
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
|
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
|
||||||
// an authoritative value for it across all systems.
|
// an authoritative value for it across all systems.
|
||||||
// The largest value I could find was 4096, so might as well use the page size.
|
// The largest value I could find was 4096, so might as well use the page size.
|
||||||
page_size := get_page_size();
|
page_size := get_page_size()
|
||||||
buf := make([dynamic]u8, page_size);
|
buf := make([dynamic]u8, page_size)
|
||||||
#no_bounds_check for {
|
#no_bounds_check for {
|
||||||
cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf)));
|
cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf)))
|
||||||
if cwd != nil {
|
if cwd != nil {
|
||||||
return string(cwd);
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
return "";
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size);
|
resize(&buf, len(buf)+page_size)
|
||||||
}
|
}
|
||||||
unreachable();
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
set_current_directory :: proc(path: string) -> (err: Errno) {
|
set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||||
cstr := strings.clone_to_cstring(path, context.temp_allocator);
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
res := _unix_chdir(cstr);
|
res := _unix_chdir(cstr)
|
||||||
if res == -1 do return Errno(get_last_error());
|
if res == -1 do return Errno(get_last_error())
|
||||||
return ERROR_NONE;
|
return ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
_unix_exit(c.int(code));
|
runtime._cleanup_runtime_contextless()
|
||||||
|
_unix_exit(c.int(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread_id :: proc "contextless" () -> int {
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
return cast(int) pthread_getthreadid_np();
|
return cast(int) pthread_getthreadid_np()
|
||||||
}
|
}
|
||||||
|
|
||||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||||
cstr := strings.clone_to_cstring(filename);
|
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||||
defer delete(cstr);
|
handle := _unix_dlopen(cstr, c.int(flags))
|
||||||
handle := _unix_dlopen(cstr, c.int(flags));
|
return handle
|
||||||
return handle;
|
|
||||||
}
|
}
|
||||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||||
assert(handle != nil);
|
assert(handle != nil)
|
||||||
cstr := strings.clone_to_cstring(symbol);
|
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||||
defer delete(cstr);
|
proc_handle := _unix_dlsym(handle, cstr)
|
||||||
proc_handle := _unix_dlsym(handle, cstr);
|
return proc_handle
|
||||||
return proc_handle;
|
|
||||||
}
|
}
|
||||||
dlclose :: proc(handle: rawptr) -> bool {
|
dlclose :: proc(handle: rawptr) -> bool {
|
||||||
assert(handle != nil);
|
assert(handle != nil)
|
||||||
return _unix_dlclose(handle) == 0;
|
return _unix_dlclose(handle) == 0
|
||||||
}
|
}
|
||||||
dlerror :: proc() -> string {
|
dlerror :: proc() -> string {
|
||||||
return string(_unix_dlerror());
|
return string(_unix_dlerror())
|
||||||
}
|
}
|
||||||
|
|
||||||
get_page_size :: proc() -> int {
|
get_page_size :: proc() -> int {
|
||||||
// NOTE(tetra): The page size never changes, so why do anything complicated
|
// NOTE(tetra): The page size never changes, so why do anything complicated
|
||||||
// if we don't have to.
|
// if we don't have to.
|
||||||
@static page_size := -1;
|
@static page_size := -1
|
||||||
if page_size != -1 do return page_size;
|
if page_size != -1 do return page_size
|
||||||
|
|
||||||
page_size = int(_unix_getpagesize());
|
page_size = int(_unix_getpagesize())
|
||||||
return page_size;
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__));
|
res := make([]string, len(runtime.args__))
|
||||||
for arg, i in runtime.args__ {
|
for arg, i in runtime.args__ {
|
||||||
res[i] = string(arg);
|
res[i] = string(arg)
|
||||||
}
|
}
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+80
-49
@@ -11,6 +11,7 @@ import "core:intrinsics"
|
|||||||
import "core:sys/unix"
|
import "core:sys/unix"
|
||||||
|
|
||||||
Handle :: distinct i32
|
Handle :: distinct i32
|
||||||
|
Pid :: distinct i32
|
||||||
File_Time :: distinct u64
|
File_Time :: distinct u64
|
||||||
Errno :: distinct i32
|
Errno :: distinct i32
|
||||||
|
|
||||||
@@ -150,6 +151,8 @@ ERFKILL: Errno : 132 /* Operation not possible due to RF-kill */
|
|||||||
|
|
||||||
EHWPOISON: Errno : 133 /* Memory page has hardware error */
|
EHWPOISON: Errno : 133 /* Memory page has hardware error */
|
||||||
|
|
||||||
|
ADDR_NO_RANDOMIZE :: 0x40000
|
||||||
|
|
||||||
O_RDONLY :: 0x00000
|
O_RDONLY :: 0x00000
|
||||||
O_WRONLY :: 0x00001
|
O_WRONLY :: 0x00001
|
||||||
O_RDWR :: 0x00002
|
O_RDWR :: 0x00002
|
||||||
@@ -266,15 +269,28 @@ X_OK :: 1 // Test for execute permission
|
|||||||
W_OK :: 2 // Test for write permission
|
W_OK :: 2 // Test for write permission
|
||||||
R_OK :: 4 // Test for read permission
|
R_OK :: 4 // Test for read permission
|
||||||
|
|
||||||
AT_FDCWD :: -100
|
AT_FDCWD :: ~uintptr(99) /* -100 */
|
||||||
AT_REMOVEDIR :: uintptr(0x200)
|
AT_REMOVEDIR :: uintptr(0x200)
|
||||||
AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
|
AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
|
||||||
|
|
||||||
|
_unix_personality :: proc(persona: u64) -> int {
|
||||||
|
return int(intrinsics.syscall(unix.SYS_personality, uintptr(persona)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_unix_fork :: proc() -> Pid {
|
||||||
|
when ODIN_ARCH != .arm64 {
|
||||||
|
res := int(intrinsics.syscall(unix.SYS_fork))
|
||||||
|
} else {
|
||||||
|
res := int(intrinsics.syscall(unix.SYS_clone, unix.SIGCHLD))
|
||||||
|
}
|
||||||
|
return -1 if res < 0 else Pid(res)
|
||||||
|
}
|
||||||
|
|
||||||
_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle {
|
_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
||||||
} else { // NOTE: arm64 does not have open
|
} else { // NOTE: arm64 does not have open
|
||||||
res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode))))
|
res := int(intrinsics.syscall(unix.SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
||||||
}
|
}
|
||||||
return -1 if res < 0 else Handle(res)
|
return -1 if res < 0 else Handle(res)
|
||||||
}
|
}
|
||||||
@@ -292,7 +308,7 @@ _unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
||||||
when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
|
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
|
||||||
return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence)))
|
return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence)))
|
||||||
} else {
|
} else {
|
||||||
low := uintptr(offset & 0xFFFFFFFF)
|
low := uintptr(offset & 0xFFFFFFFF)
|
||||||
@@ -304,17 +320,17 @@ _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||||
when ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .amd64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat)))
|
return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat)))
|
||||||
} else when ODIN_ARCH != "arm64" {
|
} else when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat)))
|
return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||||
} else { // NOTE: arm64 does not have stat
|
} else { // NOTE: arm64 does not have stat
|
||||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0))
|
return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int {
|
_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int {
|
||||||
when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
|
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat)))
|
return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat)))
|
||||||
} else {
|
} else {
|
||||||
return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat)))
|
return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat)))
|
||||||
@@ -322,28 +338,28 @@ _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||||
when ODIN_ARCH == "amd64" {
|
when ODIN_ARCH == .amd64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat)))
|
return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat)))
|
||||||
} else when ODIN_ARCH != "arm64" {
|
} else when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat)))
|
return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||||
} else { // NOTE: arm64 does not have any lstat
|
} else { // NOTE: arm64 does not have any lstat
|
||||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
|
return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
|
_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||||
} else { // NOTE: arm64 does not have readlink
|
} else { // NOTE: arm64 does not have readlink
|
||||||
return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
return int(intrinsics.syscall(unix.SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unix_access :: proc(path: cstring, mask: int) -> int {
|
_unix_access :: proc(path: cstring, mask: int) -> int {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask)))
|
return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask)))
|
||||||
} else { // NOTE: arm64 does not have access
|
} else { // NOTE: arm64 does not have access
|
||||||
return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask)))
|
return int(intrinsics.syscall(unix.SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,34 +372,34 @@ _unix_chdir :: proc(path: cstring) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_unix_rename :: proc(old, new: cstring) -> int {
|
_unix_rename :: proc(old, new: cstring) -> int {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||||
} else { // NOTE: arm64 does not have rename
|
} else { // NOTE: arm64 does not have rename
|
||||||
return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new))))
|
return int(intrinsics.syscall(unix.SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unix_unlink :: proc(path: cstring) -> int {
|
_unix_unlink :: proc(path: cstring) -> int {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path))))
|
return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path))))
|
||||||
} else { // NOTE: arm64 does not have unlink
|
} else { // NOTE: arm64 does not have unlink
|
||||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0)))
|
return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unix_rmdir :: proc(path: cstring) -> int {
|
_unix_rmdir :: proc(path: cstring) -> int {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path))))
|
return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path))))
|
||||||
} else { // NOTE: arm64 does not have rmdir
|
} else { // NOTE: arm64 does not have rmdir
|
||||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR))
|
return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_unix_mkdir :: proc(path: cstring, mode: u32) -> int {
|
_unix_mkdir :: proc(path: cstring, mode: u32) -> int {
|
||||||
when ODIN_ARCH != "arm64" {
|
when ODIN_ARCH != .arm64 {
|
||||||
return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
|
return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
|
||||||
} else { // NOTE: arm64 does not have mkdir
|
} else { // NOTE: arm64 does not have mkdir
|
||||||
return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode)))
|
return int(intrinsics.syscall(unix.SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,10 +447,25 @@ get_last_error :: proc() -> int {
|
|||||||
return __errno_location()^
|
return __errno_location()^
|
||||||
}
|
}
|
||||||
|
|
||||||
|
personality :: proc(persona: u64) -> (Errno) {
|
||||||
|
res := _unix_personality(persona)
|
||||||
|
if res == -1 {
|
||||||
|
return _get_errno(res)
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
fork :: proc() -> (Pid, Errno) {
|
||||||
|
pid := _unix_fork()
|
||||||
|
if pid == -1 {
|
||||||
|
return -1, _get_errno(int(pid))
|
||||||
|
}
|
||||||
|
return pid, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
handle := _unix_open(cstr, flags, mode)
|
handle := _unix_open(cstr, flags, mode)
|
||||||
defer delete(cstr)
|
|
||||||
if handle < 0 {
|
if handle < 0 {
|
||||||
return INVALID_HANDLE, _get_errno(int(handle))
|
return INVALID_HANDLE, _get_errno(int(handle))
|
||||||
}
|
}
|
||||||
@@ -473,11 +504,13 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||||
s, err := _fstat(fd)
|
// deliberately uninitialized; the syscall fills this buffer for us
|
||||||
if err != ERROR_NONE {
|
s: OS_Stat = ---
|
||||||
return 0, err
|
result := _unix_fstat(fd, &s)
|
||||||
}
|
if result < 0 {
|
||||||
return max(s.size, 0), ERROR_NONE
|
return 0, _get_errno(result)
|
||||||
|
}
|
||||||
|
return max(s.size, 0), ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
rename :: proc(old_path, new_path: string) -> Errno {
|
rename :: proc(old_path, new_path: string) -> Errno {
|
||||||
@@ -580,10 +613,10 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
|||||||
|
|
||||||
@private
|
@private
|
||||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer delete(cstr)
|
|
||||||
|
|
||||||
s: OS_Stat
|
// deliberately uninitialized; the syscall fills this buffer for us
|
||||||
|
s: OS_Stat = ---
|
||||||
result := _unix_stat(cstr, &s)
|
result := _unix_stat(cstr, &s)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
return s, _get_errno(result)
|
return s, _get_errno(result)
|
||||||
@@ -593,10 +626,10 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
|||||||
|
|
||||||
@private
|
@private
|
||||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer delete(cstr)
|
|
||||||
|
|
||||||
s: OS_Stat
|
// deliberately uninitialized; the syscall fills this buffer for us
|
||||||
|
s: OS_Stat = ---
|
||||||
result := _unix_lstat(cstr, &s)
|
result := _unix_lstat(cstr, &s)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
return s, _get_errno(result)
|
return s, _get_errno(result)
|
||||||
@@ -606,7 +639,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
|||||||
|
|
||||||
@private
|
@private
|
||||||
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||||
s: OS_Stat
|
// deliberately uninitialized; the syscall fills this buffer for us
|
||||||
|
s: OS_Stat = ---
|
||||||
result := _unix_fstat(fd, &s)
|
result := _unix_fstat(fd, &s)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
return s, _get_errno(result)
|
return s, _get_errno(result)
|
||||||
@@ -659,8 +693,7 @@ _readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool)
|
|||||||
|
|
||||||
@private
|
@private
|
||||||
_readlink :: proc(path: string) -> (string, Errno) {
|
_readlink :: proc(path: string) -> (string, Errno) {
|
||||||
path_cstr := strings.clone_to_cstring(path)
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer delete(path_cstr)
|
|
||||||
|
|
||||||
bufsz : uint = 256
|
bufsz : uint = 256
|
||||||
buf := make([]byte, bufsz)
|
buf := make([]byte, bufsz)
|
||||||
@@ -696,8 +729,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
|||||||
rel = "."
|
rel = "."
|
||||||
}
|
}
|
||||||
|
|
||||||
rel_cstr := strings.clone_to_cstring(rel)
|
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||||
defer delete(rel_cstr)
|
|
||||||
|
|
||||||
path_ptr := _unix_realpath(rel_cstr, nil)
|
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||||
if path_ptr == nil {
|
if path_ptr == nil {
|
||||||
@@ -712,8 +744,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||||
cstr := strings.clone_to_cstring(path)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
defer delete(cstr)
|
|
||||||
result := _unix_access(cstr, mask)
|
result := _unix_access(cstr, mask)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
return false, _get_errno(result)
|
return false, _get_errno(result)
|
||||||
@@ -727,6 +758,8 @@ heap_alloc :: proc(size: int) -> rawptr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
|
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||||
|
// POSIX platforms. Ensure your caller takes this into account.
|
||||||
return _unix_realloc(ptr, c.size_t(new_size))
|
return _unix_realloc(ptr, c.size_t(new_size))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,8 +768,7 @@ heap_free :: proc(ptr: rawptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getenv :: proc(name: string) -> (string, bool) {
|
getenv :: proc(name: string) -> (string, bool) {
|
||||||
path_str := strings.clone_to_cstring(name)
|
path_str := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
defer delete(path_str)
|
|
||||||
cstr := _unix_getenv(path_str)
|
cstr := _unix_getenv(path_str)
|
||||||
if cstr == nil {
|
if cstr == nil {
|
||||||
return "", false
|
return "", false
|
||||||
@@ -774,6 +806,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
|
runtime._cleanup_runtime_contextless()
|
||||||
_unix_exit(c.int(code))
|
_unix_exit(c.int(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,15 +815,13 @@ current_thread_id :: proc "contextless" () -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||||
cstr := strings.clone_to_cstring(filename)
|
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||||
defer delete(cstr)
|
|
||||||
handle := _unix_dlopen(cstr, c.int(flags))
|
handle := _unix_dlopen(cstr, c.int(flags))
|
||||||
return handle
|
return handle
|
||||||
}
|
}
|
||||||
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||||
assert(handle != nil)
|
assert(handle != nil)
|
||||||
cstr := strings.clone_to_cstring(symbol)
|
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||||
defer delete(cstr)
|
|
||||||
proc_handle := _unix_dlsym(handle, cstr)
|
proc_handle := _unix_dlsym(handle, cstr)
|
||||||
return proc_handle
|
return proc_handle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,707 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
foreign import libc "system:c"
|
||||||
|
|
||||||
|
import "core:strings"
|
||||||
|
import "core:c"
|
||||||
|
import "core:runtime"
|
||||||
|
|
||||||
|
Handle :: distinct i32
|
||||||
|
Pid :: distinct i32
|
||||||
|
File_Time :: distinct u64
|
||||||
|
Errno :: distinct i32
|
||||||
|
|
||||||
|
INVALID_HANDLE :: ~Handle(0)
|
||||||
|
|
||||||
|
ERROR_NONE: Errno: 0
|
||||||
|
|
||||||
|
EPERM: Errno: 1
|
||||||
|
ENOENT: Errno: 2
|
||||||
|
ESRCH: Errno: 3
|
||||||
|
EINTR: Errno: 4
|
||||||
|
EIO: Errno: 5
|
||||||
|
ENXIO: Errno: 6
|
||||||
|
E2BIG: Errno: 7
|
||||||
|
ENOEXEC: Errno: 8
|
||||||
|
EBADF: Errno: 9
|
||||||
|
ECHILD: Errno: 10
|
||||||
|
EDEADLK: Errno: 11
|
||||||
|
ENOMEM: Errno: 12
|
||||||
|
EACCES: Errno: 13
|
||||||
|
EFAULT: Errno: 14
|
||||||
|
ENOTBLK: Errno: 15
|
||||||
|
EBUSY: Errno: 16
|
||||||
|
EEXIST: Errno: 17
|
||||||
|
EXDEV: Errno: 18
|
||||||
|
ENODEV: Errno: 19
|
||||||
|
ENOTDIR: Errno: 20
|
||||||
|
EISDIR: Errno: 21
|
||||||
|
EINVAL: Errno: 22
|
||||||
|
ENFILE: Errno: 23
|
||||||
|
EMFILE: Errno: 24
|
||||||
|
ENOTTY: Errno: 25
|
||||||
|
ETXTBSY: Errno: 26
|
||||||
|
EFBIG: Errno: 27
|
||||||
|
ENOSPC: Errno: 28
|
||||||
|
ESPIPE: Errno: 29
|
||||||
|
EROFS: Errno: 30
|
||||||
|
EMLINK: Errno: 31
|
||||||
|
EPIPE: Errno: 32
|
||||||
|
EDOM: Errno: 33
|
||||||
|
ERANGE: Errno: 34
|
||||||
|
EAGAIN: Errno: 35
|
||||||
|
EWOULDBLOCK: Errno: EAGAIN
|
||||||
|
EINPROGRESS: Errno: 36
|
||||||
|
EALREADY: Errno: 37
|
||||||
|
ENOTSOCK: Errno: 38
|
||||||
|
EDESTADDRREQ: Errno: 39
|
||||||
|
EMSGSIZE: Errno: 40
|
||||||
|
EPROTOTYPE: Errno: 41
|
||||||
|
ENOPROTOOPT: Errno: 42
|
||||||
|
EPROTONOSUPPORT: Errno: 43
|
||||||
|
ESOCKTNOSUPPORT: Errno: 44
|
||||||
|
EOPNOTSUPP: Errno: 45
|
||||||
|
EPFNOSUPPORT: Errno: 46
|
||||||
|
EAFNOSUPPORT: Errno: 47
|
||||||
|
EADDRINUSE: Errno: 48
|
||||||
|
EADDRNOTAVAIL: Errno: 49
|
||||||
|
ENETDOWN: Errno: 50
|
||||||
|
ENETUNREACH: Errno: 51
|
||||||
|
ENETRESET: Errno: 52
|
||||||
|
ECONNABORTED: Errno: 53
|
||||||
|
ECONNRESET: Errno: 54
|
||||||
|
ENOBUFS: Errno: 55
|
||||||
|
EISCONN: Errno: 56
|
||||||
|
ENOTCONN: Errno: 57
|
||||||
|
ESHUTDOWN: Errno: 58
|
||||||
|
ETOOMANYREFS: Errno: 59
|
||||||
|
ETIMEDOUT: Errno: 60
|
||||||
|
ECONNREFUSED: Errno: 61
|
||||||
|
ELOOP: Errno: 62
|
||||||
|
ENAMETOOLONG: Errno: 63
|
||||||
|
EHOSTDOWN: Errno: 64
|
||||||
|
EHOSTUNREACH: Errno: 65
|
||||||
|
ENOTEMPTY: Errno: 66
|
||||||
|
EPROCLIM: Errno: 67
|
||||||
|
EUSERS: Errno: 68
|
||||||
|
EDQUOT: Errno: 69
|
||||||
|
ESTALE: Errno: 70
|
||||||
|
EREMOTE: Errno: 71
|
||||||
|
EBADRPC: Errno: 72
|
||||||
|
ERPCMISMATCH: Errno: 73
|
||||||
|
EPROGUNAVAIL: Errno: 74
|
||||||
|
EPROGMISMATCH: Errno: 75
|
||||||
|
EPROCUNAVAIL: Errno: 76
|
||||||
|
ENOLCK: Errno: 77
|
||||||
|
ENOSYS: Errno: 78
|
||||||
|
EFTYPE: Errno: 79
|
||||||
|
EAUTH: Errno: 80
|
||||||
|
ENEEDAUTH: Errno: 81
|
||||||
|
EIPSEC: Errno: 82
|
||||||
|
ENOATTR: Errno: 83
|
||||||
|
EILSEQ: Errno: 84
|
||||||
|
ENOMEDIUM: Errno: 85
|
||||||
|
EMEDIUMTYPE: Errno: 86
|
||||||
|
EOVERFLOW: Errno: 87
|
||||||
|
ECANCELED: Errno: 88
|
||||||
|
EIDRM: Errno: 89
|
||||||
|
ENOMSG: Errno: 90
|
||||||
|
ENOTSUP: Errno: 91
|
||||||
|
EBADMSG: Errno: 92
|
||||||
|
ENOTRECOVERABLE: Errno: 93
|
||||||
|
EOWNERDEAD: Errno: 94
|
||||||
|
EPROTO: Errno: 95
|
||||||
|
|
||||||
|
O_RDONLY :: 0x00000
|
||||||
|
O_WRONLY :: 0x00001
|
||||||
|
O_RDWR :: 0x00002
|
||||||
|
O_NONBLOCK :: 0x00004
|
||||||
|
O_APPEND :: 0x00008
|
||||||
|
O_ASYNC :: 0x00040
|
||||||
|
O_SYNC :: 0x00080
|
||||||
|
O_CREATE :: 0x00200
|
||||||
|
O_TRUNC :: 0x00400
|
||||||
|
O_EXCL :: 0x00800
|
||||||
|
O_NOCTTY :: 0x08000
|
||||||
|
O_CLOEXEC :: 0x10000
|
||||||
|
|
||||||
|
SEEK_SET :: 0
|
||||||
|
SEEK_CUR :: 1
|
||||||
|
SEEK_END :: 2
|
||||||
|
|
||||||
|
RTLD_LAZY :: 0x001
|
||||||
|
RTLD_NOW :: 0x002
|
||||||
|
RTLD_LOCAL :: 0x000
|
||||||
|
RTLD_GLOBAL :: 0x100
|
||||||
|
RTLD_TRACE :: 0x200
|
||||||
|
RTLD_NODELETE :: 0x400
|
||||||
|
|
||||||
|
MAX_PATH :: 1024
|
||||||
|
|
||||||
|
// "Argv" arguments converted to Odin strings
|
||||||
|
args := _alloc_command_line_arguments()
|
||||||
|
|
||||||
|
pid_t :: i32
|
||||||
|
time_t :: i64
|
||||||
|
mode_t :: u32
|
||||||
|
dev_t :: i32
|
||||||
|
ino_t :: u64
|
||||||
|
nlink_t :: u32
|
||||||
|
uid_t :: u32
|
||||||
|
gid_t :: u32
|
||||||
|
off_t :: i64
|
||||||
|
blkcnt_t :: u64
|
||||||
|
blksize_t :: i32
|
||||||
|
|
||||||
|
Unix_File_Time :: struct {
|
||||||
|
seconds: time_t,
|
||||||
|
nanoseconds: c.long,
|
||||||
|
}
|
||||||
|
|
||||||
|
OS_Stat :: struct {
|
||||||
|
mode: mode_t, // inode protection mode
|
||||||
|
device_id: dev_t, // inode's device
|
||||||
|
serial: ino_t, // inode's number
|
||||||
|
nlink: nlink_t, // number of hard links
|
||||||
|
uid: uid_t, // user ID of the file's owner
|
||||||
|
gid: gid_t, // group ID of the file's group
|
||||||
|
rdev: dev_t, // device type
|
||||||
|
|
||||||
|
last_access: Unix_File_Time, // time of last access
|
||||||
|
modified: Unix_File_Time, // time of last data modification
|
||||||
|
status_change: Unix_File_Time, // time of last file status change
|
||||||
|
|
||||||
|
size: off_t, // file size, in bytes
|
||||||
|
blocks: blkcnt_t, // blocks allocated for file
|
||||||
|
block_size: blksize_t, // optimal blocksize for I/O
|
||||||
|
|
||||||
|
flags: u32, // user defined flags for file
|
||||||
|
gen: u32, // file generation number
|
||||||
|
birthtime: Unix_File_Time, // time of file creation
|
||||||
|
}
|
||||||
|
|
||||||
|
MAXNAMLEN :: 255
|
||||||
|
|
||||||
|
// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
|
||||||
|
Dirent :: struct {
|
||||||
|
ino: ino_t, // file number of entry
|
||||||
|
off: off_t, // offset after this entry
|
||||||
|
reclen: u16, // length of this record
|
||||||
|
type: u8, // file type
|
||||||
|
namlen: u8, // length of string in name
|
||||||
|
_padding: [4]u8,
|
||||||
|
name: [MAXNAMLEN + 1]byte, // name
|
||||||
|
}
|
||||||
|
|
||||||
|
Dir :: distinct rawptr // DIR*
|
||||||
|
|
||||||
|
// File type
|
||||||
|
S_IFMT :: 0o170000 // Type of file mask
|
||||||
|
S_IFIFO :: 0o010000 // Named pipe (fifo)
|
||||||
|
S_IFCHR :: 0o020000 // Character special
|
||||||
|
S_IFDIR :: 0o040000 // Directory
|
||||||
|
S_IFBLK :: 0o060000 // Block special
|
||||||
|
S_IFREG :: 0o100000 // Regular
|
||||||
|
S_IFLNK :: 0o120000 // Symbolic link
|
||||||
|
S_IFSOCK :: 0o140000 // Socket
|
||||||
|
S_ISVTX :: 0o001000 // Save swapped text even after use
|
||||||
|
|
||||||
|
// File mode
|
||||||
|
// Read, write, execute/search by owner
|
||||||
|
S_IRWXU :: 0o0700 // RWX mask for owner
|
||||||
|
S_IRUSR :: 0o0400 // R for owner
|
||||||
|
S_IWUSR :: 0o0200 // W for owner
|
||||||
|
S_IXUSR :: 0o0100 // X for owner
|
||||||
|
|
||||||
|
// Read, write, execute/search by group
|
||||||
|
S_IRWXG :: 0o0070 // RWX mask for group
|
||||||
|
S_IRGRP :: 0o0040 // R for group
|
||||||
|
S_IWGRP :: 0o0020 // W for group
|
||||||
|
S_IXGRP :: 0o0010 // X for group
|
||||||
|
|
||||||
|
// Read, write, execute/search by others
|
||||||
|
S_IRWXO :: 0o0007 // RWX mask for other
|
||||||
|
S_IROTH :: 0o0004 // R for other
|
||||||
|
S_IWOTH :: 0o0002 // W for other
|
||||||
|
S_IXOTH :: 0o0001 // X for other
|
||||||
|
|
||||||
|
S_ISUID :: 0o4000 // Set user id on execution
|
||||||
|
S_ISGID :: 0o2000 // Set group id on execution
|
||||||
|
S_ISTXT :: 0o1000 // Sticky bit
|
||||||
|
|
||||||
|
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
|
||||||
|
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
|
||||||
|
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
|
||||||
|
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
|
||||||
|
S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
|
||||||
|
S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
|
||||||
|
S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
||||||
|
|
||||||
|
F_OK :: 0x00 // Test for file existance
|
||||||
|
X_OK :: 0x01 // Test for execute permission
|
||||||
|
W_OK :: 0x02 // Test for write permission
|
||||||
|
R_OK :: 0x04 // Test for read permission
|
||||||
|
|
||||||
|
AT_FDCWD :: -100
|
||||||
|
AT_EACCESS :: 0x01
|
||||||
|
AT_SYMLINK_NOFOLLOW :: 0x02
|
||||||
|
AT_SYMLINK_FOLLOW :: 0x04
|
||||||
|
AT_REMOVEDIR :: 0x08
|
||||||
|
|
||||||
|
@(default_calling_convention="c")
|
||||||
|
foreign libc {
|
||||||
|
@(link_name="__errno") __errno :: proc() -> ^int ---
|
||||||
|
|
||||||
|
@(link_name="fork") _unix_fork :: proc() -> pid_t ---
|
||||||
|
@(link_name="getthrid") _unix_getthrid :: proc() -> int ---
|
||||||
|
|
||||||
|
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||||
|
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||||
|
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||||
|
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||||
|
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
|
||||||
|
@(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
|
||||||
|
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
|
||||||
|
@(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
|
||||||
|
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
||||||
|
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
|
||||||
|
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||||
|
@(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
|
||||||
|
@(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
|
||||||
|
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
|
||||||
|
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
|
||||||
|
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||||
|
|
||||||
|
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||||
|
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||||
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
|
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||||
|
|
||||||
|
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
|
||||||
|
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||||
|
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||||
|
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||||
|
|
||||||
|
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||||
|
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||||
|
|
||||||
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
|
|
||||||
|
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
|
||||||
|
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
||||||
|
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
|
||||||
|
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||||
|
}
|
||||||
|
|
||||||
|
is_path_separator :: proc(r: rune) -> bool {
|
||||||
|
return r == '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
get_last_error :: proc() -> int {
|
||||||
|
return __errno()^
|
||||||
|
}
|
||||||
|
|
||||||
|
fork :: proc() -> (Pid, Errno) {
|
||||||
|
pid := _unix_fork()
|
||||||
|
if pid == -1 {
|
||||||
|
return Pid(-1), Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return Pid(pid), ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||||
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||||
|
if handle == -1 {
|
||||||
|
return INVALID_HANDLE, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return handle, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
close :: proc(fd: Handle) -> Errno {
|
||||||
|
result := _unix_close(fd)
|
||||||
|
if result == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
|
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
|
||||||
|
if bytes_read == -1 {
|
||||||
|
return -1, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return int(bytes_read), ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return 0, ERROR_NONE
|
||||||
|
}
|
||||||
|
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
|
||||||
|
if bytes_written == -1 {
|
||||||
|
return -1, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return int(bytes_written), ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
|
res := _unix_seek(fd, offset, c.int(whence))
|
||||||
|
if res == -1 {
|
||||||
|
return -1, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return res, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
return s.size, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
rename :: proc(old_path, new_path: string) -> Errno {
|
||||||
|
old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
|
||||||
|
new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||||
|
res := _unix_rename(old_path_cstr, new_path_cstr)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
remove :: proc(path: string) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_unlink(path_cstr)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_mkdir(path_cstr, mode)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_directory :: proc(path: string) -> Errno {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_rmdir(path_cstr)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file_handle :: proc(fd: Handle) -> bool {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISREG(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||||
|
s: OS_Stat
|
||||||
|
err: Errno
|
||||||
|
if follow_links {
|
||||||
|
s, err = _stat(path)
|
||||||
|
} else {
|
||||||
|
s, err = _lstat(path)
|
||||||
|
}
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISREG(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_dir_handle :: proc(fd: Handle) -> bool {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISDIR(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||||
|
s: OS_Stat
|
||||||
|
err: Errno
|
||||||
|
if follow_links {
|
||||||
|
s, err = _stat(path)
|
||||||
|
} else {
|
||||||
|
s, err = _lstat(path)
|
||||||
|
}
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return S_ISDIR(s.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_file :: proc {is_file_path, is_file_handle}
|
||||||
|
is_dir :: proc {is_dir_path, is_dir_handle}
|
||||||
|
|
||||||
|
// NOTE(bill): Uses startup to initialize it
|
||||||
|
|
||||||
|
stdin: Handle = 0
|
||||||
|
stdout: Handle = 1
|
||||||
|
stderr: Handle = 2
|
||||||
|
|
||||||
|
/* TODO(zangent): Implement these!
|
||||||
|
last_write_time :: proc(fd: Handle) -> File_Time {}
|
||||||
|
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||||
|
*/
|
||||||
|
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||||
|
s, err := _fstat(fd)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||||
|
return File_Time(modified), ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||||
|
s, err := _stat(name)
|
||||||
|
if err != ERROR_NONE {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
|
||||||
|
return File_Time(modified), ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
|
||||||
|
// deliberately uninitialized
|
||||||
|
s: OS_Stat = ---
|
||||||
|
res := _unix_stat(cstr, &s)
|
||||||
|
if res == -1 {
|
||||||
|
return s, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return s, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||||
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
|
||||||
|
// deliberately uninitialized
|
||||||
|
s: OS_Stat = ---
|
||||||
|
res := _unix_lstat(cstr, &s)
|
||||||
|
if res == -1 {
|
||||||
|
return s, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return s, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||||
|
// deliberately uninitialized
|
||||||
|
s: OS_Stat = ---
|
||||||
|
res := _unix_fstat(fd, &s)
|
||||||
|
if res == -1 {
|
||||||
|
return s, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return s, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
|
||||||
|
dirp := _unix_fdopendir(fd)
|
||||||
|
if dirp == cast(Dir)nil {
|
||||||
|
return nil, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return dirp, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_closedir :: proc(dirp: Dir) -> Errno {
|
||||||
|
rc := _unix_closedir(dirp)
|
||||||
|
if rc != 0 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_rewinddir :: proc(dirp: Dir) {
|
||||||
|
_unix_rewinddir(dirp)
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
|
||||||
|
result: ^Dirent
|
||||||
|
rc := _unix_readdir_r(dirp, &entry, &result)
|
||||||
|
|
||||||
|
if rc != 0 {
|
||||||
|
err = Errno(get_last_error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ERROR_NONE
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
end_of_stream = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@private
|
||||||
|
_readlink :: proc(path: string) -> (string, Errno) {
|
||||||
|
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
|
||||||
|
bufsz : uint = MAX_PATH
|
||||||
|
buf := make([]byte, MAX_PATH)
|
||||||
|
for {
|
||||||
|
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
|
||||||
|
if rc == -1 {
|
||||||
|
delete(buf)
|
||||||
|
return "", Errno(get_last_error())
|
||||||
|
} else if rc == int(bufsz) {
|
||||||
|
bufsz += MAX_PATH
|
||||||
|
delete(buf)
|
||||||
|
buf = make([]byte, bufsz)
|
||||||
|
} else {
|
||||||
|
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX OpenBSD
|
||||||
|
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||||
|
return "", Errno(ENOSYS)
|
||||||
|
}
|
||||||
|
|
||||||
|
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||||
|
rel := rel
|
||||||
|
if rel == "" {
|
||||||
|
rel = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||||
|
|
||||||
|
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||||
|
if path_ptr == nil {
|
||||||
|
return "", Errno(get_last_error())
|
||||||
|
}
|
||||||
|
defer _unix_free(path_ptr)
|
||||||
|
|
||||||
|
path_cstr := transmute(cstring)path_ptr
|
||||||
|
path = strings.clone( string(path_cstr) )
|
||||||
|
|
||||||
|
return path, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||||
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_access(cstr, c.int(mask))
|
||||||
|
if res == -1 {
|
||||||
|
return false, Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return true, ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_alloc :: proc(size: int) -> rawptr {
|
||||||
|
assert(size >= 0)
|
||||||
|
return _unix_calloc(1, c.size_t(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
|
||||||
|
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
|
||||||
|
// POSIX platforms. Ensure your caller takes this into account.
|
||||||
|
return _unix_realloc(ptr, c.size_t(new_size))
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_free :: proc(ptr: rawptr) {
|
||||||
|
_unix_free(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
getenv :: proc(name: string) -> (string, bool) {
|
||||||
|
path_str := strings.clone_to_cstring(name, context.temp_allocator)
|
||||||
|
cstr := _unix_getenv(path_str)
|
||||||
|
if cstr == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return string(cstr), true
|
||||||
|
}
|
||||||
|
|
||||||
|
get_current_directory :: proc() -> string {
|
||||||
|
buf := make([dynamic]u8, MAX_PATH)
|
||||||
|
for {
|
||||||
|
cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf)))
|
||||||
|
if cwd != nil {
|
||||||
|
return string(cwd)
|
||||||
|
}
|
||||||
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
resize(&buf, len(buf) + MAX_PATH)
|
||||||
|
}
|
||||||
|
unreachable()
|
||||||
|
}
|
||||||
|
|
||||||
|
set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||||
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
|
res := _unix_chdir(cstr)
|
||||||
|
if res == -1 {
|
||||||
|
return Errno(get_last_error())
|
||||||
|
}
|
||||||
|
return ERROR_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
|
runtime._cleanup_runtime_contextless()
|
||||||
|
_unix_exit(c.int(code))
|
||||||
|
}
|
||||||
|
|
||||||
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
|
return _unix_getthrid()
|
||||||
|
}
|
||||||
|
|
||||||
|
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||||
|
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||||
|
handle := _unix_dlopen(cstr, c.int(flags))
|
||||||
|
return handle
|
||||||
|
}
|
||||||
|
dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
|
||||||
|
assert(handle != nil)
|
||||||
|
cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
|
||||||
|
proc_handle := _unix_dlsym(handle, cstr)
|
||||||
|
return proc_handle
|
||||||
|
}
|
||||||
|
dlclose :: proc(handle: rawptr) -> bool {
|
||||||
|
assert(handle != nil)
|
||||||
|
return _unix_dlclose(handle) == 0
|
||||||
|
}
|
||||||
|
dlerror :: proc() -> string {
|
||||||
|
return string(_unix_dlerror())
|
||||||
|
}
|
||||||
|
|
||||||
|
get_page_size :: proc() -> int {
|
||||||
|
// NOTE(tetra): The page size never changes, so why do anything complicated
|
||||||
|
// if we don't have to.
|
||||||
|
@static page_size := -1
|
||||||
|
if page_size != -1 {
|
||||||
|
return page_size
|
||||||
|
}
|
||||||
|
|
||||||
|
page_size = int(_unix_getpagesize())
|
||||||
|
return page_size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
|
res := make([]string, len(runtime.args__))
|
||||||
|
for arg, i in runtime.args__ {
|
||||||
|
res[i] = string(arg)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package os
|
package os
|
||||||
|
|
||||||
import "core:sys/wasm/wasi"
|
import "core:sys/wasm/wasi"
|
||||||
|
import "core:runtime"
|
||||||
|
|
||||||
Handle :: distinct i32
|
Handle :: distinct i32
|
||||||
Errno :: distinct i32
|
Errno :: distinct i32
|
||||||
@@ -93,5 +94,6 @@ heap_free :: proc(ptr: rawptr) {
|
|||||||
|
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
|
runtime._cleanup_runtime_contextless()
|
||||||
wasi.proc_exit(wasi.exitcode_t(code))
|
wasi.proc_exit(wasi.exitcode_t(code))
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
package os
|
package os
|
||||||
|
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
|
import "core:runtime"
|
||||||
|
|
||||||
Handle :: distinct uintptr
|
Handle :: distinct uintptr
|
||||||
File_Time :: distinct u64
|
File_Time :: distinct u64
|
||||||
@@ -128,6 +129,7 @@ get_page_size :: proc() -> int {
|
|||||||
|
|
||||||
|
|
||||||
exit :: proc "contextless" (code: int) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
|
runtime._cleanup_runtime_contextless()
|
||||||
win32.ExitProcess(win32.DWORD(code))
|
win32.ExitProcess(win32.DWORD(code))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package os
|
|||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
|
|
||||||
File_Info :: struct {
|
File_Info :: struct {
|
||||||
fullpath: string,
|
fullpath: string,
|
||||||
name: string,
|
name: string,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//+build linux, darwin, freebsd
|
//+build linux, darwin, freebsd, openbsd
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
@@ -61,7 +61,7 @@ _make_time_from_unix_file_time :: proc(uft: Unix_File_Time) -> time.Time {
|
|||||||
_fill_file_info_from_stat :: proc(fi: ^File_Info, s: OS_Stat) {
|
_fill_file_info_from_stat :: proc(fi: ^File_Info, s: OS_Stat) {
|
||||||
fi.size = s.size
|
fi.size = s.size
|
||||||
fi.mode = cast(File_Mode)s.mode
|
fi.mode = cast(File_Mode)s.mode
|
||||||
fi.is_dir = S_ISDIR(u32(s.mode))
|
fi.is_dir = S_ISDIR(s.mode)
|
||||||
|
|
||||||
// NOTE(laleksic, 2021-01-21): Not really creation time, but closest we can get (maybe better to leave it 0?)
|
// NOTE(laleksic, 2021-01-21): Not really creation time, but closest we can get (maybe better to leave it 0?)
|
||||||
fi.creation_time = _make_time_from_unix_file_time(s.status_change)
|
fi.creation_time = _make_time_from_unix_file_time(s.status_change)
|
||||||
|
|||||||
+16
-39
@@ -80,7 +80,7 @@ stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno)
|
|||||||
return _stat(name, attrs, allocator)
|
return _stat(name, attrs, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Errno) {
|
fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, errno: Errno) {
|
||||||
if fd == 0 {
|
if fd == 0 {
|
||||||
return {}, ERROR_INVALID_HANDLE
|
return {}, ERROR_INVALID_HANDLE
|
||||||
}
|
}
|
||||||
@@ -94,14 +94,14 @@ fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Errno)
|
|||||||
h := win32.HANDLE(fd)
|
h := win32.HANDLE(fd)
|
||||||
switch win32.GetFileType(h) {
|
switch win32.GetFileType(h) {
|
||||||
case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
|
case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
|
||||||
fi: File_Info
|
|
||||||
fi.fullpath = path
|
|
||||||
fi.name = basename(path)
|
fi.name = basename(path)
|
||||||
fi.mode |= file_type_mode(h)
|
fi.mode |= file_type_mode(h)
|
||||||
return fi, ERROR_NONE
|
errno = ERROR_NONE
|
||||||
|
case:
|
||||||
|
fi, errno = file_info_from_get_file_information_by_handle(path, h)
|
||||||
}
|
}
|
||||||
|
fi.fullpath = path
|
||||||
return file_info_from_get_file_information_by_handle(path, h)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -132,26 +132,11 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
|
|||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||||
if fd == 0 {
|
buf, err := cleanpath_from_handle_u16(fd)
|
||||||
return "", ERROR_INVALID_HANDLE
|
if err != 0 {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
h := win32.HANDLE(fd)
|
return win32.utf16_to_utf8(buf, context.allocator), err
|
||||||
|
|
||||||
MAX_PATH := win32.DWORD(260) + 1
|
|
||||||
buf: []u16
|
|
||||||
for {
|
|
||||||
buf = make([]u16, MAX_PATH, context.temp_allocator)
|
|
||||||
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
|
|
||||||
switch Errno(err) {
|
|
||||||
case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER:
|
|
||||||
return "", Errno(err)
|
|
||||||
case ERROR_NOT_ENOUGH_MEMORY:
|
|
||||||
MAX_PATH = MAX_PATH*2 + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return cleanpath_from_buf(buf), ERROR_NONE
|
|
||||||
}
|
}
|
||||||
@(private)
|
@(private)
|
||||||
cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
|
cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
|
||||||
@@ -160,21 +145,13 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) {
|
|||||||
}
|
}
|
||||||
h := win32.HANDLE(fd)
|
h := win32.HANDLE(fd)
|
||||||
|
|
||||||
MAX_PATH := win32.DWORD(260) + 1
|
n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
|
||||||
buf: []u16
|
if n == 0 {
|
||||||
for {
|
return nil, Errno(win32.GetLastError())
|
||||||
buf = make([]u16, MAX_PATH, context.temp_allocator)
|
|
||||||
err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
|
|
||||||
switch Errno(err) {
|
|
||||||
case ERROR_PATH_NOT_FOUND, ERROR_INVALID_PARAMETER:
|
|
||||||
return nil, Errno(err)
|
|
||||||
case ERROR_NOT_ENOUGH_MEMORY:
|
|
||||||
MAX_PATH = MAX_PATH*2 + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
return cleanpath_strip_prefix(buf), ERROR_NONE
|
buf := make([]u16, max(n, win32.DWORD(260))+1, context.temp_allocator)
|
||||||
|
buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
|
||||||
|
return buf[:buf_len], ERROR_NONE
|
||||||
}
|
}
|
||||||
@(private)
|
@(private)
|
||||||
cleanpath_from_buf :: proc(buf: []u16) -> string {
|
cleanpath_from_buf :: proc(buf: []u16) -> string {
|
||||||
|
|||||||
+3
-3
@@ -19,7 +19,7 @@ _file_stream_vtable := &io.Stream_VTable{
|
|||||||
return
|
return
|
||||||
},
|
},
|
||||||
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||||
when ODIN_OS == "windows" || ODIN_OS == "wasi" {
|
when ODIN_OS == .Windows || ODIN_OS == .WASI {
|
||||||
fd := Handle(uintptr(s.stream_data))
|
fd := Handle(uintptr(s.stream_data))
|
||||||
os_err: Errno
|
os_err: Errno
|
||||||
n, os_err = read_at(fd, p, offset)
|
n, os_err = read_at(fd, p, offset)
|
||||||
@@ -33,7 +33,7 @@ _file_stream_vtable := &io.Stream_VTable{
|
|||||||
return
|
return
|
||||||
},
|
},
|
||||||
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) {
|
||||||
when ODIN_OS == "windows" || ODIN_OS == "wasi" {
|
when ODIN_OS == .Windows || ODIN_OS == .WASI {
|
||||||
fd := Handle(uintptr(s.stream_data))
|
fd := Handle(uintptr(s.stream_data))
|
||||||
os_err: Errno
|
os_err: Errno
|
||||||
n, os_err = write_at(fd, p, offset)
|
n, os_err = write_at(fd, p, offset)
|
||||||
@@ -53,7 +53,7 @@ _file_stream_vtable := &io.Stream_VTable{
|
|||||||
return sz
|
return sz
|
||||||
},
|
},
|
||||||
impl_flush = proc(s: io.Stream) -> io.Error {
|
impl_flush = proc(s: io.Stream) -> io.Error {
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
fd := Handle(uintptr(s.stream_data))
|
fd := Handle(uintptr(s.stream_data))
|
||||||
flush(fd)
|
flush(fd)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
|
|||||||
scan_loop: for i = 0; i < len(pattern); i += 1 {
|
scan_loop: for i = 0; i < len(pattern); i += 1 {
|
||||||
switch pattern[i] {
|
switch pattern[i] {
|
||||||
case '\\':
|
case '\\':
|
||||||
when ODIN_OS != "windows" {
|
when ODIN_OS != .Windows {
|
||||||
if i+1 < len(pattern) {
|
if i+1 < len(pattern) {
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ match_chunk :: proc(chunk, s: string) -> (rest: string, ok: bool, err: Match_Err
|
|||||||
chunk = chunk[1:]
|
chunk = chunk[1:]
|
||||||
|
|
||||||
case '\\':
|
case '\\':
|
||||||
when ODIN_OS != "windows" {
|
when ODIN_OS != .Windows {
|
||||||
chunk = chunk[1:]
|
chunk = chunk[1:]
|
||||||
if len(chunk) == 0 {
|
if len(chunk) == 0 {
|
||||||
err = .Syntax_Error
|
err = .Syntax_Error
|
||||||
@@ -188,7 +188,7 @@ get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
chunk := chunk
|
chunk := chunk
|
||||||
if chunk[0] == '\\' && ODIN_OS != "windows" {
|
if chunk[0] == '\\' && ODIN_OS != .Windows {
|
||||||
chunk = chunk[1:]
|
chunk = chunk[1:]
|
||||||
if len(chunk) == 0 {
|
if len(chunk) == 0 {
|
||||||
err = .Syntax_Error
|
err = .Syntax_Error
|
||||||
@@ -220,19 +220,21 @@ get_escape :: proc(chunk: string) -> (r: rune, next_chunk: string, err: Match_Er
|
|||||||
//
|
//
|
||||||
|
|
||||||
glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []string, err: Match_Error) {
|
glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []string, err: Match_Error) {
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
if !has_meta(pattern) {
|
if !has_meta(pattern) {
|
||||||
// TODO(bill): os.lstat on here to check for error
|
// TODO(bill): os.lstat on here to check for error
|
||||||
m := make([]string, 1, allocator)
|
m := make([]string, 1)
|
||||||
m[0] = pattern
|
m[0] = pattern
|
||||||
return m[:], .None
|
return m[:], .None
|
||||||
}
|
}
|
||||||
|
|
||||||
temp_buf: [8]byte
|
|
||||||
|
|
||||||
dir, file := split(pattern)
|
dir, file := split(pattern)
|
||||||
volume_len := 0
|
volume_len := 0
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
|
temp_buf: [8]byte
|
||||||
volume_len, dir = clean_glob_path_windows(dir, temp_buf[:])
|
volume_len, dir = clean_glob_path_windows(dir, temp_buf[:])
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
dir = clean_glob_path(dir)
|
dir = clean_glob_path(dir)
|
||||||
}
|
}
|
||||||
@@ -247,7 +249,7 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str
|
|||||||
if err != .None {
|
if err != .None {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dmatches := make([dynamic]string, 0, 0, allocator)
|
dmatches := make([dynamic]string, 0, 0)
|
||||||
for d in m {
|
for d in m {
|
||||||
dmatches, err = _glob(d, file, &dmatches)
|
dmatches, err = _glob(d, file, &dmatches)
|
||||||
if err != .None {
|
if err != .None {
|
||||||
@@ -259,11 +261,13 @@ glob :: proc(pattern: string, allocator := context.allocator) -> (matches: []str
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]string, e: Match_Error) {
|
_glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := context.allocator) -> (m: [dynamic]string, e: Match_Error) {
|
||||||
|
context.allocator = allocator
|
||||||
|
|
||||||
if matches != nil {
|
if matches != nil {
|
||||||
m = matches^
|
m = matches^
|
||||||
} else {
|
} else {
|
||||||
m = make([dynamic]string, 0, 0, context.allocator)
|
m = make([dynamic]string, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -276,6 +280,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
|
|||||||
{
|
{
|
||||||
file_info, ferr := os.fstat(d)
|
file_info, ferr := os.fstat(d)
|
||||||
defer os.file_info_delete(file_info)
|
defer os.file_info_delete(file_info)
|
||||||
|
|
||||||
if ferr != 0 {
|
if ferr != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -308,7 +313,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
|
|||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
has_meta :: proc(path: string) -> bool {
|
has_meta :: proc(path: string) -> bool {
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
CHARS :: `*?[`
|
CHARS :: `*?[`
|
||||||
} else {
|
} else {
|
||||||
CHARS :: `*?[\`
|
CHARS :: `*?[\`
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// The path/filepath package uses either forward slashes or backslashes depending on the operating system
|
// The path/filepath package uses either forward slashes or backslashes depending on the operating system
|
||||||
// To process paths usch as URLs that depend on forward slashes regardless of the OS, use the path package
|
// To process paths such as URLs that depend on forward slashes regardless of the OS, use the path package
|
||||||
package filepath
|
package filepath
|
||||||
|
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
@@ -8,7 +8,7 @@ import "core:strings"
|
|||||||
is_separator :: proc(c: byte) -> bool {
|
is_separator :: proc(c: byte) -> bool {
|
||||||
switch c {
|
switch c {
|
||||||
case '/': return true
|
case '/': return true
|
||||||
case '\\': return ODIN_OS == "windows"
|
case '\\': return ODIN_OS == .Windows
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ volume_name :: proc(path: string) -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
volume_name_len :: proc(path: string) -> int {
|
volume_name_len :: proc(path: string) -> int {
|
||||||
if ODIN_OS == "windows" {
|
if ODIN_OS == .Windows {
|
||||||
if len(path) < 2 {
|
if len(path) < 2 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -122,6 +122,7 @@ clean :: proc(path: string, allocator := context.allocator) -> string {
|
|||||||
vol_and_path = original_path,
|
vol_and_path = original_path,
|
||||||
vol_len = vol_len,
|
vol_len = vol_len,
|
||||||
}
|
}
|
||||||
|
defer lazy_buffer_destroy(out)
|
||||||
|
|
||||||
r, dot_dot := 0, 0
|
r, dot_dot := 0, 0
|
||||||
if rooted {
|
if rooted {
|
||||||
@@ -170,7 +171,6 @@ clean :: proc(path: string, allocator := context.allocator) -> string {
|
|||||||
cleaned, new_allocation := from_slash(s)
|
cleaned, new_allocation := from_slash(s)
|
||||||
if new_allocation {
|
if new_allocation {
|
||||||
delete(s)
|
delete(s)
|
||||||
lazy_buffer_destroy(out)
|
|
||||||
}
|
}
|
||||||
return cleaned
|
return cleaned
|
||||||
}
|
}
|
||||||
@@ -284,13 +284,14 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
|
|||||||
}
|
}
|
||||||
|
|
||||||
dir :: proc(path: string, allocator := context.allocator) -> string {
|
dir :: proc(path: string, allocator := context.allocator) -> string {
|
||||||
|
context.allocator = allocator
|
||||||
vol := volume_name(path)
|
vol := volume_name(path)
|
||||||
i := len(path) - 1
|
i := len(path) - 1
|
||||||
for i >= len(vol) && !is_separator(path[i]) {
|
for i >= len(vol) && !is_separator(path[i]) {
|
||||||
i -= 1
|
i -= 1
|
||||||
}
|
}
|
||||||
dir := clean(path[len(vol) : i+1], allocator)
|
dir := clean(path[len(vol) : i+1])
|
||||||
defer delete(dir, allocator)
|
defer delete(dir)
|
||||||
if dir == "." && len(vol) > 2 {
|
if dir == "." && len(vol) > 2 {
|
||||||
return strings.clone(vol)
|
return strings.clone(vol)
|
||||||
}
|
}
|
||||||
@@ -299,6 +300,11 @@ dir :: proc(path: string, allocator := context.allocator) -> string {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Splits the PATH-like `path` string, returning an array of its separated components (delete after use).
|
||||||
|
// For Windows the separator is `;`, for Unix it's `:`.
|
||||||
|
// An empty string returns nil. A non-empty string with no separators returns a 1-element array.
|
||||||
|
// Any empty components will be included, e.g. `a::b` will return a 3-element array, as will `::`.
|
||||||
|
// Separators within pairs of double-quotes will be ignored and stripped, e.g. `"a:b"c:d` will return []{`a:bc`, `d`}.
|
||||||
split_list :: proc(path: string, allocator := context.allocator) -> []string {
|
split_list :: proc(path: string, allocator := context.allocator) -> []string {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return nil
|
return nil
|
||||||
@@ -321,7 +327,7 @@ split_list :: proc(path: string, allocator := context.allocator) -> []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start, quote = 0, false
|
start, quote = 0, false
|
||||||
list := make([]string, count, allocator)
|
list := make([]string, count + 1, allocator)
|
||||||
index := 0
|
index := 0
|
||||||
for i := 0; i < len(path); i += 1 {
|
for i := 0; i < len(path); i += 1 {
|
||||||
c := path[i]
|
c := path[i]
|
||||||
@@ -335,6 +341,7 @@ split_list :: proc(path: string, allocator := context.allocator) -> []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(index == count)
|
assert(index == count)
|
||||||
|
list[index] = path[start:]
|
||||||
|
|
||||||
for s0, i in list {
|
for s0, i in list {
|
||||||
s, new := strings.replace_all(s0, `"`, ``, allocator)
|
s, new := strings.replace_all(s0, `"`, ``, allocator)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//+build linux, darwin, freebsd
|
//+build linux, darwin, freebsd, openbsd
|
||||||
package filepath
|
package filepath
|
||||||
|
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
foreign import libc "System.framework"
|
foreign import libc "System.framework"
|
||||||
} else {
|
} else {
|
||||||
foreign import libc "system:c"
|
foreign import libc "system:c"
|
||||||
@@ -54,11 +54,16 @@ foreign libc {
|
|||||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||||
|
|
||||||
}
|
}
|
||||||
when ODIN_OS == "darwin" {
|
when ODIN_OS == .Darwin {
|
||||||
@(private)
|
@(private)
|
||||||
foreign libc {
|
foreign libc {
|
||||||
@(link_name="__error") __error :: proc() -> ^i32 ---
|
@(link_name="__error") __error :: proc() -> ^i32 ---
|
||||||
}
|
}
|
||||||
|
} else when ODIN_OS == .OpenBSD {
|
||||||
|
@(private)
|
||||||
|
foreign libc {
|
||||||
|
@(link_name="__errno") __error :: proc() -> ^i32 ---
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
@(private)
|
@(private)
|
||||||
foreign libc {
|
foreign libc {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc) -> (err: os.Errno, skip_
|
|||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Errno) {
|
read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Errno) {
|
||||||
f, err := os.open(dir_name)
|
f, err := os.open(dir_name, os.O_RDONLY)
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ is_nil :: proc(v: any) -> bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
data := as_bytes(v)
|
data := as_bytes(v)
|
||||||
if data != nil {
|
if data == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for v in data {
|
for v in data {
|
||||||
@@ -365,6 +365,19 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deref :: proc(val: any) -> any {
|
||||||
|
if val != nil {
|
||||||
|
ti := type_info_base(type_info_of(val.id))
|
||||||
|
if info, ok := ti.variant.(Type_Info_Pointer); ok {
|
||||||
|
return any{
|
||||||
|
(^rawptr)(val.data)^,
|
||||||
|
info.elem.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Struct_Tag represents the type of the string of a struct field
|
// Struct_Tag represents the type of the string of a struct field
|
||||||
@@ -680,7 +693,6 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
panic("expected a union to reflect.union_variant_typeid")
|
panic("expected a union to reflect.union_variant_typeid")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||||
@@ -1042,6 +1054,7 @@ as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
|||||||
case Type_Info_Float:
|
case Type_Info_Float:
|
||||||
valid = true
|
valid = true
|
||||||
switch v in a {
|
switch v in a {
|
||||||
|
case f16: value = u64(v)
|
||||||
case f32: value = u64(v)
|
case f32: value = u64(v)
|
||||||
case f64: value = u64(v)
|
case f64: value = u64(v)
|
||||||
case f32le: value = u64(v)
|
case f32le: value = u64(v)
|
||||||
@@ -1147,6 +1160,7 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
|||||||
case Type_Info_Float:
|
case Type_Info_Float:
|
||||||
valid = true
|
valid = true
|
||||||
switch v in a {
|
switch v in a {
|
||||||
|
case f16: value = f64(v)
|
||||||
case f32: value = f64(v)
|
case f32: value = f64(v)
|
||||||
case f64: value = (v)
|
case f64: value = (v)
|
||||||
case f32le: value = f64(v)
|
case f32le: value = f64(v)
|
||||||
|
|||||||
@@ -334,11 +334,11 @@ is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid) {
|
write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) {
|
||||||
write_type(buf, type_info_of(id))
|
return write_type_writer(strings.to_writer(buf), type_info_of(id))
|
||||||
}
|
}
|
||||||
write_typeid_writer :: proc(writer: io.Writer, id: typeid) {
|
write_typeid_writer :: proc(writer: io.Writer, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) {
|
||||||
write_type(writer, type_info_of(id))
|
return write_type_writer(writer, type_info_of(id), n_written)
|
||||||
}
|
}
|
||||||
|
|
||||||
write_typeid :: proc{
|
write_typeid :: proc{
|
||||||
@@ -472,6 +472,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
|
|||||||
write_type(w, info.elem, &n) or_return
|
write_type(w, info.elem, &n) or_return
|
||||||
|
|
||||||
case Type_Info_Enumerated_Array:
|
case Type_Info_Enumerated_Array:
|
||||||
|
if info.is_sparse {
|
||||||
|
io.write_string(w, "#sparse", &n) or_return
|
||||||
|
}
|
||||||
io.write_string(w, "[", &n) or_return
|
io.write_string(w, "[", &n) or_return
|
||||||
write_type(w, info.index, &n) or_return
|
write_type(w, info.index, &n) or_return
|
||||||
io.write_string(w, "]", &n) or_return
|
io.write_string(w, "]", &n) or_return
|
||||||
|
|||||||
+54
-12
@@ -33,6 +33,11 @@ Calling_Convention :: enum u8 {
|
|||||||
|
|
||||||
None = 6,
|
None = 6,
|
||||||
Naked = 7,
|
Naked = 7,
|
||||||
|
|
||||||
|
_ = 8, // reserved
|
||||||
|
|
||||||
|
Win64 = 9,
|
||||||
|
SysV = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Info_Enum_Value :: distinct i64
|
Type_Info_Enum_Value :: distinct i64
|
||||||
@@ -95,6 +100,7 @@ Type_Info_Enumerated_Array :: struct {
|
|||||||
count: int,
|
count: int,
|
||||||
min_value: Type_Info_Enum_Value,
|
min_value: Type_Info_Enum_Value,
|
||||||
max_value: Type_Info_Enum_Value,
|
max_value: Type_Info_Enum_Value,
|
||||||
|
is_sparse: bool,
|
||||||
}
|
}
|
||||||
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int}
|
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int}
|
||||||
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int}
|
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int}
|
||||||
@@ -130,6 +136,7 @@ Type_Info_Union :: struct {
|
|||||||
custom_align: bool,
|
custom_align: bool,
|
||||||
no_nil: bool,
|
no_nil: bool,
|
||||||
maybe: bool,
|
maybe: bool,
|
||||||
|
shared_nil: bool,
|
||||||
}
|
}
|
||||||
Type_Info_Enum :: struct {
|
Type_Info_Enum :: struct {
|
||||||
base: ^Type_Info,
|
base: ^Type_Info,
|
||||||
@@ -345,7 +352,6 @@ Context :: struct {
|
|||||||
assertion_failure_proc: Assertion_Failure_Proc,
|
assertion_failure_proc: Assertion_Failure_Proc,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
|
|
||||||
user_data: any,
|
|
||||||
user_ptr: rawptr,
|
user_ptr: rawptr,
|
||||||
user_index: int,
|
user_index: int,
|
||||||
|
|
||||||
@@ -386,6 +392,35 @@ Raw_Cstring :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Defined internally by the compiler
|
||||||
|
Odin_OS_Type :: enum int {
|
||||||
|
Unknown,
|
||||||
|
Windows,
|
||||||
|
Darwin,
|
||||||
|
Linux,
|
||||||
|
Essence,
|
||||||
|
FreeBSD,
|
||||||
|
WASI,
|
||||||
|
JS,
|
||||||
|
Freestanding,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Odin_OS_Type :: type_of(ODIN_OS)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Defined internally by the compiler
|
||||||
|
Odin_Arch_Type :: enum int {
|
||||||
|
Unknown,
|
||||||
|
amd64,
|
||||||
|
i386,
|
||||||
|
arm64,
|
||||||
|
wasm32,
|
||||||
|
wasm64,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Odin_Arch_Type :: type_of(ODIN_ARCH)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Defined internally by the compiler
|
// Defined internally by the compiler
|
||||||
Odin_Build_Mode_Type :: enum int {
|
Odin_Build_Mode_Type :: enum int {
|
||||||
@@ -417,7 +452,7 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
|||||||
// This is probably only useful for freestanding targets
|
// This is probably only useful for freestanding targets
|
||||||
foreign {
|
foreign {
|
||||||
@(link_name="__$startup_runtime")
|
@(link_name="__$startup_runtime")
|
||||||
_startup_runtime :: proc() ---
|
_startup_runtime :: proc "odin" () ---
|
||||||
}
|
}
|
||||||
|
|
||||||
@(link_name="__$cleanup_runtime")
|
@(link_name="__$cleanup_runtime")
|
||||||
@@ -425,6 +460,11 @@ _cleanup_runtime :: proc() {
|
|||||||
default_temp_allocator_destroy(&global_default_temp_allocator_data)
|
default_temp_allocator_destroy(&global_default_temp_allocator_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cleanup_runtime_contextless :: proc "contextless" () {
|
||||||
|
context = default_context()
|
||||||
|
_cleanup_runtime()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
@@ -474,16 +514,18 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check
|
|||||||
return &type_table[n]
|
return &type_table[n]
|
||||||
}
|
}
|
||||||
|
|
||||||
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
when !ODIN_DISALLOW_RTTI {
|
||||||
ti := type_info_of(id)
|
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||||
ti = type_info_base(ti)
|
ti := type_info_of(id)
|
||||||
return ti.id
|
ti = type_info_base(ti)
|
||||||
|
return ti.id
|
||||||
|
}
|
||||||
|
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
||||||
|
ti := type_info_core(type_info_of(id))
|
||||||
|
return ti.id
|
||||||
|
}
|
||||||
|
typeid_base_without_enum :: typeid_core
|
||||||
}
|
}
|
||||||
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
|
||||||
ti := type_info_core(type_info_of(id))
|
|
||||||
return ti.id
|
|
||||||
}
|
|
||||||
typeid_base_without_enum :: typeid_core
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -539,7 +581,7 @@ __init_context :: proc "contextless" (c: ^Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
|
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
|
||||||
when ODIN_OS == "freestanding" {
|
when ODIN_OS == .Freestanding {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else {
|
} else {
|
||||||
print_caller_location(loc)
|
print_caller_location(loc)
|
||||||
|
|||||||
@@ -386,12 +386,13 @@ insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
|
|||||||
if array == nil {
|
if array == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n := len(array)
|
n := max(len(array), index)
|
||||||
m :: 1
|
m :: 1
|
||||||
resize(array, n+m, loc)
|
new_size := n + m
|
||||||
if n+m <= len(array) {
|
|
||||||
|
if resize(array, new_size, loc) {
|
||||||
when size_of(E) != 0 {
|
when size_of(E) != 0 {
|
||||||
copy(array[index+m:], array[index:])
|
copy(array[index + m:], array[index:])
|
||||||
array[index] = arg
|
array[index] = arg
|
||||||
}
|
}
|
||||||
ok = true
|
ok = true
|
||||||
@@ -409,12 +410,13 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
n := len(array)
|
n := max(len(array), index)
|
||||||
m := len(args)
|
m := len(args)
|
||||||
resize(array, n+m, loc)
|
new_size := n + m
|
||||||
if n+m <= len(array) {
|
|
||||||
|
if resize(array, new_size, loc) {
|
||||||
when size_of(E) != 0 {
|
when size_of(E) != 0 {
|
||||||
copy(array[index+m:], array[index:])
|
copy(array[index + m:], array[index:])
|
||||||
copy(array[index:], args)
|
copy(array[index:], args)
|
||||||
}
|
}
|
||||||
ok = true
|
ok = true
|
||||||
@@ -427,17 +429,18 @@ insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
|
|||||||
if array == nil {
|
if array == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(args) == 0 {
|
if len(arg) == 0 {
|
||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
n := len(array)
|
n := max(len(array), index)
|
||||||
m := len(args)
|
m := len(arg)
|
||||||
resize(array, n+m, loc)
|
new_size := n + m
|
||||||
if n+m <= len(array) {
|
|
||||||
|
if resize(array, new_size, loc) {
|
||||||
copy(array[index+m:], array[index:])
|
copy(array[index+m:], array[index:])
|
||||||
copy(array[index:], args)
|
copy(array[index:], arg)
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ nil_allocator :: proc() -> Allocator {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == "freestanding" {
|
when ODIN_OS == .Freestanding {
|
||||||
default_allocator_proc :: nil_allocator_proc
|
default_allocator_proc :: nil_allocator_proc
|
||||||
default_allocator :: nil_allocator
|
default_allocator :: nil_allocator
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ package runtime
|
|||||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
|
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == "freestanding" || ODIN_OS == "js" || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||||
Default_Temp_Allocator :: struct {}
|
Default_Temp_Allocator :: struct {}
|
||||||
|
|
||||||
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {}
|
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backup_allocator := context.allocator) {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//+private
|
//+private
|
||||||
//+build linux, darwin, freebsd
|
//+build linux, darwin, freebsd, openbsd
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
@@ -30,4 +30,4 @@ when ODIN_BUILD_MODE == .Dynamic {
|
|||||||
#force_no_inline _cleanup_runtime()
|
#force_no_inline _cleanup_runtime()
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ when ODIN_BUILD_MODE == .Dynamic {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||||
when ODIN_ARCH == "i386" || ODIN_NO_CRT {
|
when ODIN_ARCH == .i386 || ODIN_NO_CRT {
|
||||||
@(link_name="mainCRTStartup", linkage="strong", require)
|
@(link_name="mainCRTStartup", linkage="strong", require)
|
||||||
mainCRTStartup :: proc "stdcall" () -> i32 {
|
mainCRTStartup :: proc "stdcall" () -> i32 {
|
||||||
context = default_context()
|
context = default_context()
|
||||||
|
|||||||
+104
-68
@@ -1,7 +1,7 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
bounds_trap :: proc "contextless" () -> ! {
|
bounds_trap :: proc "contextless" () -> ! {
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
windows_trap_array_bounds()
|
windows_trap_array_bounds()
|
||||||
} else {
|
} else {
|
||||||
trap()
|
trap()
|
||||||
@@ -9,7 +9,7 @@ bounds_trap :: proc "contextless" () -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type_assertion_trap :: proc "contextless" () -> ! {
|
type_assertion_trap :: proc "contextless" () -> ! {
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == .Windows {
|
||||||
windows_trap_type_assertion()
|
windows_trap_type_assertion()
|
||||||
} else {
|
} else {
|
||||||
trap()
|
trap()
|
||||||
@@ -21,11 +21,12 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
|||||||
if 0 <= index && index < count {
|
if 0 <= index && index < count {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@(cold)
|
||||||
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
print_string(" Index ")
|
print_string(" Index ")
|
||||||
print_i64(i64(index))
|
print_i64(i64(index))
|
||||||
print_string(" is out of bounds range 0:")
|
print_string(" is out of range 0..<")
|
||||||
print_i64(i64(count))
|
print_i64(i64(count))
|
||||||
print_byte('\n')
|
print_byte('\n')
|
||||||
bounds_trap()
|
bounds_trap()
|
||||||
@@ -35,11 +36,11 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
|||||||
|
|
||||||
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
|
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
print_string(" Invalid slice indices: ")
|
print_string(" Invalid slice indices ")
|
||||||
print_i64(i64(lo))
|
print_i64(i64(lo))
|
||||||
print_string(":")
|
print_string(":")
|
||||||
print_i64(i64(hi))
|
print_i64(i64(hi))
|
||||||
print_string(":")
|
print_string(" is out of range 0..<")
|
||||||
print_i64(i64(len))
|
print_i64(i64(len))
|
||||||
print_byte('\n')
|
print_byte('\n')
|
||||||
bounds_trap()
|
bounds_trap()
|
||||||
@@ -47,7 +48,7 @@ slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, h
|
|||||||
|
|
||||||
multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! {
|
multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! {
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
print_string(" Invalid slice indices: ")
|
print_string(" Invalid slice indices ")
|
||||||
print_i64(i64(lo))
|
print_i64(i64(lo))
|
||||||
print_string(":")
|
print_string(":")
|
||||||
print_i64(i64(hi))
|
print_i64(i64(hi))
|
||||||
@@ -81,13 +82,14 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
|||||||
if 0 <= low && low <= high && high <= max {
|
if 0 <= low && low <= high && high <= max {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@(cold)
|
||||||
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
print_string(" Invalid dynamic array values: ")
|
print_string(" Invalid dynamic array indices ")
|
||||||
print_i64(i64(low))
|
print_i64(i64(low))
|
||||||
print_string(":")
|
print_string(":")
|
||||||
print_i64(i64(high))
|
print_i64(i64(high))
|
||||||
print_string(":")
|
print_string(" is out of range 0..<")
|
||||||
print_i64(i64(max))
|
print_i64(i64(max))
|
||||||
print_byte('\n')
|
print_byte('\n')
|
||||||
bounds_trap()
|
bounds_trap()
|
||||||
@@ -97,17 +99,18 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
|||||||
|
|
||||||
|
|
||||||
matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
||||||
if 0 <= row_index && row_index < row_count &&
|
if 0 <= row_index && row_index < row_count &&
|
||||||
0 <= column_index && column_index < column_count {
|
0 <= column_index && column_index < column_count {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@(cold)
|
||||||
handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
print_string(" Matrix indices [")
|
print_string(" Matrix indices [")
|
||||||
print_i64(i64(row_index))
|
print_i64(i64(row_index))
|
||||||
print_string(", ")
|
print_string(", ")
|
||||||
print_i64(i64(column_index))
|
print_i64(i64(column_index))
|
||||||
print_string(" is out of bounds range [0..<")
|
print_string(" is out of range [0..<")
|
||||||
print_i64(i64(row_count))
|
print_i64(i64(row_count))
|
||||||
print_string(", 0..<")
|
print_string(", 0..<")
|
||||||
print_i64(i64(column_count))
|
print_i64(i64(column_count))
|
||||||
@@ -119,71 +122,101 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
|
when ODIN_DISALLOW_RTTI {
|
||||||
if ok {
|
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) {
|
||||||
return
|
if ok {
|
||||||
}
|
return
|
||||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
|
}
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
@(cold)
|
||||||
print_string(" Invalid type assertion from ")
|
handle_error :: proc "contextless" (file: string, line, column: i32) {
|
||||||
print_typeid(from)
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
print_string(" to ")
|
print_string(" Invalid type assertion\n")
|
||||||
print_typeid(to)
|
type_assertion_trap()
|
||||||
print_byte('\n')
|
}
|
||||||
type_assertion_trap()
|
handle_error(file, line, column)
|
||||||
}
|
|
||||||
handle_error(file, line, column, from, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
|
||||||
if ok {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
|
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32) {
|
||||||
if id == nil || data == nil {
|
if ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@(cold)
|
||||||
|
handle_error :: proc "contextless" (file: string, line, column: i32) {
|
||||||
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
|
print_string(" Invalid type assertion\n")
|
||||||
|
type_assertion_trap()
|
||||||
|
}
|
||||||
|
handle_error(file, line, column)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
|
||||||
|
if ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@(cold)
|
||||||
|
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
|
||||||
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
|
print_string(" Invalid type assertion from ")
|
||||||
|
print_typeid(from)
|
||||||
|
print_string(" to ")
|
||||||
|
print_typeid(to)
|
||||||
|
print_byte('\n')
|
||||||
|
type_assertion_trap()
|
||||||
|
}
|
||||||
|
handle_error(file, line, column, from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||||
|
if ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
|
||||||
|
if id == nil || data == nil {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
ti := type_info_base(type_info_of(id))
|
||||||
|
#partial switch v in ti.variant {
|
||||||
|
case Type_Info_Any:
|
||||||
|
return (^any)(data).id
|
||||||
|
case Type_Info_Union:
|
||||||
|
tag_ptr := uintptr(data) + v.tag_offset
|
||||||
|
idx := 0
|
||||||
|
switch v.tag_type.size {
|
||||||
|
case 1: idx = int((^u8)(tag_ptr)^) - 1
|
||||||
|
case 2: idx = int((^u16)(tag_ptr)^) - 1
|
||||||
|
case 4: idx = int((^u32)(tag_ptr)^) - 1
|
||||||
|
case 8: idx = int((^u64)(tag_ptr)^) - 1
|
||||||
|
case 16: idx = int((^u128)(tag_ptr)^) - 1
|
||||||
|
}
|
||||||
|
if idx < 0 {
|
||||||
|
return nil
|
||||||
|
} else if idx < len(v.variants) {
|
||||||
|
return v.variants[idx].id
|
||||||
|
}
|
||||||
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
ti := type_info_base(type_info_of(id))
|
|
||||||
#partial switch v in ti.variant {
|
@(cold)
|
||||||
case Type_Info_Any:
|
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||||
return (^any)(data).id
|
|
||||||
case Type_Info_Union:
|
actual := variant_type(from, from_data)
|
||||||
tag_ptr := uintptr(data) + v.tag_offset
|
|
||||||
idx := 0
|
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||||
switch v.tag_type.size {
|
print_string(" Invalid type assertion from ")
|
||||||
case 1: idx = int((^u8)(tag_ptr)^) - 1
|
print_typeid(from)
|
||||||
case 2: idx = int((^u16)(tag_ptr)^) - 1
|
print_string(" to ")
|
||||||
case 4: idx = int((^u32)(tag_ptr)^) - 1
|
print_typeid(to)
|
||||||
case 8: idx = int((^u64)(tag_ptr)^) - 1
|
if actual != from {
|
||||||
case 16: idx = int((^u128)(tag_ptr)^) - 1
|
print_string(", actual type: ")
|
||||||
}
|
print_typeid(actual)
|
||||||
if idx < 0 {
|
|
||||||
return nil
|
|
||||||
} else if idx < len(v.variants) {
|
|
||||||
return v.variants[idx].id
|
|
||||||
}
|
}
|
||||||
|
print_byte('\n')
|
||||||
|
type_assertion_trap()
|
||||||
}
|
}
|
||||||
return id
|
handle_error(file, line, column, from, to, from_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
|
||||||
|
|
||||||
actual := variant_type(from, from_data)
|
|
||||||
|
|
||||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
|
||||||
print_string(" Invalid type assertion from ")
|
|
||||||
print_typeid(from)
|
|
||||||
print_string(" to ")
|
|
||||||
print_typeid(to)
|
|
||||||
if actual != from {
|
|
||||||
print_string(", actual type: ")
|
|
||||||
print_typeid(actual)
|
|
||||||
}
|
|
||||||
print_byte('\n')
|
|
||||||
type_assertion_trap()
|
|
||||||
}
|
|
||||||
handle_error(file, line, column, from, to, from_data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -191,6 +224,7 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
|
|||||||
if 0 <= len {
|
if 0 <= len {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@(cold)
|
||||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
|
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
|
||||||
print_caller_location(loc)
|
print_caller_location(loc)
|
||||||
print_string(" Invalid slice length for make: ")
|
print_string(" Invalid slice length for make: ")
|
||||||
@@ -205,6 +239,7 @@ make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #
|
|||||||
if 0 <= len && len <= cap {
|
if 0 <= len && len <= cap {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@(cold)
|
||||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
|
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
|
||||||
print_caller_location(loc)
|
print_caller_location(loc)
|
||||||
print_string(" Invalid dynamic array parameters for make: ")
|
print_string(" Invalid dynamic array parameters for make: ")
|
||||||
@@ -221,6 +256,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
|
|||||||
if 0 <= cap {
|
if 0 <= cap {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@(cold)
|
||||||
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
|
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
|
||||||
print_caller_location(loc)
|
print_caller_location(loc)
|
||||||
print_string(" Invalid map capacity for make: ")
|
print_string(" Invalid map capacity for make: ")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package runtime
|
|||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
IS_WASM :: ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64"
|
IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
RUNTIME_LINKAGE :: "strong" when (
|
RUNTIME_LINKAGE :: "strong" when (
|
||||||
@@ -37,10 +37,8 @@ bswap_64 :: proc "contextless" (x: u64) -> u64 {
|
|||||||
|
|
||||||
bswap_128 :: proc "contextless" (x: u128) -> u128 {
|
bswap_128 :: proc "contextless" (x: u128) -> u128 {
|
||||||
z := transmute([4]u32)x
|
z := transmute([4]u32)x
|
||||||
z[0] = bswap_32(z[3])
|
z[0], z[3] = bswap_32(z[3]), bswap_32(z[0])
|
||||||
z[1] = bswap_32(z[2])
|
z[1], z[2] = bswap_32(z[2]), bswap_32(z[1])
|
||||||
z[2] = bswap_32(z[1])
|
|
||||||
z[3] = bswap_32(z[0])
|
|
||||||
return transmute(u128)z
|
return transmute(u128)z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-4
@@ -160,11 +160,19 @@ print_caller_location :: proc "contextless" (using loc: Source_Code_Location) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_typeid :: proc "contextless" (id: typeid) {
|
print_typeid :: proc "contextless" (id: typeid) {
|
||||||
if id == nil {
|
when ODIN_DISALLOW_RTTI {
|
||||||
print_string("nil")
|
if id == nil {
|
||||||
|
print_string("nil")
|
||||||
|
} else {
|
||||||
|
print_string("<unknown type>")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ti := type_info_of(id)
|
if id == nil {
|
||||||
print_type(ti)
|
print_string("nil")
|
||||||
|
} else {
|
||||||
|
ti := type_info_of(id)
|
||||||
|
print_type(ti)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_type :: proc "contextless" (ti: ^Type_Info) {
|
print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||||
@@ -260,6 +268,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
|
|||||||
print_type(info.elem)
|
print_type(info.elem)
|
||||||
|
|
||||||
case Type_Info_Enumerated_Array:
|
case Type_Info_Enumerated_Array:
|
||||||
|
if info.is_sparse {
|
||||||
|
print_string("#sparse")
|
||||||
|
}
|
||||||
print_byte('[')
|
print_byte('[')
|
||||||
print_type(info.index)
|
print_type(info.index)
|
||||||
print_byte(']')
|
print_byte(']')
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user