mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 03:01:38 -07:00
Compare commits
218 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aa796a1032 | |||
| 5bf71ba75c | |||
| 967981aacd | |||
| 33d05a07de | |||
| 8da8301b09 | |||
| 536cceeef9 | |||
| 098684a6fe | |||
| 2ef7bfc06e | |||
| 7bfdb4f9f4 | |||
| 0a35b13411 | |||
| dacfc9de15 | |||
| 689aa4d734 | |||
| 8a46b493fd | |||
| 86abdc0603 | |||
| a634444f99 | |||
| 04a25b11ad | |||
| 40546fbde2 | |||
| c1176c2bcb | |||
| 57853fe1b1 | |||
| 013b3b9fb3 | |||
| dc0f04e53b | |||
| 40606d9272 | |||
| ebf7926fa4 | |||
| dfb3101ecf | |||
| e3d3a81617 | |||
| dbdbbcd60f | |||
| f9aaff99c6 | |||
| 57565b78a6 | |||
| b5b085914a | |||
| 044e64beb0 | |||
| adca5b57cd | |||
| 3b898e5224 | |||
| 153e7525b5 | |||
| 44a303e577 | |||
| d63878d0dd | |||
| a20c31d6b5 | |||
| 560bdc339b | |||
| 01dfb1dac8 | |||
| ee8d3e03f8 | |||
| 4aad45e3e7 | |||
| fe5c642d9f | |||
| b5fdb3f855 | |||
| 416ff149bd | |||
| 233c6e2d3a | |||
| a29a6d9285 | |||
| a7a31e4c23 | |||
| 72cad591bd | |||
| 684bf7aa61 | |||
| d760b95e4f | |||
| 5e81fc72b9 | |||
| 0977ac111a | |||
| 2db16d6a32 | |||
| 5aa46d31b2 | |||
| 14e8b299b7 | |||
| c7cb754514 | |||
| a5e42a0465 | |||
| d808f9eccf | |||
| 1734eb949f | |||
| 7fae890ef9 | |||
| 94879ed149 | |||
| 2c75fe2314 | |||
| 1da0668653 | |||
| c60fb10a6a | |||
| 7140f42915 | |||
| ad92fbfd4e | |||
| 1416946757 | |||
| 6a8c4ee04c | |||
| 516df9123d | |||
| 818d6dbbea | |||
| 286c5b7b24 | |||
| c0e8113f6f | |||
| e15dfa8eb6 | |||
| f12ded54f2 | |||
| b4951c9b39 | |||
| 9f0a28017d | |||
| d7c8a3a9dd | |||
| 10b109e25f | |||
| 2afe4bea67 | |||
| 12ae5ed09e | |||
| 0bdc3b4f21 | |||
| eaabb888d4 | |||
| b53fe14c22 | |||
| 45683703ea | |||
| 03053a18ce | |||
| 2a6d9e8927 | |||
| fa81061db0 | |||
| 39b3c8c80f | |||
| 3139151935 | |||
| 672a8f5dbd | |||
| 8672ff1c55 | |||
| abfa894566 | |||
| 5b52fed268 | |||
| 94a638b436 | |||
| 1b8c3ca22a | |||
| 71b32ae117 | |||
| 939459b635 | |||
| 562b518394 | |||
| d62503d031 | |||
| 4e8a801b35 | |||
| e1b711b3b3 | |||
| 6c69e8c043 | |||
| 7fa2d25eea | |||
| dae514a2c9 | |||
| 068993a819 | |||
| 66ae4e5afc | |||
| 218d1131e8 | |||
| f4f6e9ad49 | |||
| 48ab7f876c | |||
| 1e53a6fa96 | |||
| 4cef160c87 | |||
| 68582c5ad1 | |||
| a9a2dafca5 | |||
| da3467c25f | |||
| 5fc42bf9c9 | |||
| 42bbd31df1 | |||
| c7cc38b7d8 | |||
| 4afc78efc6 | |||
| bc34083c9c | |||
| 08dd8414c1 | |||
| d54255505a | |||
| d4914c3546 | |||
| 772c8779fa | |||
| c92b2e9612 | |||
| 1af143b749 | |||
| 1370c10d1b | |||
| 1348d8a8cd | |||
| 495aaacb81 | |||
| 22e982c8fb | |||
| 6d614ef07c | |||
| 723f351a6d | |||
| c93872cc13 | |||
| 97dece15d7 | |||
| 657103c4cf | |||
| b9d3129fb3 | |||
| b311540b16 | |||
| 07ced1cf0e | |||
| a1d4ea7718 | |||
| f921a91fc8 | |||
| 4dade34603 | |||
| d76249d90b | |||
| d118fc569a | |||
| 2dc39a5cbd | |||
| c89fc35e94 | |||
| 614d209824 | |||
| f1a7b31209 | |||
| 6a8b3fee38 | |||
| 4551521b2c | |||
| 97dfcffa76 | |||
| 6d3feb4531 | |||
| c44d25d14f | |||
| 25dd00cd0b | |||
| 01c10aa944 | |||
| 4908d1ebdd | |||
| 7bc146e6fd | |||
| 59ab51acec | |||
| cf23954297 | |||
| d1cc6534cd | |||
| 1b454c7ded | |||
| 150d4e343d | |||
| 28ada801a0 | |||
| a7676bff6e | |||
| 4369298e96 | |||
| a58c29582e | |||
| 3ad20a2d2d | |||
| b86dfa7af7 | |||
| 980890ee8a | |||
| 0a63690b39 | |||
| 0076a4df62 | |||
| 4c065a7e99 | |||
| 04036aba9c | |||
| b08aa857b3 | |||
| 2d26278a65 | |||
| 27a3c5449a | |||
| 9c63212824 | |||
| 65d41d4248 | |||
| b04231dd95 | |||
| 37633c1d2a | |||
| 5877017d30 | |||
| 132fdf14b8 | |||
| e7d3001dd1 | |||
| f163181204 | |||
| 2c5c8192f8 | |||
| 162c87b1b8 | |||
| 77734ea967 | |||
| 912fc2890b | |||
| 14059583cd | |||
| f3bffb9810 | |||
| 540730c0be | |||
| 40f0e74b8c | |||
| 5ca0cd60d0 | |||
| 96f0a08725 | |||
| d85893954d | |||
| d26033eb23 | |||
| c7a70be824 | |||
| 08c490d9ac | |||
| 8ee7ee7120 | |||
| d471a59041 | |||
| f25818e923 | |||
| 3d531be711 | |||
| 56d365a4e7 | |||
| 308300c1fc | |||
| 927d6814f2 | |||
| 7c99f52187 | |||
| 4ab9edeb53 | |||
| c5b3d7a736 | |||
| d7172e168e | |||
| d99ffe604f | |||
| b77c79294c | |||
| 8e722274f0 | |||
| ebe7fc23a5 | |||
| 4d40f564ef | |||
| fd62959bf4 | |||
| 8b8cada33e | |||
| aaa24894b6 | |||
| 2af19c496e | |||
| fea34b32ea | |||
| b891c0feab | |||
| 9f039c323e |
@@ -1,4 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [gingerBill]
|
||||
patreon: gingerbill
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build_unix:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: (macOS) Download LLVM and setup PATH
|
||||
if: startsWith(matrix.os, 'macOS')
|
||||
run: |
|
||||
brew install llvm
|
||||
echo ::add-path::/usr/local/opt/llvm/bin
|
||||
echo ::set-env name=CPATH::`xcrun --show-sdk-path`/usr/include
|
||||
- name: (Linux) Download LLVM
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
sudo apt-get install llvm
|
||||
- name: build odin
|
||||
run: make release
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
- name: Odin check
|
||||
run: ./odin check examples/demo/demo.odin -vet
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install cURL
|
||||
run: choco install curl
|
||||
- name: Download and unpack LLVM bins
|
||||
shell: cmd
|
||||
run: |
|
||||
cd bin
|
||||
curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip
|
||||
7z x llvm-binaries.zip > nul
|
||||
- name: build Odin
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
./build_ci.bat
|
||||
- name: Odin run
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo/demo.odin
|
||||
- name: Odin check
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/demo/demo.odin -vet
|
||||
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
language: cpp
|
||||
git:
|
||||
depth: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- llvm
|
||||
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH="/usr/local/opt/llvm/bin:$PATH" ; fi
|
||||
- make release
|
||||
- ./odin run examples/demo/demo.odin
|
||||
- ./odin check examples/demo/demo.odin -vet
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
@@ -10,15 +10,12 @@
|
||||
<a href="https://github.com/odin-lang/odin/releases/latest">
|
||||
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
||||
</a>
|
||||
<a href="https://github.com/odin-lang/odin/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/odin-lang/odin.svg">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://ci.appveyor.com/project/ThisDrunkDane/odin-vf0ap">
|
||||
<img src="https://ci.appveyor.com/api/projects/status/qss6l921c0eu85u6/branch/master?svg=true">
|
||||
<a href="https://discord.gg/hnwN2Rj">
|
||||
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
||||
</a>
|
||||
<a href="https://travis-ci.org/odin-lang/Odin">
|
||||
<img src="https://travis-ci.org/odin-lang/Odin.svg?branch=master">
|
||||
<a href="https://github.com/odin-lang/odin/actions">
|
||||
<img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -71,9 +68,9 @@ Instructions for downloading and install the Odin compiler and libraries.
|
||||
|
||||
An overview of the Odin programming language.
|
||||
|
||||
#### [Frequently Asked Questsions (FAQ)](https://odin-lang.org/docs/faq)
|
||||
#### [Frequently Asked Questions (FAQ)](https://odin-lang.org/docs/faq)
|
||||
|
||||
Answers to common questsions about Odin.
|
||||
Answers to common questions about Odin.
|
||||
|
||||
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
shallow_clone: true
|
||||
|
||||
platform: x64
|
||||
|
||||
install:
|
||||
- cd bin
|
||||
- appveyor DownloadFile https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip
|
||||
- 7z x llvm-binaries.zip > nul
|
||||
- cd ..
|
||||
|
||||
build_script:
|
||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
- ./build_ci.bat
|
||||
|
||||
test_script:
|
||||
- odin run examples/demo/demo.odin
|
||||
- odin check examples/demo/demo.odin -vet
|
||||
@@ -39,7 +39,6 @@ set linker_settings=%libs% %linker_flags%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
|
||||
cl %compiler_settings% "src\main.cpp" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run examples/demo/demo.odin
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
// This is purely for documentation
|
||||
package builtin
|
||||
|
||||
nil :: nil;
|
||||
false :: 0!==0;
|
||||
true :: 0==0;
|
||||
|
||||
ODIN_OS :: ODIN_OS;
|
||||
ODIN_ARCH :: ODIN_ARCH;
|
||||
ODIN_ENDIAN :: ODIN_ENDIAN;
|
||||
ODIN_VENDOR :: ODIN_VENDOR;
|
||||
ODIN_VERSION :: ODIN_VERSION;
|
||||
ODIN_ROOT :: ODIN_ROOT;
|
||||
ODIN_DEBUG :: ODIN_DEBUG;
|
||||
|
||||
byte :: u8; // alias
|
||||
|
||||
bool :: bool;
|
||||
b8 :: b8;
|
||||
b16 :: b16;
|
||||
b32 :: b32;
|
||||
b64 :: b64;
|
||||
|
||||
i8 :: i8;
|
||||
u8 :: u8;
|
||||
i16 :: i16;
|
||||
u16 :: u16;
|
||||
i32 :: i32;
|
||||
u32 :: u32;
|
||||
i64 :: i64;
|
||||
u64 :: u64;
|
||||
|
||||
i128 :: i128;
|
||||
u128 :: u128;
|
||||
|
||||
rune :: rune;
|
||||
|
||||
f16 :: f16;
|
||||
f32 :: f32;
|
||||
f64 :: f64;
|
||||
|
||||
complex32 :: complex32;
|
||||
complex64 :: complex64;
|
||||
complex128 :: complex128;
|
||||
|
||||
quaternion128 :: quaternion128;
|
||||
quaternion256 :: quaternion256;
|
||||
|
||||
int :: int;
|
||||
uint :: uint;
|
||||
uintptr :: uintptr;
|
||||
|
||||
rawptr :: rawptr;
|
||||
string :: string;
|
||||
cstring :: cstring;
|
||||
any :: any;
|
||||
|
||||
typeid :: typeid;
|
||||
|
||||
// Endian Specific Types
|
||||
i16le :: i16le;
|
||||
u16le :: u16le;
|
||||
i32le :: i32le;
|
||||
u32le :: u32le;
|
||||
i64le :: i64le;
|
||||
u64le :: u64le;
|
||||
i128le :: i128le;
|
||||
u128le :: u128le;
|
||||
|
||||
i16be :: i16be;
|
||||
u16be :: u16be;
|
||||
i32be :: i32be;
|
||||
u32be :: u32be;
|
||||
i64be :: i64be;
|
||||
u64be :: u64be;
|
||||
i128be :: i128be;
|
||||
u128be :: u128be;
|
||||
|
||||
// Procedures
|
||||
len :: proc(array: Array_Type) -> int ---
|
||||
cap :: proc(array: Array_Type) -> int ---
|
||||
|
||||
size_of :: proc($T: typeid) -> int ---
|
||||
align_of :: proc($T: typeid) -> int ---
|
||||
offset_of :: proc($T: typeid) -> uintptr ---
|
||||
type_of :: proc(x: expr) -> type ---
|
||||
type_info_of :: proc($T: typeid) -> ^runtime.Type_Info ---
|
||||
typeid_of :: proc($T: typeid) -> typeid ---
|
||||
|
||||
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
|
||||
|
||||
complex :: proc(real, imag: Float) -> Complex_Type ---
|
||||
quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type ---
|
||||
real :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||
jmag :: proc(value: Quaternion) -> Float ---
|
||||
kmag :: proc(value: Quaternion) -> Float ---
|
||||
conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion ---
|
||||
|
||||
expand_to_tuple :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
|
||||
min :: proc(values: ..T) -> T ---
|
||||
max :: proc(values: ..T) -> T ---
|
||||
abs :: proc(value: T) -> T ---
|
||||
clamp :: proc(value, minimum, maximum: T) -> T ---
|
||||
@@ -31,3 +31,5 @@ ssize_t :: b.int;
|
||||
ptrdiff_t :: b.int;
|
||||
uintptr_t :: b.uintptr;
|
||||
intptr_t :: b.int;
|
||||
|
||||
wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32;
|
||||
|
||||
@@ -19,6 +19,6 @@ unload_library :: proc(library: Library) -> bool {
|
||||
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||
c_str := strings.clone_to_cstring(symbol, context.temp_allocator);
|
||||
ptr = win32.get_proc_address(cast(win32.Hmodule)library, c_str);
|
||||
found == ptr != nil;
|
||||
found = ptr != nil;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package base64
|
||||
|
||||
// @note(zh): Encoding utility for Base64
|
||||
// A secondary param can be used to supply a custom alphabet to
|
||||
// @link(encode) and a matching decoding table to @link(decode).
|
||||
// If none is supplied it just uses the standard Base64 alphabet.
|
||||
// Incase your specific version does not use padding, you may
|
||||
// truncate it from the encoded output.
|
||||
|
||||
ENC_TABLE := [64]byte {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
PADDING :: '=';
|
||||
|
||||
DEC_TABLE := [128]int {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, 62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
23, 24, 25, -1, -1, -1, -1, -1,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32,
|
||||
33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string #no_bounds_check {
|
||||
length := len(data);
|
||||
if length == 0 do return "";
|
||||
|
||||
out_length := ((4 * length / 3) + 3) &~ 3;
|
||||
out := make([]byte, out_length, allocator);
|
||||
|
||||
c0, c1, c2, block: int;
|
||||
|
||||
for i, d := 0, 0; i < length; i, d = i + 3, d + 4 {
|
||||
c0, c1, c2 = int(data[i]), 0, 0;
|
||||
|
||||
if i + 1 < length do c1 = int(data[i + 1]);
|
||||
if i + 2 < length do c2 = int(data[i + 2]);
|
||||
|
||||
block = (c0 << 16) | (max(c1, 0) << 8) | max(c2, 0);
|
||||
|
||||
out[d] = ENC_TBL[block >> 18 & 63];
|
||||
out[d + 1] = ENC_TBL[block >> 12 & 63];
|
||||
out[d + 2] = c1 == 0 ? PADDING : ENC_TBL[block >> 6 & 63];
|
||||
out[d + 3] = c2 == 0 ? PADDING : ENC_TBL[block & 63];
|
||||
}
|
||||
return string(out);
|
||||
}
|
||||
|
||||
decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{
|
||||
length := len(data);
|
||||
if length == 0 do return []byte{};
|
||||
|
||||
pad_count := data[length - 1] == PADDING ? (data[length - 2] == PADDING ? 2 : 1) : 0;
|
||||
out_length := ((length * 6) >> 3) - pad_count;
|
||||
out := make([]byte, out_length, allocator);
|
||||
|
||||
c0, c1, c2, c3: int;
|
||||
b0, b1, b2: int;
|
||||
|
||||
for i, j := 0, 0; i < length; i, j = i + 4, j + 3 {
|
||||
c0 = DEC_TBL[data[i]];
|
||||
c1 = DEC_TBL[data[i + 1]];
|
||||
c2 = DEC_TBL[data[i + 2]];
|
||||
c3 = DEC_TBL[data[i + 3]];
|
||||
|
||||
b0 = (c0 << 2) | (c1 >> 4);
|
||||
b1 = (c1 << 4) | (c2 >> 2);
|
||||
b2 = (c2 << 6) | c3;
|
||||
|
||||
out[j] = byte(b0);
|
||||
out[j + 1] = byte(b1);
|
||||
out[j + 2] = byte(b2);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
+15
-13
@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
|
||||
}
|
||||
|
||||
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
|
||||
fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
|
||||
fmt.printf_err(msg, ..args);
|
||||
fmt.println_err();
|
||||
fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
|
||||
fmt.eprintf(msg, ..args);
|
||||
fmt.eprintln();
|
||||
|
||||
p.error_count += 1;
|
||||
}
|
||||
@@ -190,7 +190,7 @@ next_token :: proc(p: ^Parser) -> Token {
|
||||
return prev;
|
||||
}
|
||||
|
||||
unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
|
||||
unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
|
||||
hex_to_int :: proc(c: byte) -> int {
|
||||
switch c {
|
||||
case '0'..'9': return int(c-'0');
|
||||
@@ -201,18 +201,19 @@ unquote_char :: proc(s: string, quote: byte) -> (r: rune, multiple_bytes: bool,
|
||||
}
|
||||
w: int;
|
||||
|
||||
if s[0] == quote && quote == '"' {
|
||||
if str[0] == quote && quote == '"' {
|
||||
return;
|
||||
} else if s[0] >= 0x80 {
|
||||
r, w = utf8.decode_rune_in_string(s);
|
||||
return r, true, s[w:], true;
|
||||
} else if s[0] != '\\' {
|
||||
return rune(s[0]), false, s[1:], true;
|
||||
} else if str[0] >= 0x80 {
|
||||
r, w = utf8.decode_rune_in_string(str);
|
||||
return r, true, str[w:], true;
|
||||
} else if str[0] != '\\' {
|
||||
return rune(str[0]), false, str[1:], true;
|
||||
}
|
||||
|
||||
if len(s) <= 1 {
|
||||
if len(str) <= 1 {
|
||||
return;
|
||||
}
|
||||
s := str;
|
||||
c := s[1];
|
||||
s = s[2:];
|
||||
|
||||
@@ -502,7 +503,7 @@ parse_operand :: proc(p: ^Parser) -> (Value, Pos) {
|
||||
|
||||
parse_atom_expr :: proc(p: ^Parser, operand: Value, pos: Pos) -> (Value, Pos) {
|
||||
loop := true;
|
||||
for loop {
|
||||
for operand := operand; loop; {
|
||||
switch p.curr_token.kind {
|
||||
case Kind.Period:
|
||||
next_token(p);
|
||||
@@ -664,8 +665,9 @@ match_values :: proc(left, right: ^Value) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
calculate_binary_value :: proc(p: ^Parser, op: Kind, x, y: Value) -> (Value, bool) {
|
||||
calculate_binary_value :: proc(p: ^Parser, op: Kind, a, b: Value) -> (Value, bool) {
|
||||
// TODO(bill): Calculate value as you go!
|
||||
x, y := a, b;
|
||||
match_values(&x, &y);
|
||||
|
||||
|
||||
|
||||
@@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
|
||||
}
|
||||
|
||||
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
|
||||
fmt.printf_err("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
|
||||
fmt.printf_err(msg, ..args);
|
||||
fmt.println_err();
|
||||
fmt.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
|
||||
fmt.eprintf(msg, ..args);
|
||||
fmt.eprintln();
|
||||
t.error_count += 1;
|
||||
}
|
||||
|
||||
@@ -286,9 +286,10 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
||||
advance_to_next_rune(t);
|
||||
}
|
||||
}
|
||||
scan_exponent :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (Kind, string) {
|
||||
scan_exponent :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (kind: Kind, text: string) {
|
||||
kind = tok;
|
||||
if t.curr_rune == 'e' || t.curr_rune == 'E' {
|
||||
tok = Float;
|
||||
kind = Float;
|
||||
advance_to_next_rune(t);
|
||||
if t.curr_rune == '-' || t.curr_rune == '+' {
|
||||
advance_to_next_rune(t);
|
||||
@@ -299,16 +300,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
||||
token_error(t, "Illegal floating point exponent");
|
||||
}
|
||||
}
|
||||
return tok, string(t.src[offset : t.offset]);
|
||||
text = string(t.src[offset : t.offset]);
|
||||
return;
|
||||
}
|
||||
scan_fraction :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (Kind, string) {
|
||||
scan_fraction :: proc(t: ^Tokenizer, tok: Kind, offset: int) -> (kind: Kind, text: string) {
|
||||
kind = tok;
|
||||
if t.curr_rune == '.' {
|
||||
tok = Float;
|
||||
kind = Float;
|
||||
advance_to_next_rune(t);
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
|
||||
return scan_exponent(t, tok, offset);
|
||||
return scan_exponent(t, kind, offset);
|
||||
}
|
||||
|
||||
offset := t.offset;
|
||||
|
||||
@@ -5,7 +5,7 @@ import "core:math/bits"
|
||||
import "core:runtime"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:types"
|
||||
import "core:reflect"
|
||||
|
||||
Marshal_Error :: enum {
|
||||
None,
|
||||
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||
header := cast(^Map_Entry_Header)data;
|
||||
|
||||
if types.is_string(info.key) {
|
||||
if reflect.is_string(info.key) {
|
||||
marshal_arg(b, header.key.str);
|
||||
} else {
|
||||
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
|
||||
@@ -281,14 +281,13 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
||||
if ti == nil {
|
||||
return false;
|
||||
}
|
||||
ti = runtime.type_info_base(ti);
|
||||
switch info in ti.variant {
|
||||
t := runtime.type_info_base(ti);
|
||||
switch info in t.variant {
|
||||
case runtime.Type_Info_Integer:
|
||||
using runtime.Type_Info_Endianness;
|
||||
switch info.endianness {
|
||||
case Platform: return false;
|
||||
case Little: return ODIN_ENDIAN != "little";
|
||||
case Big: return ODIN_ENDIAN != "big";
|
||||
case .Platform: return false;
|
||||
case .Little: return ODIN_ENDIAN != "little";
|
||||
case .Big: return ODIN_ENDIAN != "big";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -333,7 +333,8 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) {
|
||||
|
||||
|
||||
|
||||
is_valid_number :: proc(s: string, spec: Specification) -> bool {
|
||||
is_valid_number :: proc(str: string, spec: Specification) -> bool {
|
||||
s := str;
|
||||
if s == "" {
|
||||
return false;
|
||||
}
|
||||
@@ -395,7 +396,8 @@ is_valid_number :: proc(s: string, spec: Specification) -> bool {
|
||||
return s == "";
|
||||
}
|
||||
|
||||
is_valid_string_literal :: proc(s: string, spec: Specification) -> bool {
|
||||
is_valid_string_literal :: proc(str: string, spec: Specification) -> bool {
|
||||
s := str;
|
||||
if len(s) < 2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
+201
-271
@@ -5,9 +5,9 @@ import "core:os"
|
||||
import "core:mem"
|
||||
import "core:math/bits"
|
||||
import "core:unicode/utf8"
|
||||
import "core:types"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:reflect"
|
||||
|
||||
|
||||
@private
|
||||
@@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||
|
||||
|
||||
// print* procedures return the number of bytes written
|
||||
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
|
||||
print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
|
||||
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
|
||||
println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
|
||||
printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
|
||||
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
|
||||
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
|
||||
|
||||
eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
|
||||
eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
|
||||
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
|
||||
|
||||
|
||||
@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); }
|
||||
@(deprecated="prefer eprintf") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); }
|
||||
@(deprecated="prefer eprintln") println_err :: proc(args: ..any) -> int { return eprintln(..args); }
|
||||
|
||||
|
||||
// aprint* procedures return a string that was allocated with the current context
|
||||
@@ -143,7 +149,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location)
|
||||
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
|
||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
||||
buf := strings.builder_from_slice(data[:]);
|
||||
write_type(&buf, info);
|
||||
reflect.write_type(&buf, info);
|
||||
os.write_string(fd, strings.to_string(buf));
|
||||
}
|
||||
|
||||
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
|
||||
fi.buf = buf;
|
||||
|
||||
for arg, i in args {
|
||||
is_string := arg != nil && types.is_string(type_info_of(arg.id));
|
||||
is_string := arg != nil && reflect.is_string(type_info_of(arg.id));
|
||||
if i > 0 && !is_string && !prev_string {
|
||||
strings.write_byte(buf, ' ');
|
||||
}
|
||||
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
|
||||
strings.write_rune(buf, verb);
|
||||
strings.write_byte(buf, '(');
|
||||
if arg.id != nil {
|
||||
write_typeid(buf, arg.id);
|
||||
reflect.write_typeid(buf, arg.id);
|
||||
strings.write_byte(buf, '=');
|
||||
fmt_value(fi, arg, 'v');
|
||||
} else {
|
||||
@@ -783,7 +789,8 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
|
||||
}
|
||||
}
|
||||
|
||||
enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
enum_value_to_string :: proc(val: any) -> (string, bool) {
|
||||
v := val;
|
||||
v.id = runtime.typeid_base(v.id);
|
||||
type_info := type_info_of(v.id);
|
||||
|
||||
@@ -791,7 +798,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
case: return "", false;
|
||||
case runtime.Type_Info_Enum:
|
||||
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
|
||||
if types.is_string(e.base) {
|
||||
if reflect.is_string(e.base) {
|
||||
for val, idx in e.values {
|
||||
if v, ok := val.(T); ok && v == i {
|
||||
return e.names[idx], true;
|
||||
@@ -890,8 +897,8 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
||||
if ti == nil {
|
||||
return false;
|
||||
}
|
||||
ti = runtime.type_info_base(ti);
|
||||
switch info in ti.variant {
|
||||
t := runtime.type_info_base(ti);
|
||||
switch info in t.variant {
|
||||
case runtime.Type_Info_Integer:
|
||||
switch info.endianness {
|
||||
case .Platform: return false;
|
||||
@@ -946,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
||||
if name != "" {
|
||||
strings.write_string(fi.buf, name);
|
||||
} else {
|
||||
write_type(fi.buf, type_info);
|
||||
reflect.write_type(fi.buf, type_info);
|
||||
}
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
@@ -1041,7 +1048,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
|
||||
if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
|
||||
elem := rt.type_info_base(ot.elem);
|
||||
if elem == nil do return;
|
||||
write_type(fi.buf, type_info);
|
||||
reflect.write_type(fi.buf, type_info);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
|
||||
@@ -1052,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
|
||||
// Okay
|
||||
}
|
||||
} else {
|
||||
write_type(fi.buf, type_info);
|
||||
reflect.write_type(fi.buf, type_info);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
strings.write_byte(fi.buf, '}');
|
||||
}
|
||||
@@ -1078,8 +1085,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
strings.write_string(fi.buf, "{}");
|
||||
return;
|
||||
};
|
||||
|
||||
is_soa := b.soa_base_type != nil;
|
||||
|
||||
strings.write_string(fi.buf, info.name);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
strings.write_byte(fi.buf, is_soa ? '[' : '{');
|
||||
|
||||
hash := fi.hash; defer fi.hash = hash;
|
||||
indent := fi.indent; defer fi.indent -= 1;
|
||||
@@ -1088,30 +1098,73 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
fi.indent += 1;
|
||||
|
||||
if hash do strings.write_byte(fi.buf, '\n');
|
||||
|
||||
field_count := -1;
|
||||
for name, i in b.names {
|
||||
// if len(name) > 0 && name[0] == '_' do continue;
|
||||
field_count += 1;
|
||||
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
|
||||
|
||||
strings.write_string(fi.buf, name);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
if t := b.types[i]; types.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := rawptr(uintptr(v.data) + b.offsets[i]);
|
||||
fmt_arg(fi, any{data, t.id}, 'v');
|
||||
}
|
||||
|
||||
if hash do strings.write_string(fi.buf, ",\n");
|
||||
defer {
|
||||
if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t');
|
||||
strings.write_byte(fi.buf, is_soa ? ']' : '}');
|
||||
}
|
||||
|
||||
if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t');
|
||||
strings.write_byte(fi.buf, '}');
|
||||
if is_soa {
|
||||
fi.indent += 1;
|
||||
defer fi.indent -= 1;
|
||||
|
||||
base_type_name: string;
|
||||
if v, ok := b.soa_base_type.variant.(runtime.Type_Info_Named); ok {
|
||||
base_type_name = v.name;
|
||||
}
|
||||
|
||||
for index in 0..<uintptr(b.soa_len) {
|
||||
if !hash && index > 0 do strings.write_string(fi.buf, ", ");
|
||||
|
||||
field_count := -1;
|
||||
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
|
||||
strings.write_string(fi.buf, base_type_name);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
|
||||
for name, i in b.names {
|
||||
field_count += 1;
|
||||
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
|
||||
|
||||
strings.write_string(fi.buf, name);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
t := b.types[i].variant.(runtime.Type_Info_Array).elem;
|
||||
t_size := uintptr(t.size);
|
||||
if reflect.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := rawptr(uintptr(v.data) + b.offsets[i] + index*t_size);
|
||||
fmt_arg(fi, any{data, t.id}, 'v');
|
||||
}
|
||||
|
||||
if hash do strings.write_string(fi.buf, ",\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field_count := -1;
|
||||
for name, i in b.names {
|
||||
field_count += 1;
|
||||
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
|
||||
|
||||
strings.write_string(fi.buf, name);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
if t := b.types[i]; reflect.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := rawptr(uintptr(v.data) + b.offsets[i]);
|
||||
fmt_arg(fi, any{data, t.id}, 'v');
|
||||
}
|
||||
|
||||
if hash do strings.write_string(fi.buf, ",\n");
|
||||
}
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
fmt_bit_set(fi, v);
|
||||
@@ -1128,11 +1181,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Float: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_String: fmt_arg(fi, v, verb);
|
||||
|
||||
case runtime.Type_Info_Pointer:
|
||||
if v.id == typeid_of(^runtime.Type_Info) {
|
||||
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
|
||||
reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
|
||||
} else {
|
||||
ptr := (^rawptr)(v.data)^;
|
||||
if verb != 'p' && info.elem != nil {
|
||||
@@ -1255,7 +1309,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||
header := cast(^runtime.Map_Entry_Header)data;
|
||||
|
||||
if types.is_string(info.key) {
|
||||
if reflect.is_string(info.key) {
|
||||
strings.write_string(fi.buf, header.key.str);
|
||||
} else {
|
||||
fi := Info{buf = fi.buf};
|
||||
@@ -1275,8 +1329,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
return;
|
||||
}
|
||||
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
is_soa := info.soa_base_type != nil;
|
||||
|
||||
strings.write_byte(fi.buf, is_soa ? '[' : '{');
|
||||
defer strings.write_byte(fi.buf, is_soa ? ']' : '}');
|
||||
|
||||
fi.indent += 1; defer fi.indent -= 1;
|
||||
hash := fi.hash; defer fi.hash = hash;
|
||||
@@ -1285,27 +1341,76 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
|
||||
if hash do strings.write_byte(fi.buf, '\n');
|
||||
|
||||
for _, i in info.names {
|
||||
if !hash && i > 0 do strings.write_string(fi.buf, ", ");
|
||||
if hash {
|
||||
for in 0..<fi.indent {
|
||||
strings.write_byte(fi.buf, '\t');
|
||||
if is_soa {
|
||||
fi.indent += 1;
|
||||
defer fi.indent -= 1;
|
||||
|
||||
base_type_name: string;
|
||||
if v, ok := info.soa_base_type.variant.(runtime.Type_Info_Named); ok {
|
||||
base_type_name = v.name;
|
||||
}
|
||||
|
||||
for index in 0..<uintptr(info.soa_len) {
|
||||
if !hash && index > 0 do strings.write_string(fi.buf, ", ");
|
||||
|
||||
field_count := -1;
|
||||
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
|
||||
strings.write_string(fi.buf, base_type_name);
|
||||
strings.write_byte(fi.buf, '{');
|
||||
defer strings.write_byte(fi.buf, '}');
|
||||
|
||||
for name, i in info.names {
|
||||
field_count += 1;
|
||||
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
|
||||
|
||||
strings.write_string(fi.buf, name);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
t := info.types[i].variant.(runtime.Type_Info_Array).elem;
|
||||
t_size := uintptr(t.size);
|
||||
if reflect.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := rawptr(uintptr(v.data) + info.offsets[i] + index*t_size);
|
||||
fmt_arg(fi, any{data, t.id}, 'v');
|
||||
}
|
||||
|
||||
if hash do strings.write_string(fi.buf, ",\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field_count := -1;
|
||||
for name, i in info.names {
|
||||
field_count += 1;
|
||||
|
||||
strings.write_string(fi.buf, info.names[i]);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
|
||||
if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
|
||||
|
||||
if t := info.types[i]; types.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := uintptr(v.data) + info.offsets[i];
|
||||
fmt_arg(fi, any{rawptr(data), t.id}, 'v');
|
||||
strings.write_string(fi.buf, name);
|
||||
strings.write_string(fi.buf, " = ");
|
||||
|
||||
if t := info.types[i]; reflect.is_any(t) {
|
||||
strings.write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := rawptr(uintptr(v.data) + info.offsets[i]);
|
||||
fmt_arg(fi, any{data, t.id}, 'v');
|
||||
}
|
||||
|
||||
if hash do strings.write_string(fi.buf, ",\n");
|
||||
}
|
||||
if hash do strings.write_string(fi.buf, ",\n");
|
||||
}
|
||||
|
||||
|
||||
case runtime.Type_Info_Union:
|
||||
if type_info.size == 0 {
|
||||
strings.write_string(fi.buf, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
tag_ptr := uintptr(v.data) + info.tag_offset;
|
||||
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||
|
||||
@@ -1321,8 +1426,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
case i64: tag = i64(i);
|
||||
case: panic("Invalid union tag type");
|
||||
}
|
||||
assert(tag >= 0);
|
||||
|
||||
if v.data == nil || tag == 0 {
|
||||
if v.data == nil {
|
||||
strings.write_string(fi.buf, "nil");
|
||||
} else if info.no_nil {
|
||||
id := info.variants[tag].id;
|
||||
fmt_arg(fi, any{v.data, id}, verb);
|
||||
} else if tag == 0 {
|
||||
strings.write_string(fi.buf, "nil");
|
||||
} else {
|
||||
id := info.variants[tag-1].id;
|
||||
@@ -1337,14 +1448,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
||||
if ptr == nil {
|
||||
strings.write_string(fi.buf, "nil");
|
||||
} else {
|
||||
write_typeid(fi.buf, v.id);
|
||||
reflect.write_typeid(fi.buf, v.id);
|
||||
strings.write_string(fi.buf, " @ ");
|
||||
fmt_pointer(fi, ptr, 'p');
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Type_Id:
|
||||
id := (^typeid)(v.data)^;
|
||||
write_typeid(fi.buf, id);
|
||||
reflect.write_typeid(fi.buf, id);
|
||||
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
fmt_bit_field(fi, v);
|
||||
@@ -1374,6 +1485,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
|
||||
}
|
||||
}
|
||||
|
||||
fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) {
|
||||
switch verb {
|
||||
case 'f', 'F', 'v', 'h', 'H':
|
||||
r, i, j, k := real(q), imag(q), jmag(q), kmag(q);
|
||||
|
||||
fmt_float(fi, r, bits/4, verb);
|
||||
|
||||
if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+');
|
||||
fmt_float(fi, i, bits/4, verb);
|
||||
strings.write_rune(fi.buf, 'i');
|
||||
|
||||
if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+');
|
||||
fmt_float(fi, j, bits/4, verb);
|
||||
strings.write_rune(fi.buf, 'j');
|
||||
|
||||
if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+');
|
||||
fmt_float(fi, k, bits/4, verb);
|
||||
strings.write_rune(fi.buf, 'k');
|
||||
|
||||
case:
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
if arg == nil {
|
||||
strings.write_string(fi.buf, "<nil>");
|
||||
@@ -1386,7 +1522,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
switch a in arg {
|
||||
case ^runtime.Type_Info: ti = a;
|
||||
}
|
||||
write_type(fi.buf, ti);
|
||||
reflect.write_type(fi.buf, ti);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1422,6 +1558,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
|
||||
case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
|
||||
case quaternion256: fmt_quaternion(fi, a, 256, verb);
|
||||
|
||||
case i8: fmt_int(fi, u64(a), true, 8, verb);
|
||||
case u8: fmt_int(fi, u64(a), false, 8, verb);
|
||||
case i16: fmt_int(fi, u64(a), true, 16, verb);
|
||||
@@ -1437,7 +1576,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
case string: fmt_string(fi, a, verb);
|
||||
case cstring: fmt_cstring(fi, a, verb);
|
||||
|
||||
case typeid: write_typeid(fi.buf, a);
|
||||
case typeid: reflect.write_typeid(fi.buf, a);
|
||||
|
||||
case i16le: fmt_int(fi, u64(a), true, 16, verb);
|
||||
case u16le: fmt_int(fi, u64(a), false, 16, verb);
|
||||
@@ -1470,212 +1609,3 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||
|
||||
|
||||
|
||||
|
||||
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
|
||||
write_type(buf, type_info_of(id));
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
|
||||
using strings;
|
||||
if ti == nil {
|
||||
write_string(buf, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
write_string(buf, info.name);
|
||||
case runtime.Type_Info_Integer:
|
||||
switch ti.id {
|
||||
case int: write_string(buf, "int");
|
||||
case uint: write_string(buf, "uint");
|
||||
case uintptr: write_string(buf, "uintptr");
|
||||
case:
|
||||
write_byte(buf, info.signed ? 'i' : 'u');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
switch info.endianness {
|
||||
case runtime.Type_Info_Endianness.Little:
|
||||
write_string(buf, "le");
|
||||
case runtime.Type_Info_Endianness.Big:
|
||||
write_string(buf, "be");
|
||||
}
|
||||
}
|
||||
case runtime.Type_Info_Rune:
|
||||
write_string(buf, "rune");
|
||||
case runtime.Type_Info_Float:
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case runtime.Type_Info_Complex:
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case runtime.Type_Info_String:
|
||||
if info.is_cstring {
|
||||
write_string(buf, "cstring");
|
||||
} else {
|
||||
write_string(buf, "string");
|
||||
}
|
||||
case runtime.Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: write_string(buf, "bool");
|
||||
case:
|
||||
write_byte(buf, 'b');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case runtime.Type_Info_Any:
|
||||
write_string(buf, "any");
|
||||
|
||||
case runtime.Type_Info_Type_Id:
|
||||
write_string(buf, "typeid");
|
||||
|
||||
case runtime.Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
write_string(buf, "rawptr");
|
||||
} else {
|
||||
write_string(buf, "^");
|
||||
write_type(buf, info.elem);
|
||||
}
|
||||
case runtime.Type_Info_Procedure:
|
||||
write_string(buf, "proc");
|
||||
if info.params == nil {
|
||||
write_string(buf, "()");
|
||||
} else {
|
||||
t := info.params.variant.(runtime.Type_Info_Tuple);
|
||||
write_string(buf, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, t);
|
||||
}
|
||||
write_string(buf, ")");
|
||||
}
|
||||
if info.results != nil {
|
||||
write_string(buf, " -> ");
|
||||
write_type(buf, info.results);
|
||||
}
|
||||
case runtime.Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
if count != 1 do write_string(buf, "(");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
|
||||
t := info.types[i];
|
||||
|
||||
if len(name) > 0 {
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
}
|
||||
write_type(buf, t);
|
||||
}
|
||||
if count != 1 do write_string(buf, ")");
|
||||
|
||||
case runtime.Type_Info_Array:
|
||||
write_string(buf, "[");
|
||||
write_i64(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
write_string(buf, "[dynamic]");
|
||||
write_type(buf, info.elem);
|
||||
case runtime.Type_Info_Slice:
|
||||
write_string(buf, "[]");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case runtime.Type_Info_Map:
|
||||
write_string(buf, "map[");
|
||||
write_type(buf, info.key);
|
||||
write_byte(buf, ']');
|
||||
write_type(buf, info.value);
|
||||
|
||||
case runtime.Type_Info_Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.is_packed do write_string(buf, "#packed ");
|
||||
if info.is_raw_union do write_string(buf, "#raw_union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, info.types[i]);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Union:
|
||||
write_string(buf, "union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for variant, i in info.variants {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, variant);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Enum:
|
||||
write_string(buf, "enum ");
|
||||
write_type(buf, info.base);
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
write_string(buf, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
write_string(buf, "bit_set[");
|
||||
switch {
|
||||
case types.is_enum(info.elem):
|
||||
write_type(buf, info.elem);
|
||||
case types.is_rune(info.elem):
|
||||
write_encoded_rune(buf, rune(info.lower));
|
||||
write_string(buf, "..");
|
||||
write_encoded_rune(buf, rune(info.upper));
|
||||
case:
|
||||
write_i64(buf, info.lower, 10);
|
||||
write_string(buf, "..");
|
||||
write_i64(buf, info.upper, 10);
|
||||
}
|
||||
if info.underlying != nil {
|
||||
write_string(buf, "; ");
|
||||
write_type(buf, info.underlying);
|
||||
}
|
||||
write_byte(buf, ']');
|
||||
|
||||
case runtime.Type_Info_Opaque:
|
||||
write_string(buf, "opaque ");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case runtime.Type_Info_Simd_Vector:
|
||||
if info.is_x86_mmx {
|
||||
write_string(buf, "intrinsics.x86_mmx");
|
||||
} else {
|
||||
write_string(buf, "intrinsics.vector(");
|
||||
write_i64(buf, i64(info.count));
|
||||
write_string(buf, ", ");
|
||||
write_type(buf, info.elem);
|
||||
write_byte(buf, ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// This is purely for documentation
|
||||
package intrinsics
|
||||
|
||||
|
||||
vector :: proc() ---
|
||||
|
||||
atomic_fence :: proc() ---
|
||||
atomic_fence_acq :: proc() ---
|
||||
atomic_fence_rel :: proc() ---
|
||||
atomic_fence_acqrel :: proc() ---
|
||||
|
||||
atomic_store :: proc(dst: ^$T, val: $T) ---
|
||||
atomic_store_rel :: proc(dst: ^$T, val: $T) ---
|
||||
atomic_store_relaxed :: proc(dst: ^$T, val: $T) ---
|
||||
atomic_store_unordered :: proc(dst: ^$T, val: $T) ---
|
||||
|
||||
atomic_load :: proc(dst: ^$T) -> T ---
|
||||
atomic_load_acq :: proc(dst: ^$T) -> 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_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_add_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_sub_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_and_acqrel :: proc(dst; ^$T, val: $T) -> 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_xchg_acq :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_rel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_acqrel :: proc(dst; ^$T, val: $T) -> T ---
|
||||
atomic_xchg_relaxed :: proc(dst; ^$T, val: $T) -> T ---
|
||||
|
||||
atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
|
||||
atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) ---
|
||||
|
||||
|
||||
// Constant type tests
|
||||
|
||||
type_base_type :: proc($T: typeid) -> type ---
|
||||
type_core_type :: proc($T: typeid) -> type ---
|
||||
type_elem_type :: proc($T: typeid) -> type ---
|
||||
|
||||
type_is_boolean :: proc($T: typeid) -> bool ---
|
||||
type_is_integer :: proc($T: typeid) -> bool ---
|
||||
type_is_rune :: proc($T: typeid) -> bool ---
|
||||
type_is_float :: proc($T: typeid) -> bool ---
|
||||
type_is_complex :: proc($T: typeid) -> bool ---
|
||||
type_is_quaternion :: proc($T: typeid) -> bool ---
|
||||
type_is_string :: proc($T: typeid) -> bool ---
|
||||
type_is_typeid :: proc($T: typeid) -> bool ---
|
||||
type_is_any :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_endian_little :: proc($T: typeid) -> bool ---
|
||||
type_is_endian_big :: proc($T: typeid) -> bool ---
|
||||
type_is_unsigned :: proc($T: typeid) -> bool ---
|
||||
type_is_numeric :: proc($T: typeid) -> bool ---
|
||||
type_is_ordered :: proc($T: typeid) -> bool ---
|
||||
type_is_ordered_numeric :: proc($T: typeid) -> bool ---
|
||||
type_is_indexable :: proc($T: typeid) -> bool ---
|
||||
type_is_sliceable :: proc($T: typeid) -> bool ---
|
||||
type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using memcmp
|
||||
type_is_dereferenceable :: proc($T: typeid) -> bool ---
|
||||
type_is_valid_map_key :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_named :: proc($T: typeid) -> bool ---
|
||||
type_is_pointer :: proc($T: typeid) -> bool ---
|
||||
type_is_opaque :: proc($T: typeid) -> bool ---
|
||||
type_is_array :: proc($T: typeid) -> bool ---
|
||||
type_is_slice :: proc($T: typeid) -> bool ---
|
||||
type_is_dynamic_array :: proc($T: typeid) -> bool ---
|
||||
type_is_map :: proc($T: typeid) -> bool ---
|
||||
type_is_struct :: proc($T: typeid) -> bool ---
|
||||
type_is_union :: proc($T: typeid) -> bool ---
|
||||
type_is_enum :: proc($T: typeid) -> bool ---
|
||||
type_is_proc :: proc($T: typeid) -> bool ---
|
||||
type_is_bit_field :: proc($T: typeid) -> bool ---
|
||||
type_is_bit_field_value :: proc($T: typeid) -> bool ---
|
||||
type_is_bit_set :: proc($T: typeid) -> bool ---
|
||||
type_is_simd_vector :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_has_nil :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) ---
|
||||
type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) ---
|
||||
@@ -14,18 +14,18 @@ Level_Headers := []string{
|
||||
};
|
||||
|
||||
Default_Console_Logger_Opts :: Options{
|
||||
Option.Level,
|
||||
Option.Terminal_Color,
|
||||
Option.Short_File_Path,
|
||||
Option.Line,
|
||||
Option.Procedure,
|
||||
.Level,
|
||||
.Terminal_Color,
|
||||
.Short_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
} | Full_Timestamp_Opts;
|
||||
|
||||
Default_File_Logger_Opts :: Options{
|
||||
Option.Level,
|
||||
Option.Short_File_Path,
|
||||
Option.Line,
|
||||
Option.Procedure,
|
||||
.Level,
|
||||
.Short_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
} | Full_Timestamp_Opts;
|
||||
|
||||
|
||||
@@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
|
||||
case Level.Error, Level.Fatal : col = RED;
|
||||
}
|
||||
|
||||
if Option.Level in opts {
|
||||
if Option.Terminal_Color in opts do fmt.sbprint(str, col);
|
||||
if .Level in opts {
|
||||
if .Terminal_Color in opts do fmt.sbprint(str, col);
|
||||
fmt.sbprint(str, Level_Headers[level]);
|
||||
if Option.Terminal_Color in opts do fmt.sbprint(str, RESET);
|
||||
if .Terminal_Color in opts do fmt.sbprint(str, RESET);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
|
||||
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
|
||||
|
||||
file := location.file_path;
|
||||
if Option.Short_File_Path in opts {
|
||||
if .Short_File_Path in opts {
|
||||
when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
|
||||
last := 0;
|
||||
for r, i in location.file_path do if r == delimiter do last = i+1;
|
||||
@@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
|
||||
|
||||
if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
|
||||
|
||||
if Option.Procedure in opts {
|
||||
if .Procedure in opts {
|
||||
if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
|
||||
fmt.sbprintf(buf, "%s()", location.procedure);
|
||||
}
|
||||
|
||||
if Option.Line in opts {
|
||||
if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":");
|
||||
if .Line in opts {
|
||||
if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
|
||||
fmt.sbprint(buf, location.line);
|
||||
}
|
||||
|
||||
|
||||
+36
-31
@@ -11,30 +11,30 @@ Level :: enum {
|
||||
}
|
||||
|
||||
Option :: enum {
|
||||
Level,
|
||||
Date,
|
||||
Time,
|
||||
Short_File_Path,
|
||||
Long_File_Path,
|
||||
Line,
|
||||
Procedure,
|
||||
Terminal_Color
|
||||
Level,
|
||||
Date,
|
||||
Time,
|
||||
Short_File_Path,
|
||||
Long_File_Path,
|
||||
Line,
|
||||
Procedure,
|
||||
Terminal_Color
|
||||
}
|
||||
|
||||
Options :: bit_set[Option];
|
||||
Full_Timestamp_Opts :: Options{
|
||||
Option.Date,
|
||||
Option.Time
|
||||
.Date,
|
||||
.Time
|
||||
};
|
||||
Location_Header_Opts :: Options{
|
||||
Option.Short_File_Path,
|
||||
Option.Long_File_Path,
|
||||
Option.Line,
|
||||
Option.Procedure,
|
||||
.Short_File_Path,
|
||||
.Long_File_Path,
|
||||
.Line,
|
||||
.Procedure,
|
||||
};
|
||||
Location_File_Opts :: Options{
|
||||
Option.Short_File_Path,
|
||||
Option.Long_File_Path
|
||||
.Short_File_Path,
|
||||
.Long_File_Path
|
||||
};
|
||||
|
||||
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
|
||||
@@ -42,30 +42,34 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt
|
||||
Logger :: struct {
|
||||
procedure: Logger_Proc,
|
||||
data: rawptr,
|
||||
options: Options,
|
||||
options: Options,
|
||||
}
|
||||
|
||||
Multi_Logger_Data :: struct {
|
||||
loggers : []Logger,
|
||||
loggers : []Logger,
|
||||
}
|
||||
|
||||
create_multi_logger :: proc(logs: ..Logger) -> Logger {
|
||||
data := new(Multi_Logger_Data);
|
||||
data.loggers = make([]Logger, len(logs));
|
||||
copy(data.loggers, logs);
|
||||
return Logger{multi_logger_proc, data, nil};
|
||||
data := new(Multi_Logger_Data);
|
||||
data.loggers = make([]Logger, len(logs));
|
||||
copy(data.loggers, logs);
|
||||
return Logger{multi_logger_proc, data, nil};
|
||||
}
|
||||
|
||||
destroy_multi_logger ::proc(log : ^Logger) {
|
||||
free(log.data);
|
||||
log^ = nil_logger();
|
||||
destroy_multi_logger :: proc(log : ^Logger) {
|
||||
free(log.data);
|
||||
log^ = nil_logger();
|
||||
}
|
||||
|
||||
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
||||
options: Options, location := #caller_location) {
|
||||
data := cast(^Multi_Logger_Data)logger_data;
|
||||
if data.loggers == nil || len(data.loggers) == 0 do return;
|
||||
for log in data.loggers do log.procedure(log.data, level, text, log.options, location);
|
||||
data := cast(^Multi_Logger_Data)logger_data;
|
||||
if data.loggers == nil || len(data.loggers) == 0 {
|
||||
return;
|
||||
}
|
||||
for log in data.loggers {
|
||||
log.procedure(log.data, level, text, log.options, location);
|
||||
}
|
||||
}
|
||||
|
||||
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
|
||||
@@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger {
|
||||
return Logger{nil_logger_proc, nil, nil};
|
||||
}
|
||||
|
||||
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
|
||||
debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
|
||||
info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
|
||||
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
|
||||
@@ -83,7 +88,7 @@ error :: proc(fmt_str : string, args : ..any, location := #caller_location) do l
|
||||
fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location);
|
||||
|
||||
logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
|
||||
logger := context.logger;
|
||||
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
|
||||
logger.procedure(logger.data, level, str, logger.options, location);
|
||||
logger := context.logger;
|
||||
str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
|
||||
logger.procedure(logger.data, level, str, logger.options, location);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
package linalg
|
||||
|
||||
import "core:math"
|
||||
import "intrinsics"
|
||||
|
||||
// Generic
|
||||
|
||||
dot_vector :: proc(a, b: $T/[$N]$E) -> (c: E) {
|
||||
for i in 0..<N {
|
||||
c += a[i] * b[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
dot_quaternion128 :: proc(a, b: $T/quaternion128) -> (c: f32) {
|
||||
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
|
||||
}
|
||||
dot_quaternion256 :: proc(a, b: $T/quaternion256) -> (c: f64) {
|
||||
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
|
||||
}
|
||||
|
||||
dot :: proc{dot_vector, dot_quaternion128, dot_quaternion256};
|
||||
|
||||
cross2 :: proc(a, b: $T/[2]$E) -> E {
|
||||
return a[0]*b[1] - b[0]*a[1];
|
||||
}
|
||||
|
||||
cross3 :: proc(a, b: $T/[3]$E) -> (c: T) {
|
||||
c[0] = +(a[1]*b[2] - b[1]*a[2]);
|
||||
c[1] = -(a[2]*b[0] - b[2]*a[0]);
|
||||
c[2] = +(a[0]*b[1] - b[0]*a[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
cross :: proc{cross2, cross3};
|
||||
|
||||
|
||||
normalize_vector :: proc(v: $T/[$N]$E) -> T {
|
||||
return v / length(v);
|
||||
}
|
||||
normalize_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
|
||||
return q/abs(q);
|
||||
}
|
||||
normalize_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
|
||||
return q/abs(q);
|
||||
}
|
||||
normalize :: proc{normalize_vector, normalize_quaternion128, normalize_quaternion256};
|
||||
|
||||
normalize0_vector :: proc(v: $T/[$N]$E) -> T {
|
||||
m := length(v);
|
||||
return m == 0 ? 0 : v/m;
|
||||
}
|
||||
normalize0_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
|
||||
m := abs(q);
|
||||
return m == 0 ? 0 : q/m;
|
||||
}
|
||||
normalize0_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
|
||||
m := abs(q);
|
||||
return m == 0 ? 0 : q/m;
|
||||
}
|
||||
normalize0 :: proc{normalize0_vector, normalize0_quaternion128, normalize0_quaternion256};
|
||||
|
||||
|
||||
length :: proc(v: $T/[$N]$E) -> E {
|
||||
return math.sqrt(dot(v, v));
|
||||
}
|
||||
|
||||
|
||||
identity :: proc($T: typeid/[$N][N]$E) -> (m: T) {
|
||||
for i in 0..<N do m[i][i] = E(1);
|
||||
return m;
|
||||
}
|
||||
|
||||
transpose :: proc(a: $T/[$N][$M]$E) -> (m: [M][N]E) {
|
||||
for j in 0..<M {
|
||||
for i in 0..<N {
|
||||
m[j][i] = a[i][j];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mul_matrix :: proc(a, b: $M/[$N][N]$E) -> (c: M)
|
||||
where !intrinsics.type_is_array(E),
|
||||
intrinsics.type_is_numeric(E) {
|
||||
for i in 0..<N {
|
||||
for k in 0..<N {
|
||||
for j in 0..<N {
|
||||
c[k][i] += a[j][i] * b[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mul_matrix_differ :: proc(a: $A/[$J][$I]$E, b: $B/[$K][J]E) -> (c: [K][I]E)
|
||||
where !intrinsics.type_is_array(E),
|
||||
intrinsics.type_is_numeric(E),
|
||||
I != K {
|
||||
for k in 0..<K {
|
||||
for j in 0..<J {
|
||||
for i in 0..<I {
|
||||
c[k][i] += a[j][i] * b[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
|
||||
where !intrinsics.type_is_array(E),
|
||||
intrinsics.type_is_numeric(E) {
|
||||
for i in 0..<I {
|
||||
for j in 0..<J {
|
||||
c[i] += a[i][j] * b[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mul_quaternion128_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f32, r: f32};
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f32)v;
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
}
|
||||
|
||||
mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
|
||||
Raw_Quaternion :: struct {xyz: [3]f64, r: f64};
|
||||
|
||||
q := transmute(Raw_Quaternion)q;
|
||||
v := transmute([3]f64)v;
|
||||
|
||||
t := cross(2*q.xyz, v);
|
||||
return V(v + q.r*t + cross(q.xyz, t));
|
||||
}
|
||||
mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3};
|
||||
|
||||
mul :: proc{
|
||||
mul_matrix,
|
||||
mul_matrix_differ,
|
||||
mul_matrix_vector,
|
||||
mul_quaternion128_vector3,
|
||||
mul_quaternion256_vector3,
|
||||
};
|
||||
|
||||
|
||||
// Specific
|
||||
|
||||
Float :: f32;
|
||||
|
||||
Vector2 :: distinct [2]Float;
|
||||
Vector3 :: distinct [3]Float;
|
||||
Vector4 :: distinct [4]Float;
|
||||
|
||||
Matrix1x1 :: distinct [1][1]Float;
|
||||
Matrix1x2 :: distinct [1][2]Float;
|
||||
Matrix1x3 :: distinct [1][3]Float;
|
||||
Matrix1x4 :: distinct [1][4]Float;
|
||||
|
||||
Matrix2x1 :: distinct [2][1]Float;
|
||||
Matrix2x2 :: distinct [2][2]Float;
|
||||
Matrix2x3 :: distinct [2][3]Float;
|
||||
Matrix2x4 :: distinct [2][4]Float;
|
||||
|
||||
Matrix3x1 :: distinct [3][1]Float;
|
||||
Matrix3x2 :: distinct [3][2]Float;
|
||||
Matrix3x3 :: distinct [3][3]Float;
|
||||
Matrix3x4 :: distinct [3][4]Float;
|
||||
|
||||
Matrix4x1 :: distinct [4][1]Float;
|
||||
Matrix4x2 :: distinct [4][2]Float;
|
||||
Matrix4x3 :: distinct [4][3]Float;
|
||||
Matrix4x4 :: distinct [4][4]Float;
|
||||
|
||||
|
||||
Matrix1 :: Matrix1x1;
|
||||
Matrix2 :: Matrix2x2;
|
||||
Matrix3 :: Matrix3x3;
|
||||
Matrix4 :: Matrix4x4;
|
||||
|
||||
|
||||
Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256);
|
||||
|
||||
|
||||
translate_matrix4 :: proc(v: Vector3) -> Matrix4 {
|
||||
m := identity(Matrix4);
|
||||
m[3][0] = v[0];
|
||||
m[3][1] = v[1];
|
||||
m[3][2] = v[2];
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
rotate_matrix4 :: proc(v: Vector3, angle_radians: Float) -> Matrix4 {
|
||||
c := math.cos(angle_radians);
|
||||
s := math.sin(angle_radians);
|
||||
|
||||
a := normalize(v);
|
||||
t := a * (1-c);
|
||||
|
||||
rot := identity(Matrix4);
|
||||
|
||||
rot[0][0] = c + t[0]*a[0];
|
||||
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
|
||||
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
|
||||
rot[0][3] = 0;
|
||||
|
||||
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
|
||||
rot[1][1] = c + t[1]*a[1];
|
||||
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
|
||||
rot[1][3] = 0;
|
||||
|
||||
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
|
||||
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
|
||||
rot[2][2] = c + t[2]*a[2];
|
||||
rot[2][3] = 0;
|
||||
|
||||
return rot;
|
||||
}
|
||||
|
||||
scale_matrix4 :: proc(m: Matrix4, v: Vector3) -> Matrix4 {
|
||||
mm := m;
|
||||
mm[0][0] *= v[0];
|
||||
mm[1][1] *= v[1];
|
||||
mm[2][2] *= v[2];
|
||||
return mm;
|
||||
}
|
||||
|
||||
|
||||
look_at :: proc(eye, centre, up: Vector3) -> Matrix4 {
|
||||
f := normalize(centre - eye);
|
||||
s := normalize(cross(f, up));
|
||||
u := cross(s, f);
|
||||
return Matrix4{
|
||||
{+s.x, +u.x, -f.x, 0},
|
||||
{+s.y, +u.y, -f.y, 0},
|
||||
{+s.z, +u.z, -f.z, 0},
|
||||
{-dot(s, eye), -dot(u, eye), +dot(f, eye), 1},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
perspective :: proc(fovy, aspect, near, far: Float) -> (m: Matrix4) {
|
||||
tan_half_fovy := math.tan(0.5 * fovy);
|
||||
m[0][0] = 1 / (aspect*tan_half_fovy);
|
||||
m[1][1] = 1 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
m[2][3] = -1;
|
||||
m[3][2] = -2*far*near / (far - near);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ortho3d :: proc(left, right, bottom, top, near, far: Float) -> (m: Matrix4) {
|
||||
m[0][0] = +2 / (right - left);
|
||||
m[1][1] = +2 / (top - bottom);
|
||||
m[2][2] = -2 / (far - near);
|
||||
m[3][0] = -(right + left) / (right - left);
|
||||
m[3][1] = -(top + bottom) / (top - bottom);
|
||||
m[3][2] = -(far + near) / (far- near);
|
||||
m[3][3] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
axis_angle :: proc(axis: Vector3, angle_radians: Float) -> Quaternion {
|
||||
t := angle_radians*0.5;
|
||||
w := math.cos(t);
|
||||
v := normalize(axis) * math.sin(t);
|
||||
return quaternion(w, v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion {
|
||||
t := angle_radians*0.5;
|
||||
w := math.cos(t);
|
||||
v := normalize(axis) * math.sin(t);
|
||||
return quaternion(w, v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
euler_angles :: proc(pitch, yaw, roll: Float) -> Quaternion {
|
||||
p := axis_angle({1, 0, 0}, pitch);
|
||||
y := axis_angle({0, 1, 0}, yaw);
|
||||
r := axis_angle({0, 0, 1}, roll);
|
||||
return (y * p) * r;
|
||||
}
|
||||
+390
-391
@@ -1,36 +1,41 @@
|
||||
package math
|
||||
|
||||
import "intrinsics"
|
||||
|
||||
Float_Class :: enum {
|
||||
Normal, // an ordinary nonzero floating point value
|
||||
Subnormal, // a subnormal floating point value
|
||||
Zero, // zero
|
||||
Neg_Zero, // the negative zero
|
||||
NaN, // Not-A-Number (NaN)
|
||||
Inf, // positive infinity
|
||||
Neg_Inf // negative infinity
|
||||
};
|
||||
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
|
||||
E :: 2.71828182845904523536;
|
||||
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
e :: E;
|
||||
|
||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||
|
||||
LOG_TWO :: 0.693147180559945309417232121458176568;
|
||||
LOG_TEN :: 2.30258509299404568401799145468436421;
|
||||
LN2 :: 0.693147180559945309417232121458176568;
|
||||
LN10 :: 2.30258509299404568401799145468436421;
|
||||
|
||||
EPSILON :: 1.19209290e-7;
|
||||
MAX_F64_PRECISION :: 16; // Maximum number of meaningful digits after the decimal point for 'f64'
|
||||
MAX_F32_PRECISION :: 8; // Maximum number of meaningful digits after the decimal point for 'f32'
|
||||
|
||||
τ :: TAU;
|
||||
π :: PI;
|
||||
|
||||
Vec2 :: distinct [2]f32;
|
||||
Vec3 :: distinct [3]f32;
|
||||
Vec4 :: distinct [4]f32;
|
||||
|
||||
// Column major
|
||||
Mat2 :: distinct [2][2]f32;
|
||||
Mat3 :: distinct [3][3]f32;
|
||||
Mat4 :: distinct [4][4]f32;
|
||||
|
||||
Quat :: struct {x, y, z, w: f32};
|
||||
|
||||
QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1};
|
||||
RAD_PER_DEG :: TAU/360.0;
|
||||
DEG_PER_RAD :: 360.0/TAU;
|
||||
|
||||
|
||||
@(default_calling_convention="c")
|
||||
@(default_calling_convention="none")
|
||||
foreign _ {
|
||||
@(link_name="llvm.sqrt.f32")
|
||||
sqrt_f32 :: proc(x: f32) -> f32 ---;
|
||||
@@ -58,9 +63,9 @@ foreign _ {
|
||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.log.f32")
|
||||
log_f32 :: proc(x: f32) -> f32 ---;
|
||||
ln_f32 :: proc(x: f32) -> f32 ---;
|
||||
@(link_name="llvm.log.f64")
|
||||
log_f64 :: proc(x: f64) -> f64 ---;
|
||||
ln_f64 :: proc(x: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.exp.f32")
|
||||
exp_f32 :: proc(x: f32) -> f32 ---;
|
||||
@@ -68,20 +73,40 @@ foreign _ {
|
||||
exp_f64 :: proc(x: f64) -> f64 ---;
|
||||
}
|
||||
|
||||
log :: proc{log_f32, log_f64};
|
||||
exp :: proc{exp_f32, exp_f64};
|
||||
sqrt :: proc{sqrt_f32, sqrt_f64};
|
||||
sin :: proc{sin_f32, sin_f64};
|
||||
cos :: proc{cos_f32, cos_f64};
|
||||
pow :: proc{pow_f32, pow_f64};
|
||||
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
|
||||
ln :: proc{ln_f32, ln_f64};
|
||||
exp :: proc{exp_f32, exp_f64};
|
||||
|
||||
log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
|
||||
log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
|
||||
log :: proc{log_f32, log_f64};
|
||||
|
||||
log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
|
||||
log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
|
||||
log2 :: proc{log2_f32, log2_f64};
|
||||
|
||||
log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
|
||||
log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
|
||||
log10 :: proc{log10_f32, log10_f64};
|
||||
|
||||
|
||||
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
|
||||
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
|
||||
tan :: proc{tan_f32, tan_f64};
|
||||
|
||||
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
|
||||
|
||||
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
|
||||
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
|
||||
unlerp :: proc{unlerp_f32, unlerp_f64};
|
||||
|
||||
|
||||
sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||
sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||
sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
|
||||
sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
|
||||
sign :: proc{sign_f32, sign_f64};
|
||||
|
||||
copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
||||
ix := transmute(u32)x;
|
||||
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
||||
ix |= iy & 0x8000_0000;
|
||||
return transmute(f32)ix;
|
||||
}
|
||||
|
||||
copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
||||
ix := transmute(u64)x;
|
||||
iy := transmute(u64)y;
|
||||
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
||||
ix |= iy & 0x8000_0000_0000_0000;
|
||||
return transmute(f64)ix;
|
||||
}
|
||||
|
||||
|
||||
sqrt :: proc{sqrt_f32, sqrt_f64};
|
||||
sin :: proc{sin_f32, sin_f64};
|
||||
cos :: proc{cos_f32, cos_f64};
|
||||
tan :: proc{tan_f32, tan_f64};
|
||||
pow :: proc{pow_f32, pow_f64};
|
||||
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
|
||||
sign :: proc{sign_f32, sign_f64};
|
||||
copy_sign :: proc{copy_sign_f32, copy_sign_f64};
|
||||
|
||||
|
||||
round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
||||
to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
|
||||
to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
|
||||
to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
|
||||
to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
|
||||
to_radians :: proc{to_radians_f32, to_radians_f64};
|
||||
to_degrees :: proc{to_degrees_f32, to_degrees_f64};
|
||||
|
||||
trunc_f32 :: proc(x: f32) -> f32 {
|
||||
trunc_internal :: proc(f: f32) -> f32 {
|
||||
mask :: 0xff;
|
||||
shift :: 32 - 9;
|
||||
bias :: 0x7f;
|
||||
|
||||
if f < 1 {
|
||||
switch {
|
||||
case f < 0: return -trunc_internal(-f);
|
||||
case f == 0: return f;
|
||||
case: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
x := transmute(u32)f;
|
||||
e := (x >> shift) & mask - bias;
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1;
|
||||
}
|
||||
return transmute(f32)x;
|
||||
}
|
||||
switch classify(x) {
|
||||
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
|
||||
return x;
|
||||
}
|
||||
return trunc_internal(x);
|
||||
}
|
||||
|
||||
trunc_f64 :: proc(x: f64) -> f64 {
|
||||
trunc_internal :: proc(f: f64) -> f64 {
|
||||
mask :: 0x7ff;
|
||||
shift :: 64 - 12;
|
||||
bias :: 0x3ff;
|
||||
|
||||
if f < 1 {
|
||||
switch {
|
||||
case f < 0: return -trunc_internal(-f);
|
||||
case f == 0: return f;
|
||||
case: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
x := transmute(u64)f;
|
||||
e := (x >> shift) & mask - bias;
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1;
|
||||
}
|
||||
return transmute(f64)x;
|
||||
}
|
||||
switch classify(x) {
|
||||
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
|
||||
return x;
|
||||
}
|
||||
return trunc_internal(x);
|
||||
}
|
||||
|
||||
trunc :: proc{trunc_f32, trunc_f64};
|
||||
|
||||
round_f32 :: proc(x: f32) -> f32 {
|
||||
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
|
||||
}
|
||||
round_f64 :: proc(x: f64) -> f64 {
|
||||
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
|
||||
}
|
||||
round :: proc{round_f32, round_f64};
|
||||
|
||||
|
||||
ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
|
||||
ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
|
||||
ceil :: proc{ceil_f32, ceil_f64};
|
||||
|
||||
floor_f32 :: proc(x: f32) -> f32 {
|
||||
if x == 0 || is_nan(x) || is_inf(x) {
|
||||
return x;
|
||||
@@ -144,35 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
|
||||
}
|
||||
floor :: proc{floor_f32, floor_f64};
|
||||
|
||||
ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); }
|
||||
ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); }
|
||||
ceil :: proc{ceil_f32, ceil_f64};
|
||||
|
||||
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
remainder :: proc{remainder_f32, remainder_f64};
|
||||
|
||||
mod_f32 :: proc(x, y: f32) -> f32 {
|
||||
result: f32;
|
||||
y = abs(y);
|
||||
result = remainder(abs(x), y);
|
||||
if sign(result) < 0 {
|
||||
result += y;
|
||||
floor_div :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_integer(T) {
|
||||
a := x / y;
|
||||
r := x % y;
|
||||
if (r > 0 && y < 0) || (r < 0 && y > 0) {
|
||||
a -= 1;
|
||||
}
|
||||
return copy_sign(result, x);
|
||||
return a;
|
||||
}
|
||||
mod_f64 :: proc(x, y: f64) -> f64 {
|
||||
result: f64;
|
||||
y = abs(y);
|
||||
result = remainder(abs(x), y);
|
||||
if sign(result) < 0 {
|
||||
result += y;
|
||||
}
|
||||
return copy_sign(result, x);
|
||||
}
|
||||
mod :: proc{mod_f32, mod_f64};
|
||||
|
||||
// TODO(bill): These need to implemented with the actual instructions
|
||||
floor_mod :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_integer(T) {
|
||||
r := x % y;
|
||||
if (r > 0 && y < 0) || (r < 0 && y > 0) {
|
||||
r += y;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
||||
shift :: 32 - 8 - 1;
|
||||
mask :: 0xff;
|
||||
@@ -192,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
||||
i := transmute(u32)x;
|
||||
e := uint(i>>shift)&mask - bias;
|
||||
|
||||
if e < 32-9 {
|
||||
i &~= 1<<(32-9-e) - 1;
|
||||
if e < shift {
|
||||
i &~= 1<<(shift-e) - 1;
|
||||
}
|
||||
int = transmute(f32)i;
|
||||
frac = x - int;
|
||||
@@ -218,358 +301,274 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
|
||||
i := transmute(u64)x;
|
||||
e := uint(i>>shift)&mask - bias;
|
||||
|
||||
if e < 64-12 {
|
||||
i &~= 1<<(64-12-e) - 1;
|
||||
if e < shift {
|
||||
i &~= 1<<(shift-e) - 1;
|
||||
}
|
||||
int = transmute(f64)i;
|
||||
frac = x - int;
|
||||
return;
|
||||
}
|
||||
modf :: proc{modf_f32, modf_f64};
|
||||
split_decimal :: modf;
|
||||
|
||||
is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; }
|
||||
is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; }
|
||||
mod_f32 :: proc(x, y: f32) -> (n: f32) {
|
||||
z := abs(y);
|
||||
n = remainder(abs(x), z);
|
||||
if sign(n) < 0 {
|
||||
n += z;
|
||||
}
|
||||
return copy_sign(n, x);
|
||||
}
|
||||
mod_f64 :: proc(x, y: f64) -> (n: f64) {
|
||||
z := abs(y);
|
||||
n = remainder(abs(x), z);
|
||||
if sign(n) < 0 {
|
||||
n += z;
|
||||
}
|
||||
return copy_sign(n, x);
|
||||
}
|
||||
mod :: proc{mod_f32, mod_f64};
|
||||
|
||||
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
|
||||
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
||||
remainder :: proc{remainder_f32, remainder_f64};
|
||||
|
||||
|
||||
|
||||
gcd :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_ordered_numeric(T) {
|
||||
x, y := x, y;
|
||||
for y != 0 {
|
||||
x %= y;
|
||||
x, y = y, x;
|
||||
}
|
||||
return abs(x);
|
||||
}
|
||||
|
||||
lcm :: proc(x, y: $T) -> T
|
||||
where intrinsics.type_is_ordered_numeric(T) {
|
||||
return x / gcd(x, y) * y;
|
||||
}
|
||||
|
||||
frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) {
|
||||
switch {
|
||||
case x == 0:
|
||||
return 0, 0;
|
||||
case x < 0:
|
||||
significand, exponent = frexp(-x);
|
||||
return -significand, exponent;
|
||||
}
|
||||
ex := trunc(log2(x));
|
||||
exponent = int(ex);
|
||||
significand = x / pow(2.0, ex);
|
||||
if abs(significand) >= 1 {
|
||||
exponent += 1;
|
||||
significand /= 2;
|
||||
}
|
||||
if exponent == 1024 && significand == 0 {
|
||||
significand = 0.99999999999999988898;
|
||||
}
|
||||
return;
|
||||
}
|
||||
frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) {
|
||||
switch {
|
||||
case x == 0:
|
||||
return 0, 0;
|
||||
case x < 0:
|
||||
significand, exponent = frexp(-x);
|
||||
return -significand, exponent;
|
||||
}
|
||||
ex := trunc(log2(x));
|
||||
exponent = int(ex);
|
||||
significand = x / pow(2.0, ex);
|
||||
if abs(significand) >= 1 {
|
||||
exponent += 1;
|
||||
significand /= 2;
|
||||
}
|
||||
if exponent == 1024 && significand == 0 {
|
||||
significand = 0.99999999999999988898;
|
||||
}
|
||||
return;
|
||||
}
|
||||
frexp :: proc{frexp_f32, frexp_f64};
|
||||
|
||||
|
||||
|
||||
|
||||
binomial :: proc(n, k: int) -> int {
|
||||
switch {
|
||||
case k <= 0: return 1;
|
||||
case 2*k > n: return binomial(n, n-k);
|
||||
}
|
||||
|
||||
b := n;
|
||||
for i in 2..<k {
|
||||
b = (b * (n+1-i))/i;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
factorial :: proc(n: int) -> int {
|
||||
when size_of(int) == size_of(i64) {
|
||||
@static table := [21]int{
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
6,
|
||||
24,
|
||||
120,
|
||||
720,
|
||||
5_040,
|
||||
40_320,
|
||||
362_880,
|
||||
3_628_800,
|
||||
39_916_800,
|
||||
479_001_600,
|
||||
6_227_020_800,
|
||||
87_178_291_200,
|
||||
1_307_674_368_000,
|
||||
20_922_789_888_000,
|
||||
355_687_428_096_000,
|
||||
6_402_373_705_728_000,
|
||||
121_645_100_408_832_000,
|
||||
2_432_902_008_176_640_000,
|
||||
};
|
||||
} else {
|
||||
@static table := [13]int{
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
6,
|
||||
24,
|
||||
120,
|
||||
720,
|
||||
5_040,
|
||||
40_320,
|
||||
362_880,
|
||||
3_628_800,
|
||||
39_916_800,
|
||||
479_001_600,
|
||||
};
|
||||
}
|
||||
|
||||
assert(n >= 0, "parameter must not be negative");
|
||||
assert(n < len(table), "parameter is too large to lookup in the table");
|
||||
return 0;
|
||||
}
|
||||
|
||||
classify_f32 :: proc(x: f32) -> Float_Class {
|
||||
switch {
|
||||
case x == 0:
|
||||
i := transmute(i32)x;
|
||||
if i < 0 {
|
||||
return .Neg_Zero;
|
||||
}
|
||||
return .Zero;
|
||||
case x*0.5 == x:
|
||||
if x < 0 {
|
||||
return .Neg_Inf;
|
||||
}
|
||||
return .Inf;
|
||||
case x != x:
|
||||
return .NaN;
|
||||
}
|
||||
|
||||
u := transmute(u32)x;
|
||||
exp := int(u>>23) & (1<<8 - 1);
|
||||
if exp == 0 {
|
||||
return .Subnormal;
|
||||
}
|
||||
return .Normal;
|
||||
}
|
||||
classify_f64 :: proc(x: f64) -> Float_Class {
|
||||
switch {
|
||||
case x == 0:
|
||||
i := transmute(i64)x;
|
||||
if i < 0 {
|
||||
return .Neg_Zero;
|
||||
}
|
||||
return .Zero;
|
||||
case x*0.5 == x:
|
||||
if x < 0 {
|
||||
return .Neg_Inf;
|
||||
}
|
||||
return .Inf;
|
||||
case x != x:
|
||||
return .NaN;
|
||||
}
|
||||
u := transmute(u64)x;
|
||||
exp := int(u>>52) & (1<<11 - 1);
|
||||
if exp == 0 {
|
||||
return .Subnormal;
|
||||
}
|
||||
return .Normal;
|
||||
}
|
||||
classify :: proc{classify_f32, classify_f64};
|
||||
|
||||
is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; }
|
||||
is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; }
|
||||
is_nan :: proc{is_nan_f32, is_nan_f64};
|
||||
|
||||
is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); }
|
||||
is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); }
|
||||
is_finite :: proc{is_finite_f32, is_finite_f64};
|
||||
|
||||
is_inf_f32 :: proc(x: f32, sign := 0) -> bool {
|
||||
return sign >= 0 && x > F32_MAX || sign <= 0 && x < -F32_MAX;
|
||||
}
|
||||
is_inf_f64 :: proc(x: f64, sign := 0) -> bool {
|
||||
return sign >= 0 && x > F64_MAX || sign <= 0 && x < -F64_MAX;
|
||||
}
|
||||
// If sign > 0, is_inf reports whether f is positive infinity
|
||||
// If sign < 0, is_inf reports whether f is negative infinity
|
||||
// If sign == 0, is_inf reports whether f is either infinity
|
||||
is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; }
|
||||
is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; }
|
||||
is_inf :: proc{is_inf_f32, is_inf_f64};
|
||||
|
||||
|
||||
|
||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||
is_power_of_two :: proc(x: int) -> bool {
|
||||
return x > 0 && (x & (x-1)) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
mul :: proc{
|
||||
mat3_mul,
|
||||
mat4_mul, mat4_mul_vec4,
|
||||
quat_mul, quat_mulf,
|
||||
};
|
||||
|
||||
div :: proc{quat_div, quat_divf};
|
||||
|
||||
inverse :: proc{mat4_inverse, quat_inverse};
|
||||
dot :: proc{vec_dot, quat_dot};
|
||||
cross :: proc{cross2, cross3};
|
||||
|
||||
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
|
||||
res: E;
|
||||
for i in 0..<N {
|
||||
res += a[i] * b[i];
|
||||
next_power_of_two :: proc(x: int) -> int {
|
||||
k := x -1;
|
||||
when size_of(int) == 8 {
|
||||
k = k | (k >> 32);
|
||||
}
|
||||
return res;
|
||||
k = k | (k >> 16);
|
||||
k = k | (k >> 8);
|
||||
k = k | (k >> 4);
|
||||
k = k | (k >> 2);
|
||||
k = k | (k >> 1);
|
||||
k += 1 + int(x <= 0);
|
||||
return k;
|
||||
}
|
||||
|
||||
cross2 :: proc(a, b: $T/[2]$E) -> E {
|
||||
return a[0]*b[1] - a[1]*b[0];
|
||||
sum :: proc(x: $T/[]$E) -> (res: E)
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
for i in x {
|
||||
res += i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cross3 :: proc(a, b: $T/[3]$E) -> T {
|
||||
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
|
||||
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
|
||||
return T(i - j);
|
||||
prod :: proc(x: $T/[]$E) -> (res: E)
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
for i in x {
|
||||
res *= i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cumsum_inplace :: proc(x: $T/[]$E) -> T
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
for i in 1..<len(x) {
|
||||
x[i] = x[i-1] + x[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }
|
||||
|
||||
norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); }
|
||||
|
||||
norm0 :: proc(v: $T/[$N]$E) -> T {
|
||||
m := length(v);
|
||||
return m == 0 ? 0 : v/m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
identity :: proc($T: typeid/[$N][N]$E) -> T {
|
||||
m: T;
|
||||
for i in 0..<N do m[i][i] = E(1);
|
||||
return m;
|
||||
}
|
||||
|
||||
transpose :: proc(m: $M/[$N][N]f32) -> M {
|
||||
for j in 0..<N {
|
||||
for i in 0..<N {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
cumsum :: proc(dst, src: $T/[]$E) -> T
|
||||
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||
N := min(len(dst), len(src));
|
||||
if N > 0 {
|
||||
dst[0] = src[0];
|
||||
for i in 1..<N {
|
||||
dst[i] = dst[i-1] + src[i];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
return dst[:N];
|
||||
}
|
||||
|
||||
mat3_mul :: proc(a, b: Mat3) -> Mat3 {
|
||||
c: Mat3;
|
||||
for j in 0..<3 {
|
||||
for i in 0..<3 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j in 0..<4 {
|
||||
for i in 0..<4 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2] +
|
||||
a[3][i]*b[j][3];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
return Vec4{
|
||||
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
|
||||
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
|
||||
m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3],
|
||||
m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3],
|
||||
};
|
||||
}
|
||||
|
||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4;
|
||||
|
||||
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
|
||||
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
|
||||
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
|
||||
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
|
||||
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
|
||||
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
|
||||
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
|
||||
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
|
||||
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
|
||||
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
|
||||
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
|
||||
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
|
||||
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
|
||||
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
|
||||
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
|
||||
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
|
||||
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
|
||||
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
|
||||
|
||||
|
||||
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
|
||||
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
|
||||
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
|
||||
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
|
||||
|
||||
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
|
||||
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
|
||||
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
|
||||
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
|
||||
|
||||
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
|
||||
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
|
||||
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
|
||||
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
|
||||
|
||||
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
|
||||
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
|
||||
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
|
||||
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
|
||||
|
||||
ood := 1.0 / (m[0][0] * o[0][0] +
|
||||
m[0][1] * o[0][1] +
|
||||
m[0][2] * o[0][2] +
|
||||
m[0][3] * o[0][3]);
|
||||
|
||||
o[0][0] *= ood;
|
||||
o[0][1] *= ood;
|
||||
o[0][2] *= ood;
|
||||
o[0][3] *= ood;
|
||||
o[1][0] *= ood;
|
||||
o[1][1] *= ood;
|
||||
o[1][2] *= ood;
|
||||
o[1][3] *= ood;
|
||||
o[2][0] *= ood;
|
||||
o[2][1] *= ood;
|
||||
o[2][2] *= ood;
|
||||
o[2][3] *= ood;
|
||||
o[3][0] *= ood;
|
||||
o[3][1] *= ood;
|
||||
o[3][2] *= ood;
|
||||
o[3][3] *= ood;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
mat4_translate :: proc(v: Vec3) -> Mat4 {
|
||||
m := identity(Mat4);
|
||||
m[3][0] = v[0];
|
||||
m[3][1] = v[1];
|
||||
m[3][2] = v[2];
|
||||
m[3][3] = 1;
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
|
||||
c := cos(angle_radians);
|
||||
s := sin(angle_radians);
|
||||
|
||||
a := norm(v);
|
||||
t := a * (1-c);
|
||||
|
||||
rot := identity(Mat4);
|
||||
|
||||
rot[0][0] = c + t[0]*a[0];
|
||||
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
|
||||
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
|
||||
rot[0][3] = 0;
|
||||
|
||||
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
|
||||
rot[1][1] = c + t[1]*a[1];
|
||||
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
|
||||
rot[1][3] = 0;
|
||||
|
||||
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
|
||||
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
|
||||
rot[2][2] = c + t[2]*a[2];
|
||||
rot[2][3] = 0;
|
||||
|
||||
return rot;
|
||||
}
|
||||
|
||||
scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 {
|
||||
m[0][0] *= v[0];
|
||||
m[1][1] *= v[1];
|
||||
m[2][2] *= v[2];
|
||||
return m;
|
||||
}
|
||||
|
||||
scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 {
|
||||
m[0][0] *= s;
|
||||
m[1][1] *= s;
|
||||
m[2][2] *= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
scale :: proc{scale_vec3, scale_f32};
|
||||
|
||||
|
||||
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
|
||||
f := norm(centre - eye);
|
||||
s := norm(cross(f, up));
|
||||
u := cross(s, f);
|
||||
|
||||
return Mat4{
|
||||
{+s.x, +u.x, -f.x, 0},
|
||||
{+s.y, +u.y, -f.y, 0},
|
||||
{+s.z, +u.z, -f.z, 0},
|
||||
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
|
||||
};
|
||||
}
|
||||
|
||||
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
|
||||
m: Mat4;
|
||||
tan_half_fovy := tan(0.5 * fovy);
|
||||
|
||||
m[0][0] = 1.0 / (aspect*tan_half_fovy);
|
||||
m[1][1] = 1.0 / (tan_half_fovy);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
m[2][3] = -1.0;
|
||||
m[3][2] = -2.0*far*near / (far - near);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
|
||||
m := identity(Mat4);
|
||||
m[0][0] = +2.0 / (right - left);
|
||||
m[1][1] = +2.0 / (top - bottom);
|
||||
m[2][2] = -2.0 / (far - near);
|
||||
m[3][0] = -(right + left) / (right - left);
|
||||
m[3][1] = -(top + bottom) / (top - bottom);
|
||||
m[3][2] = -(far + near) / (far - near);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
// Quaternion operations
|
||||
|
||||
conj :: proc(q: Quat) -> Quat {
|
||||
return Quat{-q.x, -q.y, -q.z, q.w};
|
||||
}
|
||||
|
||||
quat_mul :: proc(q0, q1: Quat) -> Quat {
|
||||
d: Quat;
|
||||
d.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
|
||||
d.y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x;
|
||||
d.z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w;
|
||||
d.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
|
||||
return d;
|
||||
}
|
||||
|
||||
quat_mulf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x*f, q.y*f, q.z*f, q.w*f}; }
|
||||
quat_divf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x/f, q.y/f, q.z/f, q.w/f}; }
|
||||
|
||||
quat_div :: proc(q0, q1: Quat) -> Quat { return mul(q0, quat_inverse(q1)); }
|
||||
quat_inverse :: proc(q: Quat) -> Quat { return div(conj(q), dot(q, q)); }
|
||||
quat_dot :: proc(q0, q1: Quat) -> f32 { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; }
|
||||
|
||||
quat_norm :: proc(q: Quat) -> Quat {
|
||||
m := sqrt(dot(q, q));
|
||||
return div(q, m);
|
||||
}
|
||||
|
||||
axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat {
|
||||
v := norm(axis) * sin(0.5*angle_radians);
|
||||
w := cos(0.5*angle_radians);
|
||||
return Quat{v.x, v.y, v.z, w};
|
||||
}
|
||||
|
||||
euler_angles :: proc(pitch, yaw, roll: f32) -> Quat {
|
||||
p := axis_angle(Vec3{1, 0, 0}, pitch);
|
||||
y := axis_angle(Vec3{0, 1, 0}, yaw);
|
||||
r := axis_angle(Vec3{0, 0, 1}, roll);
|
||||
return mul(mul(y, p), r);
|
||||
}
|
||||
|
||||
quat_to_mat4 :: proc(q: Quat) -> Mat4 {
|
||||
a := quat_norm(q);
|
||||
xx := a.x*a.x; yy := a.y*a.y; zz := a.z*a.z;
|
||||
xy := a.x*a.y; xz := a.x*a.z; yz := a.y*a.z;
|
||||
wx := a.w*a.x; wy := a.w*a.y; wz := a.w*a.z;
|
||||
|
||||
m := identity(Mat4);
|
||||
|
||||
m[0][0] = 1 - 2*(yy + zz);
|
||||
m[0][1] = 2*(xy + wz);
|
||||
m[0][2] = 2*(xz - wy);
|
||||
|
||||
m[1][0] = 2*(xy - wz);
|
||||
m[1][1] = 1 - 2*(xx + zz);
|
||||
m[1][2] = 2*(yz + wx);
|
||||
|
||||
m[2][0] = 2*(xz + wy);
|
||||
m[2][1] = 2*(yz - wx);
|
||||
m[2][2] = 1 - 2*(xx + yy);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
F32_DIG :: 6;
|
||||
F32_EPSILON :: 1.192092896e-07;
|
||||
|
||||
@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
|
||||
|
||||
if i == 0 {
|
||||
for {
|
||||
x = -math.log(float64(r)) * (1.0/ rn);
|
||||
y := -math.log(float64(r));
|
||||
x = -math.ln(float64(r)) * (1.0/ rn);
|
||||
y := -math.ln(float64(r));
|
||||
if y+y >= x*x {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -47,8 +47,17 @@ uint64 :: proc(r: ^Rand = global_rand_ptr) -> u64 {
|
||||
return (a<<32) | b;
|
||||
}
|
||||
|
||||
int31 :: proc(r: ^Rand = global_rand_ptr) -> i32 { return i32(uint32(r) << 1 >> 1); }
|
||||
int63 :: proc(r: ^Rand = global_rand_ptr) -> i64 { return i64(uint64(r) << 1 >> 1); }
|
||||
uint128 :: proc(r: ^Rand = global_rand_ptr) -> u128 {
|
||||
a := u128(_random(r));
|
||||
b := u128(_random(r));
|
||||
c := u128(_random(r));
|
||||
d := u128(_random(r));
|
||||
return (a<<96) | (b<<64) | (c<<32) | d;
|
||||
}
|
||||
|
||||
int31 :: proc(r: ^Rand = global_rand_ptr) -> i32 { return i32(uint32(r) << 1 >> 1); }
|
||||
int63 :: proc(r: ^Rand = global_rand_ptr) -> i64 { return i64(uint64(r) << 1 >> 1); }
|
||||
int127 :: proc(r: ^Rand = global_rand_ptr) -> i128 { return i128(uint128(r) << 1 >> 1); }
|
||||
|
||||
int31_max :: proc(n: i32, r: ^Rand = global_rand_ptr) -> i32 {
|
||||
if n <= 0 do panic("Invalid argument to int31_max");
|
||||
@@ -76,6 +85,19 @@ int63_max :: proc(n: i64, r: ^Rand = global_rand_ptr) -> i64 {
|
||||
return v % n;
|
||||
}
|
||||
|
||||
int127_max :: proc(n: i128, r: ^Rand = global_rand_ptr) -> i128 {
|
||||
if n <= 0 do panic("Invalid argument to int63_max");
|
||||
if n&(n-1) == 0 {
|
||||
return int127(r) & (n-1);
|
||||
}
|
||||
max := i128((1<<63) - 1 - (1<<63)&u128(n));
|
||||
v := int127(r);
|
||||
for v > max {
|
||||
v = int127(r);
|
||||
}
|
||||
return v % n;
|
||||
}
|
||||
|
||||
int_max :: proc(n: int, r: ^Rand = global_rand_ptr) -> int {
|
||||
if n <= 0 do panic("Invalid argument to int_max");
|
||||
when size_of(int) == 4 {
|
||||
|
||||
+11
-12
@@ -1,7 +1,5 @@
|
||||
package mem
|
||||
|
||||
|
||||
|
||||
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||
@@ -377,7 +375,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
return nil;
|
||||
}
|
||||
|
||||
alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2);
|
||||
align := clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2);
|
||||
|
||||
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> rawptr {
|
||||
curr_addr := uintptr(&s.data[0]) + uintptr(s.offset);
|
||||
@@ -400,7 +398,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
return raw_alloc(s, size, alignment);
|
||||
return raw_alloc(s, size, align);
|
||||
case .Free:
|
||||
if old_memory == nil {
|
||||
return nil;
|
||||
@@ -429,7 +427,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
|
||||
case .Resize:
|
||||
if old_memory == nil {
|
||||
return raw_alloc(s, size, alignment);
|
||||
return raw_alloc(s, size, align);
|
||||
}
|
||||
if size == 0 {
|
||||
return nil;
|
||||
@@ -452,7 +450,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
return old_memory;
|
||||
}
|
||||
|
||||
ptr := raw_alloc(s, size, alignment);
|
||||
ptr := raw_alloc(s, size, align);
|
||||
copy(ptr, old_memory, min(old_size, size));
|
||||
return ptr;
|
||||
}
|
||||
@@ -568,9 +566,10 @@ dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
|
||||
}
|
||||
|
||||
|
||||
extra := alignment - (bytes % alignment);
|
||||
bytes += extra;
|
||||
if bytes >= out_band_size {
|
||||
n := bytes;
|
||||
extra := alignment - (n % alignment);
|
||||
n += extra;
|
||||
if n >= out_band_size {
|
||||
assert(block_allocator.procedure != nil);
|
||||
memory := block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
|
||||
block_size, alignment,
|
||||
@@ -581,7 +580,7 @@ dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
|
||||
return memory;
|
||||
}
|
||||
|
||||
if bytes_left < bytes {
|
||||
if bytes_left < n {
|
||||
cycle_new_block(pool);
|
||||
if current_block == nil {
|
||||
return nil;
|
||||
@@ -589,8 +588,8 @@ dynamic_pool_alloc :: proc(using pool: ^Dynamic_Pool, bytes: int) -> rawptr {
|
||||
}
|
||||
|
||||
memory := current_pos;
|
||||
current_pos = ptr_offset((^byte)(current_pos), bytes);
|
||||
bytes_left -= bytes;
|
||||
current_pos = ptr_offset((^byte)(current_pos), n);
|
||||
bytes_left -= n;
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
+14
-26
@@ -1,5 +1,7 @@
|
||||
package mem
|
||||
|
||||
import "core:runtime"
|
||||
|
||||
foreign _ {
|
||||
@(link_name = "llvm.bswap.i16") swap16 :: proc(b: u16) -> u16 ---;
|
||||
@(link_name = "llvm.bswap.i32") swap32 :: proc(b: u32) -> u32 ---;
|
||||
@@ -38,34 +40,10 @@ zero_slice :: proc "contextless" (data: $T/[]$E) {
|
||||
|
||||
|
||||
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memmove
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memmove(dst, src, len, 1, false);
|
||||
return dst;
|
||||
return runtime.mem_copy(dst, src, len);
|
||||
}
|
||||
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memcpy
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memcpy(dst, src, len, 1, false);
|
||||
return dst;
|
||||
return runtime.mem_copy_non_overlapping(dst, src, len);
|
||||
}
|
||||
compare :: inline proc "contextless" (a, b: []byte) -> int {
|
||||
return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
@@ -129,6 +107,16 @@ slice_to_bytes :: inline proc "contextless" (slice: $E/[]$T) -> []byte {
|
||||
return transmute([]byte)s;
|
||||
}
|
||||
|
||||
slice_data_cast :: inline proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
|
||||
when size_of(A) == 0 || size_of(B) == 0 {
|
||||
return nil;
|
||||
} else {
|
||||
s := transmute(Raw_Slice)slice;
|
||||
s.len = (len(slice) * size_of(B)) / size_of(A);
|
||||
return transmute(T)s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
buffer_from_slice :: inline proc(backing: $T/[]$E) -> [dynamic]E {
|
||||
s := transmute(Raw_Slice)backing;
|
||||
|
||||
+9
-3
@@ -31,19 +31,25 @@ Raw_Map :: struct {
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
Raw_Complex64 :: struct {real, imag: f32};
|
||||
Raw_Complex128 :: struct {real, imag: f64};
|
||||
Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32};
|
||||
Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64};
|
||||
Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32};
|
||||
Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64};
|
||||
|
||||
make_any :: inline proc(data: rawptr, id: typeid) -> any {
|
||||
return transmute(any)Raw_Any{data, id};
|
||||
}
|
||||
|
||||
raw_string_data :: inline proc(s: $T/string) -> ^byte {
|
||||
return (^Raw_String)(&s).data;
|
||||
return (transmute(Raw_String)s).data;
|
||||
}
|
||||
raw_slice_data :: inline proc(a: $T/[]$E) -> ^E {
|
||||
return cast(^E)(^Raw_Slice)(&a).data;
|
||||
return cast(^E)(transmute(Raw_Slice)a).data;
|
||||
}
|
||||
raw_dynamic_array_data :: inline proc(a: $T/[dynamic]$E) -> ^E {
|
||||
return cast(^E)(^Raw_Dynamic_Array)(&a).data;
|
||||
return cast(^E)(transmute(Raw_Dynamic_Array)a).data;
|
||||
}
|
||||
|
||||
raw_data :: proc{raw_string_data, raw_slice_data, raw_dynamic_array_data};
|
||||
|
||||
+121
-110
@@ -1,11 +1,10 @@
|
||||
package odin_ast
|
||||
|
||||
import "core:odin/token"
|
||||
import "core:odin/tokenizer"
|
||||
|
||||
Proc_Tag :: enum {
|
||||
Bounds_Check,
|
||||
No_Bounds_Check,
|
||||
Require_Results,
|
||||
}
|
||||
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
|
||||
|
||||
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
|
||||
|
||||
|
||||
Comment_Group :: struct {
|
||||
list: []token.Token,
|
||||
list: []tokenizer.Token,
|
||||
}
|
||||
|
||||
Node :: struct {
|
||||
pos: token.Pos,
|
||||
end: token.Pos,
|
||||
pos: tokenizer.Pos,
|
||||
end: tokenizer.Pos,
|
||||
derived: any,
|
||||
state_flags: Node_State_Flags,
|
||||
}
|
||||
@@ -68,29 +67,29 @@ Ident :: struct {
|
||||
|
||||
Implicit :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
}
|
||||
|
||||
|
||||
Undef :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
}
|
||||
|
||||
Basic_Lit :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
}
|
||||
|
||||
Basic_Directive :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
name: string,
|
||||
}
|
||||
|
||||
Ellipsis :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
|
||||
body: ^Stmt,
|
||||
tags: Proc_Tags,
|
||||
inlining: Proc_Inlining,
|
||||
where_token: tokenizer.Token,
|
||||
where_clauses: []^Expr,
|
||||
}
|
||||
|
||||
Comp_Lit :: struct {
|
||||
using node: Expr,
|
||||
type: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
elems: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
|
||||
Tag_Expr :: struct {
|
||||
using node: Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
name: string,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
Unary_Expr :: struct {
|
||||
using node: Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
Binary_Expr :: struct {
|
||||
using node: Expr,
|
||||
left: ^Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
right: ^Expr,
|
||||
}
|
||||
|
||||
Paren_Expr :: struct {
|
||||
using node: Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Selector_Expr :: struct {
|
||||
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
|
||||
Index_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
index: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Deref_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
}
|
||||
|
||||
Slice_Expr :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
low: ^Expr,
|
||||
interval: token.Token,
|
||||
interval: tokenizer.Token,
|
||||
high: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Call_Expr :: struct {
|
||||
using node: Expr,
|
||||
inlining: Proc_Inlining,
|
||||
expr: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
args: []^Expr,
|
||||
ellipsis: token.Token,
|
||||
close: token.Pos,
|
||||
ellipsis: tokenizer.Token,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Field_Value :: struct {
|
||||
using node: Expr,
|
||||
field: ^Expr,
|
||||
sep: token.Pos,
|
||||
sep: tokenizer.Pos,
|
||||
value: ^Expr,
|
||||
}
|
||||
|
||||
Ternary_Expr :: struct {
|
||||
using node: Expr,
|
||||
cond: ^Expr,
|
||||
op1: token.Token,
|
||||
op1: tokenizer.Token,
|
||||
x: ^Expr,
|
||||
op2: token.Token,
|
||||
op2: tokenizer.Token,
|
||||
y: ^Expr,
|
||||
}
|
||||
|
||||
Type_Assertion :: struct {
|
||||
using node: Expr,
|
||||
expr: ^Expr,
|
||||
dot: token.Pos,
|
||||
open: token.Pos,
|
||||
dot: tokenizer.Pos,
|
||||
open: tokenizer.Pos,
|
||||
type: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Type_Cast :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
open: token.Pos,
|
||||
tok: tokenizer.Token,
|
||||
open: tokenizer.Pos,
|
||||
type: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
Auto_Cast :: struct {
|
||||
using node: Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
expr: ^Expr,
|
||||
}
|
||||
|
||||
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
|
||||
|
||||
Empty_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
semicolon: token.Pos, // Position of the following ';'
|
||||
semicolon: tokenizer.Pos, // Position of the following ';'
|
||||
}
|
||||
|
||||
Expr_Stmt :: struct {
|
||||
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
|
||||
|
||||
Tag_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
name: string,
|
||||
stmt: ^Stmt,
|
||||
}
|
||||
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
|
||||
Assign_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
lhs: []^Expr,
|
||||
op: token.Token,
|
||||
op: tokenizer.Token,
|
||||
rhs: []^Expr,
|
||||
}
|
||||
|
||||
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
|
||||
Block_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
stmts: []^Stmt,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
If_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
if_pos: token.Pos,
|
||||
if_pos: tokenizer.Pos,
|
||||
init: ^Stmt,
|
||||
cond: ^Expr,
|
||||
body: ^Stmt,
|
||||
@@ -277,7 +278,7 @@ If_Stmt :: struct {
|
||||
|
||||
When_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
when_pos: token.Pos,
|
||||
when_pos: tokenizer.Pos,
|
||||
cond: ^Expr,
|
||||
body: ^Stmt,
|
||||
else_stmt: ^Stmt,
|
||||
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
|
||||
For_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
for_pos: token.Pos,
|
||||
for_pos: tokenizer.Pos,
|
||||
init: ^Stmt,
|
||||
cond: ^Expr,
|
||||
post: ^Stmt,
|
||||
@@ -306,10 +307,10 @@ For_Stmt :: struct {
|
||||
Range_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
for_pos: token.Pos,
|
||||
for_pos: tokenizer.Pos,
|
||||
val0: ^Expr,
|
||||
val1: ^Expr,
|
||||
in_pos: token.Pos,
|
||||
in_pos: tokenizer.Pos,
|
||||
expr: ^Expr,
|
||||
body: ^Stmt,
|
||||
}
|
||||
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
|
||||
|
||||
Case_Clause :: struct {
|
||||
using node: Stmt,
|
||||
case_pos: token.Pos,
|
||||
case_pos: tokenizer.Pos,
|
||||
list: []^Expr,
|
||||
terminator: token.Token,
|
||||
terminator: tokenizer.Token,
|
||||
body: []^Stmt,
|
||||
}
|
||||
|
||||
Switch_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
switch_pos: token.Pos,
|
||||
switch_pos: tokenizer.Pos,
|
||||
init: ^Stmt,
|
||||
cond: ^Expr,
|
||||
body: ^Stmt,
|
||||
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
|
||||
Type_Switch_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
label: ^Expr,
|
||||
switch_pos: token.Pos,
|
||||
switch_pos: tokenizer.Pos,
|
||||
tag: ^Stmt,
|
||||
expr: ^Expr,
|
||||
body: ^Stmt,
|
||||
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
|
||||
|
||||
Branch_Stmt :: struct {
|
||||
using node: Stmt,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
label: ^Ident,
|
||||
}
|
||||
|
||||
@@ -376,7 +377,7 @@ Value_Decl :: struct {
|
||||
Package_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
token: token.Token,
|
||||
token: tokenizer.Token,
|
||||
name: string,
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
@@ -385,9 +386,9 @@ Import_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
is_using: bool,
|
||||
import_tok: token.Token,
|
||||
name: token.Token,
|
||||
relpath: token.Token,
|
||||
import_tok: tokenizer.Token,
|
||||
name: tokenizer.Token,
|
||||
relpath: tokenizer.Token,
|
||||
fullpath: string,
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
foreign_library: ^Expr,
|
||||
body: ^Stmt,
|
||||
}
|
||||
@@ -404,27 +405,29 @@ Foreign_Block_Decl :: struct {
|
||||
Foreign_Import_Decl :: struct {
|
||||
using node: Decl,
|
||||
docs: ^Comment_Group,
|
||||
foreign_tok: token.Token,
|
||||
import_tok: token.Token,
|
||||
foreign_tok: tokenizer.Token,
|
||||
import_tok: tokenizer.Token,
|
||||
name: ^Ident,
|
||||
collection_name: string,
|
||||
fullpaths: []string,
|
||||
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Other things
|
||||
unparen_expr :: proc(expr: ^Expr) -> ^Expr {
|
||||
unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
|
||||
val = expr;
|
||||
if expr == nil {
|
||||
return nil;
|
||||
return;
|
||||
}
|
||||
for {
|
||||
e, ok := expr.derived.(Paren_Expr);
|
||||
e, ok := val.derived.(Paren_Expr);
|
||||
if !ok do break;
|
||||
expr = e.expr;
|
||||
val = e.expr;
|
||||
}
|
||||
return expr;
|
||||
return;
|
||||
}
|
||||
|
||||
Field_Flag :: enum {
|
||||
@@ -434,7 +437,9 @@ Field_Flag :: enum {
|
||||
C_Vararg,
|
||||
Auto_Cast,
|
||||
In,
|
||||
|
||||
Results,
|
||||
Tags,
|
||||
Default_Parameters,
|
||||
Typeid_Token,
|
||||
}
|
||||
@@ -442,18 +447,19 @@ Field_Flag :: enum {
|
||||
Field_Flags :: distinct bit_set[Field_Flag];
|
||||
|
||||
Field_Flags_Struct :: Field_Flags{
|
||||
Field_Flag.Using,
|
||||
.Using,
|
||||
.Tags,
|
||||
};
|
||||
Field_Flags_Record_Poly_Params :: Field_Flags{
|
||||
Field_Flag.Typeid_Token,
|
||||
.Typeid_Token,
|
||||
};
|
||||
Field_Flags_Signature :: Field_Flags{
|
||||
Field_Flag.Ellipsis,
|
||||
Field_Flag.Using,
|
||||
Field_Flag.No_Alias,
|
||||
Field_Flag.C_Vararg,
|
||||
Field_Flag.Auto_Cast,
|
||||
Field_Flag.Default_Parameters,
|
||||
.Ellipsis,
|
||||
.Using,
|
||||
.No_Alias,
|
||||
.C_Vararg,
|
||||
.Auto_Cast,
|
||||
.Default_Parameters,
|
||||
};
|
||||
|
||||
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
|
||||
@@ -462,18 +468,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
|
||||
|
||||
Proc_Group :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
open: token.Pos,
|
||||
tok: tokenizer.Token,
|
||||
open: tokenizer.Pos,
|
||||
args: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Attribute :: struct {
|
||||
using node: Node,
|
||||
tok: token.Kind,
|
||||
open: token.Pos,
|
||||
tok: tokenizer.Token_Kind,
|
||||
open: tokenizer.Pos,
|
||||
elems: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Field :: struct {
|
||||
@@ -482,56 +488,57 @@ Field :: struct {
|
||||
names: []^Expr, // Could be polymorphic
|
||||
type: ^Expr,
|
||||
default_value: ^Expr,
|
||||
tag: tokenizer.Token,
|
||||
flags: Field_Flags,
|
||||
comment: ^Comment_Group,
|
||||
}
|
||||
|
||||
Field_List :: struct {
|
||||
using node: Node,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
list: []^Field,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
|
||||
// Types
|
||||
Typeid_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
specialization: ^Expr,
|
||||
}
|
||||
|
||||
Helper_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
type: ^Expr,
|
||||
}
|
||||
|
||||
Distinct_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
type: ^Expr,
|
||||
}
|
||||
|
||||
Opaque_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Kind,
|
||||
tok: tokenizer.Token_Kind,
|
||||
type: ^Expr,
|
||||
}
|
||||
|
||||
Poly_Type :: struct {
|
||||
using node: Expr,
|
||||
dollar: token.Pos,
|
||||
dollar: tokenizer.Pos,
|
||||
type: ^Ident,
|
||||
specialization: ^Expr,
|
||||
}
|
||||
|
||||
Proc_Type :: struct {
|
||||
using node: Expr,
|
||||
tok: token.Token,
|
||||
tok: tokenizer.Token,
|
||||
calling_convention: Proc_Calling_Convention,
|
||||
params: ^Field_List,
|
||||
arrow: token.Pos,
|
||||
arrow: tokenizer.Pos,
|
||||
results: ^Field_List,
|
||||
tags: Proc_Tags,
|
||||
generic: bool,
|
||||
@@ -540,77 +547,81 @@ Proc_Type :: struct {
|
||||
|
||||
Pointer_Type :: struct {
|
||||
using node: Expr,
|
||||
pointer: token.Pos,
|
||||
pointer: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Array_Type :: struct {
|
||||
using node: Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Dynamic_Array_Type :: struct {
|
||||
using node: Expr,
|
||||
open: token.Pos,
|
||||
dynamic_pos: token.Pos,
|
||||
close: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
dynamic_pos: tokenizer.Pos,
|
||||
close: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
}
|
||||
|
||||
Struct_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
poly_params: ^Field_List,
|
||||
align: ^Expr,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
fields: ^Field_List,
|
||||
name_count: int,
|
||||
tok_pos: tokenizer.Pos,
|
||||
poly_params: ^Field_List,
|
||||
align: ^Expr,
|
||||
fields: ^Field_List,
|
||||
name_count: int,
|
||||
where_token: tokenizer.Token,
|
||||
where_clauses: []^Expr,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
}
|
||||
|
||||
Union_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
poly_params: ^Field_List,
|
||||
align: ^Expr,
|
||||
variants: []^Expr,
|
||||
where_token: tokenizer.Token,
|
||||
where_clauses: []^Expr,
|
||||
}
|
||||
|
||||
Enum_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
base_type: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
fields: []^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
|
||||
is_using: bool,
|
||||
}
|
||||
|
||||
Bit_Field_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
align: ^Expr,
|
||||
open: token.Pos,
|
||||
open: tokenizer.Pos,
|
||||
fields: []^Field_Value, // Field_Value with ':' rather than '='
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Bit_Set_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
open: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
open: tokenizer.Pos,
|
||||
elem: ^Expr,
|
||||
underlying: ^Expr,
|
||||
close: token.Pos,
|
||||
close: tokenizer.Pos,
|
||||
}
|
||||
|
||||
Map_Type :: struct {
|
||||
using node: Expr,
|
||||
tok_pos: token.Pos,
|
||||
tok_pos: tokenizer.Pos,
|
||||
key: ^Expr,
|
||||
value: ^Expr,
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package odin_ast
|
||||
|
||||
import "core:mem"
|
||||
import "core:fmt"
|
||||
import "core:odin/token"
|
||||
import "core:odin/tokenizer"
|
||||
|
||||
new :: proc($T: typeid, pos, end: token.Pos) -> ^T {
|
||||
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
|
||||
n := mem.new(T);
|
||||
n.pos = pos;
|
||||
n.end = end;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package odin_ast
|
||||
|
||||
import "core:odin/token"
|
||||
import "core:odin/tokenizer"
|
||||
|
||||
Package_Kind :: enum {
|
||||
Normal,
|
||||
@@ -26,7 +26,7 @@ File :: struct {
|
||||
src: []byte,
|
||||
|
||||
pkg_decl: ^Package_Decl,
|
||||
pkg_token: token.Token,
|
||||
pkg_token: tokenizer.Token,
|
||||
pkg_name: string,
|
||||
|
||||
decls: [dynamic]^Stmt,
|
||||
|
||||
+485
-411
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
package odin_token
|
||||
package odin_tokenizer
|
||||
|
||||
import "core:strings"
|
||||
|
||||
Token :: struct {
|
||||
kind: Kind,
|
||||
kind: Token_Kind,
|
||||
text: string,
|
||||
pos: Pos,
|
||||
}
|
||||
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
|
||||
return strings.compare(lhs.file, rhs.file);
|
||||
}
|
||||
|
||||
using Kind :: enum u32 {
|
||||
Token_Kind :: enum u32 {
|
||||
Invalid,
|
||||
EOF,
|
||||
Comment,
|
||||
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
|
||||
Package,
|
||||
Typeid,
|
||||
When,
|
||||
Where,
|
||||
If,
|
||||
Else,
|
||||
For,
|
||||
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
|
||||
Offset_Of,
|
||||
Type_Of,
|
||||
Const,
|
||||
Asm,
|
||||
Yield,
|
||||
Await,
|
||||
B_Keyword_End,
|
||||
|
||||
COUNT,
|
||||
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
|
||||
// ... Custom keywords
|
||||
};
|
||||
|
||||
tokens := [Kind.COUNT]string {
|
||||
tokens := [Token_Kind.COUNT]string {
|
||||
"Invalid",
|
||||
"EOF",
|
||||
"Comment",
|
||||
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
|
||||
"package",
|
||||
"typeid",
|
||||
"when",
|
||||
"where",
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
|
||||
"offset_of",
|
||||
"type_of",
|
||||
"const",
|
||||
"asm",
|
||||
"yield",
|
||||
"await",
|
||||
"",
|
||||
};
|
||||
|
||||
custom_keyword_tokens: []string;
|
||||
|
||||
to_string :: proc(kind: Kind) -> string {
|
||||
if Invalid <= kind && kind < COUNT {
|
||||
to_string :: proc(kind: Token_Kind) -> string {
|
||||
if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
|
||||
return tokens[kind];
|
||||
}
|
||||
if B_Custom_Keyword_Begin < kind {
|
||||
n := int(u16(kind)-u16(B_Custom_Keyword_Begin));
|
||||
if Token_Kind.B_Custom_Keyword_Begin < kind {
|
||||
n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
|
||||
if n < len(custom_keyword_tokens) {
|
||||
return custom_keyword_tokens[n];
|
||||
}
|
||||
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; }
|
||||
is_operator :: proc(kind: Kind) -> bool {
|
||||
is_literal :: proc(kind: Token_Kind) -> bool {
|
||||
return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
|
||||
}
|
||||
is_operator :: proc(kind: Token_Kind) -> bool {
|
||||
switch kind {
|
||||
case B_Operator_Begin..B_Operator_End:
|
||||
case .B_Operator_Begin .. .B_Operator_End:
|
||||
return true;
|
||||
case In, Notin:
|
||||
case .In, .Notin:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_assignment_operator :: proc(kind: Kind) -> bool {
|
||||
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
|
||||
is_assignment_operator :: proc(kind: Token_Kind) -> bool {
|
||||
return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
|
||||
}
|
||||
is_keyword :: proc(kind: Kind) -> bool {
|
||||
is_keyword :: proc(kind: Token_Kind) -> bool {
|
||||
switch {
|
||||
case B_Keyword_Begin < kind && kind < B_Keyword_End:
|
||||
case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
|
||||
return true;
|
||||
case B_Custom_Keyword_Begin < kind:
|
||||
case Token_Kind.B_Custom_Keyword_Begin < kind:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1,10 +1,9 @@
|
||||
package odin_tokenizer
|
||||
|
||||
import "core:fmt"
|
||||
import "core:odin/token"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
|
||||
Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
|
||||
|
||||
Tokenizer :: struct {
|
||||
// Immutable data
|
||||
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
|
||||
}
|
||||
|
||||
@(private)
|
||||
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
|
||||
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
|
||||
line := t.line_count;
|
||||
column := offset - t.line_offset + 1;
|
||||
|
||||
return token.Pos {
|
||||
return Pos {
|
||||
file = t.path,
|
||||
offset = offset,
|
||||
line = line,
|
||||
@@ -53,10 +52,10 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
|
||||
};
|
||||
}
|
||||
|
||||
default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
|
||||
fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column);
|
||||
fmt.printf_err(msg, ..args);
|
||||
fmt.printf_err("\n");
|
||||
default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
|
||||
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
|
||||
fmt.eprintf(msg, ..args);
|
||||
fmt.eprintf("\n");
|
||||
}
|
||||
|
||||
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
|
||||
@@ -98,9 +97,9 @@ advance_rune :: proc(using t: ^Tokenizer) {
|
||||
}
|
||||
}
|
||||
|
||||
peek_byte :: proc(using t: ^Tokenizer, offset := 0) -> byte {
|
||||
if read_offset+offset < len(src) {
|
||||
return src[read_offset+offset];
|
||||
peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte {
|
||||
if t.read_offset+offset < len(t.src) {
|
||||
return t.src[t.read_offset+offset];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
|
||||
return string(t.src[offset : t.offset]);
|
||||
}
|
||||
|
||||
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) {
|
||||
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
|
||||
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
|
||||
for digit_val(t.ch) < base || t.ch == '_' {
|
||||
advance_rune(t);
|
||||
}
|
||||
}
|
||||
scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) {
|
||||
scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) {
|
||||
if t.ch == 'e' || t.ch == 'E' {
|
||||
kind^ = token.Float;
|
||||
kind^ = .Float;
|
||||
advance_rune(t);
|
||||
if t.ch == '-' || t.ch == '+' {
|
||||
advance_rune(t);
|
||||
@@ -343,17 +342,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
}
|
||||
|
||||
// NOTE(bill): This needs to be here for sanity's sake
|
||||
if t.ch == 'i' {
|
||||
kind^ = token.Imag;
|
||||
switch t.ch {
|
||||
case 'i', 'j', 'k':
|
||||
kind^ = .Imag;
|
||||
advance_rune(t);
|
||||
}
|
||||
}
|
||||
scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) {
|
||||
scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
|
||||
if t.ch == '.' && peek_byte(t) == '.' {
|
||||
return true;
|
||||
}
|
||||
if t.ch == '.' {
|
||||
kind^ = token.Float;
|
||||
kind^ = .Float;
|
||||
advance_rune(t);
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
@@ -362,21 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
|
||||
|
||||
offset := t.offset;
|
||||
kind := token.Integer;
|
||||
kind := Token_Kind.Integer;
|
||||
seen_point := seen_decimal_point;
|
||||
|
||||
if seen_decimal_point {
|
||||
if seen_point {
|
||||
offset -= 1;
|
||||
kind = token.Float;
|
||||
kind = .Float;
|
||||
scan_mantissa(t, 10);
|
||||
scan_exponent(t, &kind);
|
||||
} else {
|
||||
if t.ch == '0' {
|
||||
int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) {
|
||||
int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) {
|
||||
prev := t.offset;
|
||||
advance_rune(t);
|
||||
scan_mantissa(t, base);
|
||||
if t.offset - prev <= 1 {
|
||||
kind^ = token.Invalid;
|
||||
kind^ = .Invalid;
|
||||
error(t, t.offset, msg);
|
||||
}
|
||||
}
|
||||
@@ -393,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
advance_rune(t);
|
||||
scan_mantissa(t, 16);
|
||||
if t.offset - prev <= 1 {
|
||||
kind = token.Invalid;
|
||||
kind = .Invalid;
|
||||
error(t, t.offset, "illegal hexadecimal floating-point number");
|
||||
} else {
|
||||
sub := t.src[prev+1 : t.offset];
|
||||
@@ -412,10 +413,10 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
}
|
||||
|
||||
case:
|
||||
seen_decimal_point = false;
|
||||
seen_point = false;
|
||||
scan_mantissa(t, 10);
|
||||
if t.ch == '.' {
|
||||
seen_decimal_point = true;
|
||||
seen_point = true;
|
||||
if scan_fraction(t, &kind) {
|
||||
return kind, string(t.src[offset : t.offset]);
|
||||
}
|
||||
@@ -438,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
||||
}
|
||||
|
||||
|
||||
scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind {
|
||||
scan :: proc(t: ^Tokenizer) -> Token {
|
||||
switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind {
|
||||
if t.ch == '=' {
|
||||
advance_rune(t);
|
||||
return tok1;
|
||||
}
|
||||
return tok0;
|
||||
}
|
||||
switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind {
|
||||
switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind {
|
||||
if t.ch == '=' {
|
||||
advance_rune(t);
|
||||
return tok1;
|
||||
@@ -457,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
}
|
||||
return tok0;
|
||||
}
|
||||
switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind {
|
||||
switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
|
||||
if t.ch == '=' {
|
||||
advance_rune(t);
|
||||
return tok1;
|
||||
@@ -478,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
|
||||
offset := t.offset;
|
||||
|
||||
kind: token.Kind;
|
||||
kind: Token_Kind;
|
||||
lit: string;
|
||||
pos := offset_to_pos(t, offset);
|
||||
|
||||
switch ch := t.ch; true {
|
||||
case is_letter(ch):
|
||||
lit = scan_identifier(t);
|
||||
kind = token.Ident;
|
||||
kind = .Ident;
|
||||
check_keyword: if len(lit) > 1 {
|
||||
// TODO(bill): Maybe have a hash table lookup rather than this linear search
|
||||
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
|
||||
if lit == token.tokens[i] {
|
||||
kind = token.Kind(i);
|
||||
for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End {
|
||||
if lit == tokens[i] {
|
||||
kind = Token_Kind(i);
|
||||
break check_keyword;
|
||||
}
|
||||
}
|
||||
for keyword, i in token.custom_keyword_tokens {
|
||||
for keyword, i in custom_keyword_tokens {
|
||||
if lit == keyword {
|
||||
kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin;
|
||||
kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
|
||||
break check_keyword;
|
||||
}
|
||||
}
|
||||
@@ -507,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
||||
advance_rune(t);
|
||||
switch ch {
|
||||
case -1:
|
||||
kind = token.EOF;
|
||||
kind = .EOF;
|
||||
case '"':
|
||||
kind = token.String;
|
||||
kind = .String;
|
||||
lit = scan_string(t);
|
||||
case '\'':
|
||||
kind = token.Rune;
|
||||
kind = .Rune;
|
||||
lit = scan_rune(t);
|
||||
case '`':
|
||||
kind = token.String;
|
||||
kind = .String;
|
||||
lit = scan_raw_string(t);
|
||||
case '=':
|
||||
if t.ch == '>' {
|
||||
advance_rune(t);
|
||||
kind = token.Double_Arrow_Right;
|
||||
kind = .Double_Arrow_Right;
|
||||
} else {
|
||||
kind = switch2(t, token.Eq, token.Cmp_Eq);
|
||||
kind = switch2(t, .Eq, .Cmp_Eq);
|
||||
}
|
||||
case '!': kind = switch2(t, token.Not, token.Not_Eq);
|
||||
case '!': kind = switch2(t, .Not, .Not_Eq);
|
||||
case '#':
|
||||
kind = token.Hash;
|
||||
kind = .Hash;
|
||||
if t.ch == '!' {
|
||||
kind = token.Comment;
|
||||
kind = .Comment;
|
||||
lit = scan_comment(t);
|
||||
}
|
||||
case '?': kind = token.Question;
|
||||
case '@': kind = token.At;
|
||||
case '$': kind = token.Dollar;
|
||||
case '^': kind = token.Pointer;
|
||||
case '+': kind = switch2(t, token.Add, token.Add_Eq);
|
||||
case '?': kind = .Question;
|
||||
case '@': kind = .At;
|
||||
case '$': kind = .Dollar;
|
||||
case '^': kind = .Pointer;
|
||||
case '+': kind = switch2(t, .Add, .Add_Eq);
|
||||
case '-':
|
||||
if t.ch == '>' {
|
||||
advance_rune(t);
|
||||
kind = token.Arrow_Right;
|
||||
kind = .Arrow_Right;
|
||||
} else if t.ch == '-' && peek_byte(t) == '-' {
|
||||
advance_rune(t);
|
||||
advance_rune(t);
|
||||
kind = token.Undef;
|
||||
kind = .Undef;
|
||||
} else {
|
||||
kind = switch2(t, token.Sub, token.Sub_Eq);
|
||||
kind = switch2(t, .Sub, .Sub_Eq);
|
||||
}
|
||||
case '*': kind = switch2(t, token.Mul, token.Mul_Eq);
|
||||
case '*': kind = switch2(t, .Mul, .Mul_Eq);
|
||||
case '/':
|
||||
if t.ch == '/' || t.ch == '*' {
|
||||
kind = token.Comment;
|
||||
kind = .Comment;
|
||||
lit = scan_comment(t);
|
||||
} else {
|
||||
kind = switch2(t, token.Quo, token.Quo_Eq);
|
||||
kind = switch2(t, .Quo, .Quo_Eq);
|
||||
}
|
||||
case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq);
|
||||
case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
|
||||
case '&':
|
||||
if t.ch == '~' {
|
||||
advance_rune(t);
|
||||
kind = switch2(t, token.And_Not, token.And_Not_Eq);
|
||||
kind = switch2(t, .And_Not, .And_Not_Eq);
|
||||
} else {
|
||||
kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And);
|
||||
kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
|
||||
}
|
||||
case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or);
|
||||
case '~': kind = token.Xor;
|
||||
case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
|
||||
case '~': kind = .Xor;
|
||||
case '<':
|
||||
if t.ch == '-' {
|
||||
advance_rune(t);
|
||||
kind = token.Arrow_Left;
|
||||
kind = .Arrow_Left;
|
||||
} else {
|
||||
kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq);
|
||||
kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
|
||||
}
|
||||
case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq);
|
||||
case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
|
||||
|
||||
case '≠': kind = token.Not_Eq;
|
||||
case '≤': kind = token.Lt_Eq;
|
||||
case '≥': kind = token.Gt_Eq;
|
||||
case '∈': kind = token.In;
|
||||
case '∉': kind = token.Notin;
|
||||
case '≠': kind = .Not_Eq;
|
||||
case '≤': kind = .Lt_Eq;
|
||||
case '≥': kind = .Gt_Eq;
|
||||
case '∈': kind = .In;
|
||||
case '∉': kind = .Notin;
|
||||
|
||||
case '.':
|
||||
if '0' <= t.ch && t.ch <= '9' {
|
||||
kind, lit = scan_number(t, true);
|
||||
} else {
|
||||
kind = token.Period;
|
||||
kind = .Period;
|
||||
if t.ch == '.' {
|
||||
advance_rune(t);
|
||||
kind = token.Ellipsis;
|
||||
kind = .Ellipsis;
|
||||
if t.ch == '<' {
|
||||
advance_rune(t);
|
||||
kind = token.Range_Half;
|
||||
kind = .Range_Half;
|
||||
}
|
||||
}
|
||||
}
|
||||
case ':': kind = token.Colon;
|
||||
case ',': kind = token.Comma;
|
||||
case ';': kind = token.Semicolon;
|
||||
case '(': kind = token.Open_Paren;
|
||||
case ')': kind = token.Close_Paren;
|
||||
case '[': kind = token.Open_Bracket;
|
||||
case ']': kind = token.Close_Bracket;
|
||||
case '{': kind = token.Open_Brace;
|
||||
case '}': kind = token.Close_Brace;
|
||||
case ':': kind = .Colon;
|
||||
case ',': kind = .Comma;
|
||||
case ';': kind = .Semicolon;
|
||||
case '(': kind = .Open_Paren;
|
||||
case ')': kind = .Close_Paren;
|
||||
case '[': kind = .Open_Bracket;
|
||||
case ']': kind = .Close_Bracket;
|
||||
case '{': kind = .Open_Brace;
|
||||
case '}': kind = .Close_Brace;
|
||||
|
||||
case '\\': kind = token.Back_Slash;
|
||||
case '\\': kind = .Back_Slash;
|
||||
|
||||
case:
|
||||
if ch != utf8.RUNE_BOM {
|
||||
error(t, t.offset, "illegal character '%r': %d", ch, ch);
|
||||
}
|
||||
kind = token.Invalid;
|
||||
kind = .Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
if lit == "" {
|
||||
lit = string(t.src[offset : t.offset]);
|
||||
}
|
||||
return token.Token{kind, lit, pos};
|
||||
return Token{kind, lit, pos};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ foreign import libc "system:c"
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
OS :: "osx";
|
||||
OS :: "darwin";
|
||||
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
@@ -258,7 +258,6 @@ exit :: inline proc(code: int) -> ! {
|
||||
_unix_exit(code);
|
||||
}
|
||||
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
// return int(_unix_gettid());
|
||||
return 0;
|
||||
@@ -287,9 +286,9 @@ dlerror :: proc() -> string {
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
args := make([]string, len(runtime.args__));
|
||||
res := make([]string, len(runtime.args__));
|
||||
for arg, i in runtime.args__ {
|
||||
args[i] = string(arg);
|
||||
res[i] = string(arg);
|
||||
}
|
||||
return args;
|
||||
return res;
|
||||
}
|
||||
+2422
-162
File diff suppressed because it is too large
Load Diff
@@ -392,9 +392,9 @@ dlerror :: proc() -> string {
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
args := make([]string, len(runtime.args__));
|
||||
res := make([]string, len(runtime.args__));
|
||||
for arg, i in runtime.args__ {
|
||||
args[i] = string(arg);
|
||||
res[i] = string(arg);
|
||||
}
|
||||
return args;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool {
|
||||
is_windows_10 :: proc() -> bool {
|
||||
osvi := get_windows_version_ansi();
|
||||
return (osvi.major_version == 10 && osvi.minor_version == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
package reflect
|
||||
|
||||
import "core:runtime"
|
||||
import "core:mem"
|
||||
|
||||
|
||||
Type_Kind :: enum {
|
||||
Invalid,
|
||||
|
||||
Named,
|
||||
Integer,
|
||||
Rune,
|
||||
Float,
|
||||
Complex,
|
||||
Quaternion,
|
||||
String,
|
||||
Boolean,
|
||||
Any,
|
||||
Type_Id,
|
||||
Pointer,
|
||||
Procedure,
|
||||
Array,
|
||||
Dynamic_Array,
|
||||
Slice,
|
||||
Tuple,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
Map,
|
||||
Bit_Field,
|
||||
Bit_Set,
|
||||
Opaque,
|
||||
Simd_Vector,
|
||||
}
|
||||
|
||||
|
||||
type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
ti := type_info_of(T);
|
||||
if ti != nil {
|
||||
#complete switch _ in ti.variant {
|
||||
case runtime.Type_Info_Named: return .Named;
|
||||
case runtime.Type_Info_Integer: return .Integer;
|
||||
case runtime.Type_Info_Rune: return .Rune;
|
||||
case runtime.Type_Info_Float: return .Float;
|
||||
case runtime.Type_Info_Complex: return .Complex;
|
||||
case runtime.Type_Info_Quaternion: return .Quaternion;
|
||||
case runtime.Type_Info_String: return .String;
|
||||
case runtime.Type_Info_Boolean: return .Boolean;
|
||||
case runtime.Type_Info_Any: return .Any;
|
||||
case runtime.Type_Info_Type_Id: return .Type_Id;
|
||||
case runtime.Type_Info_Pointer: return .Pointer;
|
||||
case runtime.Type_Info_Procedure: return .Procedure;
|
||||
case runtime.Type_Info_Array: return .Array;
|
||||
case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
|
||||
case runtime.Type_Info_Slice: return .Slice;
|
||||
case runtime.Type_Info_Tuple: return .Tuple;
|
||||
case runtime.Type_Info_Struct: return .Struct;
|
||||
case runtime.Type_Info_Union: return .Union;
|
||||
case runtime.Type_Info_Enum: return .Enum;
|
||||
case runtime.Type_Info_Map: return .Map;
|
||||
case runtime.Type_Info_Bit_Field: return .Bit_Field;
|
||||
case runtime.Type_Info_Bit_Set: return .Bit_Set;
|
||||
case runtime.Type_Info_Opaque: return .Opaque;
|
||||
case runtime.Type_Info_Simd_Vector: return .Simd_Vector;
|
||||
}
|
||||
|
||||
}
|
||||
return .Invalid;
|
||||
}
|
||||
|
||||
// TODO(bill): Better name
|
||||
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
return type_kind(runtime.typeid_base(T));
|
||||
}
|
||||
|
||||
// TODO(bill): Better name
|
||||
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
return type_kind(runtime.typeid_core(T));
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_of_typeid :: proc(T: typeid) -> int {
|
||||
if ti := type_info_of(T); ti != nil {
|
||||
return ti.size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
align_of_typeid :: proc(T: typeid) -> int {
|
||||
if ti := type_info_of(T); ti != nil {
|
||||
return ti.align;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
to_bytes :: proc(v: any) -> []byte {
|
||||
if v != nil {
|
||||
sz := size_of_typeid(v.id);
|
||||
return mem.slice_ptr((^byte)(v.data), sz);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
|
||||
return v.data, v.id;
|
||||
}
|
||||
|
||||
is_nil :: proc(v: any) -> bool {
|
||||
data := to_bytes(v);
|
||||
if data != nil {
|
||||
return true;
|
||||
}
|
||||
for v in data do if v != 0 {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
length :: proc(val: any) -> int {
|
||||
if val == nil do return 0;
|
||||
|
||||
v := val;
|
||||
v.id = runtime.typeid_base(v.id);
|
||||
switch a in v {
|
||||
case runtime.Type_Info_Array:
|
||||
return a.count;
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
return (^mem.Raw_Slice)(v.data).len;
|
||||
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
return (^mem.Raw_Dynamic_Array)(v.data).len;
|
||||
|
||||
case runtime.Type_Info_String:
|
||||
if a.is_cstring {
|
||||
return len((^cstring)(v.data)^);
|
||||
} else {
|
||||
return (^mem.Raw_String)(v.data).len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
if val == nil do return nil;
|
||||
|
||||
v := val;
|
||||
v.id = runtime.typeid_base(v.id);
|
||||
switch a in v {
|
||||
case runtime.Type_Info_Array:
|
||||
runtime.bounds_check_error_loc(loc, i, a.count);
|
||||
offset := uintptr(a.elem.size * i);
|
||||
data := rawptr(uintptr(v.data) + offset);
|
||||
return any{data, a.elem.id};
|
||||
|
||||
case runtime.Type_Info_Slice:
|
||||
raw := (^mem.Raw_Slice)(v.data);
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len);
|
||||
offset := uintptr(a.elem.size * i);
|
||||
data := rawptr(uintptr(raw.data) + offset);
|
||||
return any{data, a.elem.id};
|
||||
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
raw := (^mem.Raw_Dynamic_Array)(v.data);
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len);
|
||||
offset := uintptr(a.elem.size * i);
|
||||
data := rawptr(uintptr(raw.data) + offset);
|
||||
return any{data, a.elem.id};
|
||||
|
||||
case runtime.Type_Info_String:
|
||||
if a.is_cstring do return nil;
|
||||
|
||||
raw := (^mem.Raw_String)(v.data);
|
||||
runtime.bounds_check_error_loc(loc, i, raw.len);
|
||||
offset := uintptr(size_of(u8) * i);
|
||||
data := rawptr(uintptr(raw.data) + offset);
|
||||
return any{data, typeid_of(u8)};
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Struct_Tag :: distinct string;
|
||||
|
||||
Struct_Field :: struct {
|
||||
name: string,
|
||||
type: typeid,
|
||||
tag: Struct_Tag,
|
||||
offset: uintptr,
|
||||
}
|
||||
|
||||
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
if 0 <= i && i < len(s.names) {
|
||||
field.name = s.names[i];
|
||||
field.type = s.types[i].id;
|
||||
field.tag = Struct_Tag(s.tags[i]);
|
||||
field.offset = s.offsets[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
for fname, i in s.names {
|
||||
if fname == name {
|
||||
field.name = s.names[i];
|
||||
field.type = s.types[i].id;
|
||||
field.tag = Struct_Tag(s.tags[i]);
|
||||
field.offset = s.offsets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
|
||||
if a == nil do return nil;
|
||||
|
||||
ti := runtime.type_info_base(type_info_of(a.id));
|
||||
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
for name, i in s.names {
|
||||
if name == field {
|
||||
return any{
|
||||
rawptr(uintptr(a.data) + s.offsets[i]),
|
||||
s.types[i].id,
|
||||
};
|
||||
}
|
||||
|
||||
if recurse && s.usings[i] {
|
||||
f := any{
|
||||
rawptr(uintptr(a.data) + s.offsets[i]),
|
||||
s.types[i].id,
|
||||
};
|
||||
|
||||
if res := struct_field_value_by_name(f, field, recurse); res != nil {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct_field_names :: proc(T: typeid) -> []string {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return s.names;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return s.types;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return transmute([]Struct_Tag)s.tags;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
||||
ti := runtime.type_info_base(type_info_of(T));
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
return s.offsets;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
|
||||
value, _ = struct_tag_lookup(tag, key);
|
||||
return;
|
||||
}
|
||||
|
||||
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
|
||||
for t := tag; t != ""; /**/ {
|
||||
i := 0;
|
||||
for i < len(t) && t[i] == ' ' { // Skip whitespace
|
||||
i += 1;
|
||||
}
|
||||
t = t[i:];
|
||||
if len(t) == 0 do break;
|
||||
|
||||
i = 0;
|
||||
loop: for i < len(t) {
|
||||
switch t[i] {
|
||||
case ':', '"':
|
||||
break loop;
|
||||
case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
|
||||
break loop;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i == 0 do break;
|
||||
if i+1 >= len(t) do break;
|
||||
|
||||
if t[i] != ':' || t[i+1] != '"' {
|
||||
break;
|
||||
}
|
||||
name := string(t[:i]);
|
||||
t = t[i+1:];
|
||||
|
||||
i = 1;
|
||||
for i < len(t) && t[i] != '"' { // find closing quote
|
||||
if t[i] == '\\' do i += 1; // Skip escaped characters
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if i >= len(t) do break;
|
||||
|
||||
val := string(t[:i+1]);
|
||||
t = t[i+1:];
|
||||
|
||||
if key == name {
|
||||
return val[1:i], true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
enum_string :: proc(a: any) -> string {
|
||||
if a == nil do return "";
|
||||
ti := runtime.type_info_base(type_info_of(a.id));
|
||||
if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
|
||||
for _, i in e.values {
|
||||
value := &e.values[i];
|
||||
n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
|
||||
if n == 0 {
|
||||
return e.names[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic("expected an enum to reflect.enum_string");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
|
||||
id := union_variant_typeid(a);
|
||||
return type_info_of(id);
|
||||
}
|
||||
|
||||
union_variant_typeid :: proc(a: any) -> typeid {
|
||||
if a == nil do return nil;
|
||||
|
||||
ti := runtime.type_info_base(type_info_of(a.id));
|
||||
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||
tag_ptr := uintptr(a.data) + info.tag_offset;
|
||||
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||
|
||||
tag: i64 = ---;
|
||||
switch i in tag_any {
|
||||
case u8: tag = i64(i);
|
||||
case i8: tag = i64(i);
|
||||
case u16: tag = i64(i);
|
||||
case i16: tag = i64(i);
|
||||
case u32: tag = i64(i);
|
||||
case i32: tag = i64(i);
|
||||
case u64: tag = i64(i);
|
||||
case i64: tag = i64(i);
|
||||
case: unimplemented();
|
||||
}
|
||||
|
||||
if a.data != nil && tag != 0 {
|
||||
return info.variants[tag-1].id;
|
||||
}
|
||||
} else {
|
||||
panic("expected a union to reflect.union_variant_typeid");
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package types
|
||||
package reflect
|
||||
|
||||
import rt "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||
if a == b do return true;
|
||||
@@ -108,9 +109,11 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||
for _, i in x.types {
|
||||
xn, yn := x.names[i], y.names[i];
|
||||
xt, yt := x.types[i], y.types[i];
|
||||
xl, yl := x.tags[i], y.tags[i];
|
||||
|
||||
if xn != yn do return false;
|
||||
if !are_types_identical(xt, yt) do return false;
|
||||
if xl != yl do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -272,3 +275,216 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
|
||||
write_type(buf, type_info_of(id));
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
|
||||
using strings;
|
||||
if ti == nil {
|
||||
write_string(buf, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case rt.Type_Info_Named:
|
||||
write_string(buf, info.name);
|
||||
case rt.Type_Info_Integer:
|
||||
switch ti.id {
|
||||
case int: write_string(buf, "int");
|
||||
case uint: write_string(buf, "uint");
|
||||
case uintptr: write_string(buf, "uintptr");
|
||||
case:
|
||||
write_byte(buf, info.signed ? 'i' : 'u');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
switch info.endianness {
|
||||
case .Little: write_string(buf, "le");
|
||||
case .Big: write_string(buf, "be");
|
||||
}
|
||||
}
|
||||
case rt.Type_Info_Rune:
|
||||
write_string(buf, "rune");
|
||||
case rt.Type_Info_Float:
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case rt.Type_Info_Complex:
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case rt.Type_Info_String:
|
||||
if info.is_cstring {
|
||||
write_string(buf, "cstring");
|
||||
} else {
|
||||
write_string(buf, "string");
|
||||
}
|
||||
case rt.Type_Info_Boolean:
|
||||
switch ti.id {
|
||||
case bool: write_string(buf, "bool");
|
||||
case:
|
||||
write_byte(buf, 'b');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case rt.Type_Info_Any:
|
||||
write_string(buf, "any");
|
||||
|
||||
case rt.Type_Info_Type_Id:
|
||||
write_string(buf, "typeid");
|
||||
|
||||
case rt.Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
write_string(buf, "rawptr");
|
||||
} else {
|
||||
write_string(buf, "^");
|
||||
write_type(buf, info.elem);
|
||||
}
|
||||
case rt.Type_Info_Procedure:
|
||||
write_string(buf, "proc");
|
||||
if info.params == nil {
|
||||
write_string(buf, "()");
|
||||
} else {
|
||||
t := info.params.variant.(rt.Type_Info_Tuple);
|
||||
write_string(buf, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, t);
|
||||
}
|
||||
write_string(buf, ")");
|
||||
}
|
||||
if info.results != nil {
|
||||
write_string(buf, " -> ");
|
||||
write_type(buf, info.results);
|
||||
}
|
||||
case rt.Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
if count != 1 do write_string(buf, "(");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
|
||||
t := info.types[i];
|
||||
|
||||
if len(name) > 0 {
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
}
|
||||
write_type(buf, t);
|
||||
}
|
||||
if count != 1 do write_string(buf, ")");
|
||||
|
||||
case rt.Type_Info_Array:
|
||||
write_string(buf, "[");
|
||||
write_i64(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
case rt.Type_Info_Dynamic_Array:
|
||||
write_string(buf, "[dynamic]");
|
||||
write_type(buf, info.elem);
|
||||
case rt.Type_Info_Slice:
|
||||
write_string(buf, "[]");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case rt.Type_Info_Map:
|
||||
write_string(buf, "map[");
|
||||
write_type(buf, info.key);
|
||||
write_byte(buf, ']');
|
||||
write_type(buf, info.value);
|
||||
|
||||
case rt.Type_Info_Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.is_packed do write_string(buf, "#packed ");
|
||||
if info.is_raw_union do write_string(buf, "#raw_union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_type(buf, info.types[i]);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Union:
|
||||
write_string(buf, "union ");
|
||||
if info.custom_align {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_byte(buf, '{');
|
||||
for variant, i in info.variants {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_type(buf, variant);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Enum:
|
||||
write_string(buf, "enum ");
|
||||
write_type(buf, info.base);
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Bit_Field:
|
||||
write_string(buf, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
write_string(buf, "#align ");
|
||||
write_i64(buf, i64(ti.align), 10);
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
write_string(buf, name);
|
||||
write_string(buf, ": ");
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case rt.Type_Info_Bit_Set:
|
||||
write_string(buf, "bit_set[");
|
||||
switch {
|
||||
case is_enum(info.elem):
|
||||
write_type(buf, info.elem);
|
||||
case is_rune(info.elem):
|
||||
write_encoded_rune(buf, rune(info.lower));
|
||||
write_string(buf, "..");
|
||||
write_encoded_rune(buf, rune(info.upper));
|
||||
case:
|
||||
write_i64(buf, info.lower, 10);
|
||||
write_string(buf, "..");
|
||||
write_i64(buf, info.upper, 10);
|
||||
}
|
||||
if info.underlying != nil {
|
||||
write_string(buf, "; ");
|
||||
write_type(buf, info.underlying);
|
||||
}
|
||||
write_byte(buf, ']');
|
||||
|
||||
case rt.Type_Info_Opaque:
|
||||
write_string(buf, "opaque ");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case rt.Type_Info_Simd_Vector:
|
||||
if info.is_x86_mmx {
|
||||
write_string(buf, "intrinsics.x86_mmx");
|
||||
} else {
|
||||
write_string(buf, "intrinsics.vector(");
|
||||
write_i64(buf, i64(info.count));
|
||||
write_string(buf, ", ");
|
||||
write_type(buf, info.elem);
|
||||
write_byte(buf, ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+108
-79
@@ -6,6 +6,7 @@ package runtime
|
||||
import "core:os"
|
||||
import "core:mem"
|
||||
import "core:log"
|
||||
import "intrinsics"
|
||||
|
||||
// Naming Conventions:
|
||||
// In general, Ada_Case for types and snake_case for values
|
||||
@@ -40,23 +41,24 @@ Type_Info_Enum_Value :: union {
|
||||
u8, u16, u32, u64, uint, uintptr,
|
||||
};
|
||||
|
||||
Type_Info_Endianness :: enum u8 {
|
||||
Platform_Endianness :: enum u8 {
|
||||
Platform = 0,
|
||||
Little = 1,
|
||||
Big = 2,
|
||||
}
|
||||
|
||||
// Variant Types
|
||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {};
|
||||
Type_Info_Complex :: struct {};
|
||||
Type_Info_String :: struct {is_cstring: bool};
|
||||
Type_Info_Boolean :: struct {};
|
||||
Type_Info_Any :: struct {};
|
||||
Type_Info_Type_Id :: struct {};
|
||||
Type_Info_Pointer :: struct {
|
||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {};
|
||||
Type_Info_Complex :: struct {};
|
||||
Type_Info_Quaternion :: struct {};
|
||||
Type_Info_String :: struct {is_cstring: bool};
|
||||
Type_Info_Boolean :: struct {};
|
||||
Type_Info_Any :: struct {};
|
||||
Type_Info_Type_Id :: struct {};
|
||||
Type_Info_Pointer :: struct {
|
||||
elem: ^Type_Info // nil -> rawptr
|
||||
};
|
||||
Type_Info_Procedure :: struct {
|
||||
@@ -79,17 +81,22 @@ Type_Info_Tuple :: struct { // Only really used for procedures
|
||||
Type_Info_Struct :: struct {
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
offsets: []uintptr, // offsets may not be used in tuples
|
||||
usings: []bool, // usings may not be used in tuples
|
||||
offsets: []uintptr,
|
||||
usings: []bool,
|
||||
tags: []string,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
custom_align: bool,
|
||||
// These are only set iff this structure is an SOA structure
|
||||
soa_base_type: ^Type_Info,
|
||||
soa_len: int,
|
||||
};
|
||||
Type_Info_Union :: struct {
|
||||
variants: []^Type_Info,
|
||||
tag_offset: uintptr,
|
||||
tag_type: ^Type_Info,
|
||||
variants: []^Type_Info,
|
||||
tag_offset: uintptr,
|
||||
tag_type: ^Type_Info,
|
||||
custom_align: bool,
|
||||
no_nil: bool,
|
||||
};
|
||||
Type_Info_Enum :: struct {
|
||||
base: ^Type_Info,
|
||||
@@ -133,6 +140,7 @@ Type_Info :: struct {
|
||||
Type_Info_Rune,
|
||||
Type_Info_Float,
|
||||
Type_Info_Complex,
|
||||
Type_Info_Quaternion,
|
||||
Type_Info_String,
|
||||
Type_Info_Boolean,
|
||||
Type_Info_Any,
|
||||
@@ -161,6 +169,7 @@ Typeid_Kind :: enum u8 {
|
||||
Rune,
|
||||
Float,
|
||||
Complex,
|
||||
Quaternion,
|
||||
String,
|
||||
Boolean,
|
||||
Any,
|
||||
@@ -182,12 +191,13 @@ Typeid_Kind :: enum u8 {
|
||||
#assert(len(Typeid_Kind) < 32);
|
||||
|
||||
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
||||
index: 8*size_of(align_of(uintptr)) - 8,
|
||||
index: 8*size_of(uintptr) - 8,
|
||||
kind: 5, // Typeid_Kind
|
||||
named: 1,
|
||||
special: 1, // signed, cstring, etc
|
||||
reserved: 1,
|
||||
}
|
||||
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
|
||||
|
||||
// NOTE(bill): only the ones that are needed (not all types)
|
||||
// This will be set by the compiler
|
||||
@@ -230,7 +240,22 @@ global_scratch_allocator_data: mem.Scratch_Allocator;
|
||||
|
||||
|
||||
|
||||
Raw_Slice :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Raw_Dynamic_Array :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: mem.Allocator,
|
||||
}
|
||||
|
||||
Raw_Map :: struct {
|
||||
hashes: []int,
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
INITIAL_MAP_CAP :: 16;
|
||||
|
||||
@@ -254,7 +279,7 @@ Map_Entry_Header :: struct {
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^mem.Raw_Map,
|
||||
m: ^Raw_Map,
|
||||
is_key_string: bool,
|
||||
|
||||
entry_size: int,
|
||||
@@ -281,19 +306,21 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
}
|
||||
|
||||
|
||||
type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil do return nil;
|
||||
|
||||
base := info;
|
||||
loop: for {
|
||||
switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base;
|
||||
case Type_Info_Enum: base = i.base;
|
||||
case Type_Info_Named: base = i.base;
|
||||
case Type_Info_Enum: base = i.base;
|
||||
case Type_Info_Opaque: base = i.elem;
|
||||
case: break loop;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
type_info_base_without_enum :: type_info_core;
|
||||
|
||||
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
|
||||
data := transmute(Typeid_Bit_Field)id;
|
||||
@@ -309,10 +336,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti = type_info_base(ti);
|
||||
return ti.id;
|
||||
}
|
||||
typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
|
||||
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_base_without_enum(type_info_of(id));
|
||||
return ti.id;
|
||||
}
|
||||
typeid_base_without_enum :: typeid_core;
|
||||
|
||||
|
||||
|
||||
@@ -384,7 +412,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
|
||||
@builtin
|
||||
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
|
||||
if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -395,7 +423,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
||||
if array == nil do return E{};
|
||||
assert(len(array) > 0);
|
||||
res := array[len(array)-1];
|
||||
(^mem.Raw_Dynamic_Array)(array).len -= 1;
|
||||
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -459,14 +487,11 @@ make :: proc{
|
||||
mem.make_map,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@builtin
|
||||
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
if m == nil do return;
|
||||
raw_map := (^mem.Raw_Map)(m);
|
||||
entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
|
||||
raw_map := (^Raw_Map)(m);
|
||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries);
|
||||
entries.len = 0;
|
||||
for _, i in raw_map.hashes {
|
||||
raw_map.hashes[i] = -1;
|
||||
@@ -497,10 +522,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
if arg_len > 0 {
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
data := (^E)(a.data);
|
||||
assert(data != nil);
|
||||
mem.copy(mem.ptr_offset(data, a.len), &arg, size_of(E));
|
||||
val := arg;
|
||||
mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E));
|
||||
a.len += arg_len;
|
||||
}
|
||||
}
|
||||
@@ -518,10 +544,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
if arg_len > 0 {
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
data := (^E)(a.data);
|
||||
assert(data != nil);
|
||||
mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
|
||||
mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
|
||||
a.len += arg_len;
|
||||
}
|
||||
}
|
||||
@@ -538,13 +564,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
|
||||
|
||||
@builtin
|
||||
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
|
||||
if array != nil do (^Raw_Dynamic_Array)(array).len = 0;
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
if array == nil do return false;
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
|
||||
if capacity <= a.cap do return true;
|
||||
|
||||
@@ -571,7 +597,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
||||
@builtin
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||
if array == nil do return false;
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
a := (^Raw_Dynamic_Array)(array);
|
||||
|
||||
if length <= a.cap {
|
||||
a.len = max(length, 0);
|
||||
@@ -664,11 +690,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
||||
@builtin
|
||||
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
|
||||
if !condition {
|
||||
p := context.assertion_failure_proc;
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
}
|
||||
p("Runtime assertion", message, loc);
|
||||
proc(message: string, loc: Source_Code_Location) {
|
||||
p := context.assertion_failure_proc;
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
}
|
||||
p("runtime assertion", message, loc);
|
||||
}(message, loc);
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
@@ -679,7 +707,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
|
||||
if p == nil {
|
||||
p = default_assertion_failure_proc;
|
||||
}
|
||||
p("Panic", message, loc);
|
||||
p("panic", message, loc);
|
||||
}
|
||||
|
||||
@builtin
|
||||
@@ -709,7 +737,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! {
|
||||
|
||||
|
||||
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
array.allocator = context.allocator;
|
||||
assert(array.allocator.procedure != nil);
|
||||
|
||||
@@ -720,7 +748,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca
|
||||
}
|
||||
|
||||
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
if cap <= array.cap do return true;
|
||||
|
||||
@@ -742,7 +770,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
|
||||
}
|
||||
|
||||
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
|
||||
if ok do array.len = len;
|
||||
@@ -752,7 +780,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
|
||||
|
||||
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
items: rawptr, item_count: int, loc := #caller_location) -> int {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
if items == nil do return 0;
|
||||
if item_count <= 0 do return 0;
|
||||
@@ -769,13 +797,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
assert(array.data != nil);
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||
|
||||
mem.copy(rawptr(data), items, elem_size * item_count);
|
||||
mem_copy(rawptr(data), items, elem_size * item_count);
|
||||
array.len += item_count;
|
||||
return array.len;
|
||||
}
|
||||
|
||||
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array := (^Raw_Dynamic_Array)(array_);
|
||||
|
||||
ok := true;
|
||||
if array.cap <= array.len+1 {
|
||||
@@ -798,15 +826,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
||||
// Map
|
||||
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header := Map_Header{m = (^mem.Raw_Map)(m)};
|
||||
header := Map_Header{m = (^Raw_Map)(m)};
|
||||
Entry :: struct {
|
||||
key: Map_Key,
|
||||
next: int,
|
||||
value: V,
|
||||
}
|
||||
};
|
||||
|
||||
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
|
||||
header.is_key_string = is_string;
|
||||
header.is_key_string = intrinsics.type_is_string(K);
|
||||
header.entry_size = int(size_of(Entry));
|
||||
header.entry_align = int(align_of(Entry));
|
||||
header.value_offset = uintptr(offset_of(Entry, value));
|
||||
@@ -814,35 +841,37 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
return header;
|
||||
}
|
||||
|
||||
__get_map_key :: proc "contextless" (key: $K) -> Map_Key {
|
||||
__get_map_key :: proc "contextless" (k: $K) -> Map_Key {
|
||||
key := k;
|
||||
map_key: Map_Key;
|
||||
ti := type_info_base_without_enum(type_info_of(K));
|
||||
switch _ in ti.variant {
|
||||
case Type_Info_Integer:
|
||||
switch 8*size_of(key) {
|
||||
case 8: map_key.hash = u64(( ^u8)(&key)^);
|
||||
case 16: map_key.hash = u64(( ^u16)(&key)^);
|
||||
case 32: map_key.hash = u64(( ^u32)(&key)^);
|
||||
case 64: map_key.hash = u64(( ^u64)(&key)^);
|
||||
case: panic("Unhandled integer size");
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
|
||||
T :: intrinsics.type_core_type(K);
|
||||
|
||||
when intrinsics.type_is_integer(T) {
|
||||
sz :: 8*size_of(T);
|
||||
when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
|
||||
else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
|
||||
else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
|
||||
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
|
||||
else do #assert(false, "Unhandled integer size");
|
||||
} else when intrinsics.type_is_rune(T) {
|
||||
map_key.hash = u64((^rune)(&key)^);
|
||||
case Type_Info_Pointer:
|
||||
} else when intrinsics.type_is_pointer(T) {
|
||||
map_key.hash = u64(uintptr((^rawptr)(&key)^));
|
||||
case Type_Info_Float:
|
||||
switch 8*size_of(key) {
|
||||
case 32: map_key.hash = u64((^u32)(&key)^);
|
||||
case 64: map_key.hash = u64((^u64)(&key)^);
|
||||
case: panic("Unhandled float size");
|
||||
}
|
||||
case Type_Info_String:
|
||||
} else when intrinsics.type_is_float(T) {
|
||||
sz :: 8*size_of(T);
|
||||
when sz == 32 do map_key.hash = u64((^u32)(&key)^);
|
||||
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
|
||||
else do #assert(false, "Unhandled float size");
|
||||
} else when intrinsics.type_is_string(T) {
|
||||
#assert(T == string);
|
||||
str := (^string)(&key)^;
|
||||
map_key.hash = default_hash_string(str);
|
||||
map_key.str = str;
|
||||
case:
|
||||
panic("Unhandled map key type");
|
||||
} else {
|
||||
#assert(false, "Unhandled map key type");
|
||||
}
|
||||
|
||||
return map_key;
|
||||
}
|
||||
|
||||
@@ -871,7 +900,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
||||
|
||||
|
||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Slice)(array_);
|
||||
array := (^Raw_Slice)(array_);
|
||||
|
||||
if new_count < array.len do return true;
|
||||
|
||||
@@ -897,7 +926,7 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller
|
||||
}
|
||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
|
||||
new_header: Map_Header = header;
|
||||
nm := mem.Raw_Map{};
|
||||
nm := Raw_Map{};
|
||||
nm.entries.allocator = m.entries.allocator;
|
||||
new_header.m = &nm;
|
||||
|
||||
@@ -929,7 +958,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c
|
||||
e := __dynamic_map_get_entry(new_header, j);
|
||||
e.next = fr.entry_index;
|
||||
ndata := uintptr(e);
|
||||
mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
|
||||
mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
|
||||
|
||||
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
|
||||
}
|
||||
@@ -972,7 +1001,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca
|
||||
e := __dynamic_map_get_entry(h, index);
|
||||
e.key = key;
|
||||
val := (^byte)(uintptr(e) + h.value_offset);
|
||||
mem.copy(val, value, h.value_size);
|
||||
mem_copy(val, value, h.value_size);
|
||||
}
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
@@ -1051,7 +1080,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
|
||||
} else {
|
||||
old := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
end := __dynamic_map_get_entry(h, m.entries.len-1);
|
||||
mem.copy(old, end, entry_size);
|
||||
mem_copy(old, end, entry_size);
|
||||
|
||||
if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
|
||||
|
||||
+262
-14
@@ -1,16 +1,46 @@
|
||||
package runtime
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memmove
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memmove(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
print_u64 :: proc(fd: os.Handle, u: u64) {
|
||||
mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memmove
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memmove(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
print_u64 :: proc(fd: os.Handle, x: u64) {
|
||||
digits := "0123456789";
|
||||
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
b := u64(10);
|
||||
u := x;
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
u /= b;
|
||||
@@ -20,10 +50,11 @@ print_u64 :: proc(fd: os.Handle, u: u64) {
|
||||
os.write(fd, a[i:]);
|
||||
}
|
||||
|
||||
print_i64 :: proc(fd: os.Handle, u: i64) {
|
||||
print_i64 :: proc(fd: os.Handle, x: i64) {
|
||||
digits := "0123456789";
|
||||
b :: i64(10);
|
||||
|
||||
u := x;
|
||||
neg := u < 0;
|
||||
u = abs(u);
|
||||
|
||||
@@ -241,6 +272,78 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
||||
}
|
||||
}
|
||||
|
||||
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
|
||||
x := uintptr(a);
|
||||
y := uintptr(b);
|
||||
n := uintptr(n);
|
||||
|
||||
SU :: size_of(uintptr);
|
||||
fast := uintptr(n/SU + 1);
|
||||
offset := (fast-1)*SU;
|
||||
curr_block := uintptr(0);
|
||||
if n < SU {
|
||||
fast = 0;
|
||||
}
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
|
||||
vb := (^uintptr)(y + curr_block * size_of(uintptr))^;
|
||||
if va ~ vb != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
a := (^byte)(x+pos)^;
|
||||
b := (^byte)(y+pos)^;
|
||||
if a ~ b != 0 {
|
||||
return (int(a) - int(b)) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
a := (^byte)(x+offset)^;
|
||||
b := (^byte)(y+offset)^;
|
||||
if a ~ b != 0 {
|
||||
return (int(a) - int(b)) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
|
||||
x := uintptr(a);
|
||||
n := uintptr(n);
|
||||
|
||||
SU :: size_of(uintptr);
|
||||
fast := uintptr(n/SU + 1);
|
||||
offset := (fast-1)*SU;
|
||||
curr_block := uintptr(0);
|
||||
if n < SU {
|
||||
fast = 0;
|
||||
}
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
|
||||
if va ~ 0 != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
a := (^byte)(x+pos)^;
|
||||
if a ~ 0 != 0 {
|
||||
return int(a) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
a := (^byte)(x+offset)^;
|
||||
if a ~ 0 != 0 {
|
||||
return int(a) < 0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||
switch {
|
||||
case len(a) != len(b): return false;
|
||||
@@ -251,7 +354,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||
}
|
||||
|
||||
string_cmp :: proc "contextless" (a, b: string) -> int {
|
||||
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
return memory_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
|
||||
string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
|
||||
@@ -261,18 +364,23 @@ string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cm
|
||||
string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
|
||||
|
||||
cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||
n := 0;
|
||||
for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) {
|
||||
n += 1;
|
||||
p0 := uintptr((^byte)(s));
|
||||
p := p0;
|
||||
for p != 0 && (^byte)(p)^ != 0 {
|
||||
p += 1;
|
||||
}
|
||||
return n;
|
||||
return int(p - p0);
|
||||
}
|
||||
|
||||
cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
Raw_String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
};
|
||||
if s == nil do return "";
|
||||
ptr := (^byte)(s);
|
||||
n := cstring_len(s);
|
||||
return transmute(string)mem.Raw_String{ptr, n};
|
||||
return transmute(string)Raw_String{ptr, n};
|
||||
}
|
||||
|
||||
|
||||
@@ -283,6 +391,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r
|
||||
complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
|
||||
|
||||
|
||||
quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
|
||||
quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
|
||||
|
||||
quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
|
||||
quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
|
||||
|
||||
|
||||
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
|
||||
@@ -356,8 +469,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
|
||||
handle_error(file, line, column, from, to);
|
||||
}
|
||||
|
||||
|
||||
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
|
||||
return utf8.decode_rune_in_string(s);
|
||||
// NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
|
||||
|
||||
@static accept_sizes := [256]u8{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
||||
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
|
||||
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
};
|
||||
Accept_Range :: struct {lo, hi: u8};
|
||||
|
||||
@static accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0xbf},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
{0x90, 0xbf},
|
||||
{0x80, 0x8f},
|
||||
};
|
||||
|
||||
MASKX :: 0b0011_1111;
|
||||
MASK2 :: 0b0001_1111;
|
||||
MASK3 :: 0b0000_1111;
|
||||
MASK4 :: 0b0000_0111;
|
||||
|
||||
LOCB :: 0b1000_0000;
|
||||
HICB :: 0b1011_1111;
|
||||
|
||||
|
||||
RUNE_ERROR :: '\ufffd';
|
||||
|
||||
n := len(s);
|
||||
if n < 1 {
|
||||
return RUNE_ERROR, 0;
|
||||
}
|
||||
s0 := s[0];
|
||||
x := accept_sizes[s0];
|
||||
if x >= 0xF0 {
|
||||
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
|
||||
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
|
||||
}
|
||||
sz := x & 7;
|
||||
accept := accept_ranges[x>>4];
|
||||
if n < int(sz) {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
b1 := s[1];
|
||||
if b1 < accept.lo || accept.hi < b1 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if sz == 2 {
|
||||
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
|
||||
}
|
||||
b2 := s[2];
|
||||
if b2 < LOCB || HICB < b2 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
if sz == 3 {
|
||||
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
|
||||
}
|
||||
b3 := s[3];
|
||||
if b3 < LOCB || HICB < b3 {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
|
||||
}
|
||||
|
||||
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
|
||||
@@ -472,9 +661,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
|
||||
r, i := real(x), imag(x);
|
||||
return _sqrt_f64(r*r + i*i);
|
||||
}
|
||||
abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
|
||||
return _sqrt_f32(r*r + i*i + j*j + k*k);
|
||||
}
|
||||
abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
|
||||
return _sqrt_f64(r*r + i*i + j*j + k*k);
|
||||
}
|
||||
|
||||
|
||||
quo_complex64 :: proc(n, m: complex64) -> complex64 {
|
||||
quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
|
||||
e, f: f32;
|
||||
|
||||
if abs(real(m)) >= abs(imag(m)) {
|
||||
@@ -492,7 +688,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
|
||||
return complex(e, f);
|
||||
}
|
||||
|
||||
quo_complex128 :: proc(n, m: complex128) -> complex128 {
|
||||
quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
|
||||
e, f: f64;
|
||||
|
||||
if abs(real(m)) >= abs(imag(m)) {
|
||||
@@ -509,3 +705,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
|
||||
|
||||
return complex(e, f);
|
||||
}
|
||||
|
||||
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
|
||||
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
|
||||
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
|
||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
|
||||
|
||||
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
|
||||
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
|
||||
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
|
||||
|
||||
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
|
||||
|
||||
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
|
||||
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
|
||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
|
||||
|
||||
return quaternion(t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,6 +1,7 @@
|
||||
package sort
|
||||
|
||||
import "core:mem"
|
||||
import "intrinsics"
|
||||
|
||||
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
@@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
}
|
||||
}
|
||||
|
||||
bubble_sort :: proc(array: $A/[]$T) {
|
||||
bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
count := len(array);
|
||||
|
||||
init_j, last_j := 0, count-1;
|
||||
@@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
quick_sort_proc(a[i:n], f);
|
||||
}
|
||||
|
||||
quick_sort :: proc(array: $A/[]$T) {
|
||||
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
a := array;
|
||||
n := len(a);
|
||||
if n < 2 do return;
|
||||
@@ -96,9 +97,9 @@ quick_sort :: proc(array: $A/[]$T) {
|
||||
quick_sort(a[i:n]);
|
||||
}
|
||||
|
||||
_log2 :: proc(n: int) -> int {
|
||||
_log2 :: proc(x: int) -> int {
|
||||
res := 0;
|
||||
for ; n != 0; n >>= 1 do res += 1;
|
||||
for n := x; n != 0; n >>= 1 do res += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
if M & 1 == 0 do copy(arr2, arr1);
|
||||
}
|
||||
|
||||
merge_sort :: proc(array: $A/[]$T) {
|
||||
merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||
merge_slices :: proc(arr1, arr2, out: A) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Multiple precision decimal numbers
|
||||
// NOTE: This is only for floating point printing and nothing else
|
||||
package decimal
|
||||
package strconv_decimal
|
||||
|
||||
Decimal :: struct {
|
||||
digits: [384]byte, // big-endian digits
|
||||
@@ -20,29 +20,29 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||
|
||||
// TODO(bill): make this work with a buffer that's not big enough
|
||||
assert(len(buf) >= n);
|
||||
buf = buf[0:n];
|
||||
b := buf[0:n];
|
||||
|
||||
if a.count == 0 {
|
||||
buf[0] = '0';
|
||||
return string(buf[0:1]);
|
||||
b[0] = '0';
|
||||
return string(b[0:1]);
|
||||
}
|
||||
|
||||
w := 0;
|
||||
if a.decimal_point <= 0 {
|
||||
buf[w] = '0'; w += 1;
|
||||
buf[w] = '.'; w += 1;
|
||||
w += digit_zero(buf[w : w-a.decimal_point]);
|
||||
w += copy(buf[w:], a.digits[0:a.count]);
|
||||
b[w] = '0'; w += 1;
|
||||
b[w] = '.'; w += 1;
|
||||
w += digit_zero(b[w : w-a.decimal_point]);
|
||||
w += copy(b[w:], a.digits[0:a.count]);
|
||||
} else if a.decimal_point < a.count {
|
||||
w += copy(buf[w:], a.digits[0:a.decimal_point]);
|
||||
buf[w] = '.'; w += 1;
|
||||
w += copy(buf[w:], a.digits[a.decimal_point : a.count]);
|
||||
w += copy(b[w:], a.digits[0:a.decimal_point]);
|
||||
b[w] = '.'; w += 1;
|
||||
w += copy(b[w:], a.digits[a.decimal_point : a.count]);
|
||||
} else {
|
||||
w += copy(buf[w:], a.digits[0:a.count]);
|
||||
w += digit_zero(buf[w : w+a.decimal_point-a.count]);
|
||||
w += copy(b[w:], a.digits[0:a.count]);
|
||||
w += digit_zero(b[w : w+a.decimal_point-a.count]);
|
||||
}
|
||||
|
||||
return string(buf[0:w]);
|
||||
return string(b[0:w]);
|
||||
}
|
||||
|
||||
// trim trailing zeros
|
||||
@@ -56,10 +56,10 @@ trim :: proc(a: ^Decimal) {
|
||||
}
|
||||
|
||||
|
||||
assign :: proc(a: ^Decimal, i: u64) {
|
||||
assign :: proc(a: ^Decimal, idx: u64) {
|
||||
buf: [64]byte;
|
||||
n := 0;
|
||||
for i > 0 {
|
||||
for i := idx; i > 0; {
|
||||
j := i/10;
|
||||
i -= 10*j;
|
||||
buf[n] = byte('0'+i);
|
||||
@@ -175,11 +175,11 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
trim(a);
|
||||
}
|
||||
|
||||
shift :: proc(a: ^Decimal, k: int) {
|
||||
shift :: proc(a: ^Decimal, i: int) {
|
||||
uint_size :: 8*size_of(uint);
|
||||
max_shift :: uint_size-4;
|
||||
|
||||
switch {
|
||||
switch k := i; {
|
||||
case a.count == 0:
|
||||
// no need to update
|
||||
case k > 0:
|
||||
@@ -1,6 +1,6 @@
|
||||
package strconv
|
||||
|
||||
using import "core:decimal"
|
||||
using import "decimal"
|
||||
|
||||
Int_Flag :: enum {
|
||||
Prefix,
|
||||
@@ -28,7 +28,7 @@ _f32_info := Float_Info{23, 8, -127};
|
||||
_f64_info := Float_Info{52, 11, -1023};
|
||||
|
||||
|
||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
|
||||
bits: u64;
|
||||
flt: ^Float_Info;
|
||||
switch bit_size {
|
||||
@@ -73,6 +73,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
assign(d, mant);
|
||||
shift(d, exp - int(flt.mantbits));
|
||||
digs: Decimal_Slice;
|
||||
prec := precision;
|
||||
shortest := prec < 0;
|
||||
if shortest {
|
||||
round_shortest(d, mant, exp, flt);
|
||||
@@ -100,11 +101,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
|
||||
|
||||
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte {
|
||||
Buffer :: struct {
|
||||
b: []byte,
|
||||
n: int,
|
||||
}
|
||||
};
|
||||
|
||||
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
|
||||
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
|
||||
@@ -112,6 +113,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
|
||||
}
|
||||
|
||||
b := Buffer{b = buf};
|
||||
prec := precision;
|
||||
|
||||
switch fmt {
|
||||
case 'f', 'F':
|
||||
@@ -289,7 +291,8 @@ MAX_BASE :: 32;
|
||||
digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
|
||||
is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
|
||||
is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64, neg: bool) {
|
||||
u = x;
|
||||
if is_signed {
|
||||
switch bit_size {
|
||||
case 8:
|
||||
@@ -312,18 +315,17 @@ is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned
|
||||
panic("is_integer_negative: Unknown integer size");
|
||||
}
|
||||
}
|
||||
return u, neg;
|
||||
return;
|
||||
}
|
||||
|
||||
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits");
|
||||
}
|
||||
|
||||
neg: bool;
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
u, neg = is_integer_negative(u, is_signed, bit_size);
|
||||
u, neg := is_integer_negative(x, is_signed, bit_size);
|
||||
b := u64(base);
|
||||
for u >= b {
|
||||
i-=1; a[i] = digits[u % b];
|
||||
@@ -360,7 +362,8 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
||||
return string(buf[0:len(out)]);
|
||||
}
|
||||
|
||||
is_integer_negative_128 :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
|
||||
is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u: u128, neg: bool) {
|
||||
u = x;
|
||||
if is_signed {
|
||||
switch bit_size {
|
||||
case 8:
|
||||
@@ -387,19 +390,18 @@ is_integer_negative_128 :: proc(u: u128, is_signed: bool, bit_size: int) -> (uns
|
||||
panic("is_integer_negative: Unknown integer size");
|
||||
}
|
||||
}
|
||||
return u, neg;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
append_bits_128 :: proc(buf: []byte, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits");
|
||||
}
|
||||
|
||||
neg: bool;
|
||||
a: [140]byte;
|
||||
i := len(a);
|
||||
u, neg = is_integer_negative_128(u, is_signed, bit_size);
|
||||
u, neg := is_integer_negative_128(x, is_signed, bit_size);
|
||||
b := u128(base);
|
||||
for u >= b {
|
||||
i-=1; a[i] = digits[u % b];
|
||||
|
||||
@@ -23,7 +23,8 @@ _digit_value :: proc(r: rune) -> int {
|
||||
return v;
|
||||
}
|
||||
|
||||
parse_i64 :: proc(s: string) -> i64 {
|
||||
parse_i64 :: proc(str: string) -> i64 {
|
||||
s := str;
|
||||
neg := false;
|
||||
if len(s) > 1 {
|
||||
switch s[0] {
|
||||
@@ -66,7 +67,8 @@ parse_i64 :: proc(s: string) -> i64 {
|
||||
return value;
|
||||
}
|
||||
|
||||
parse_u64 :: proc(s: string) -> u64 {
|
||||
parse_u64 :: proc(str: string) -> u64 {
|
||||
s := str;
|
||||
neg := false;
|
||||
if len(s) > 1 && s[0] == '+' {
|
||||
s = s[1:];
|
||||
@@ -203,13 +205,17 @@ itoa :: proc(buf: []byte, i: int) -> string {
|
||||
atoi :: proc(s: string) -> int {
|
||||
return parse_int(s);
|
||||
}
|
||||
atof :: proc(s: string) -> f64 {
|
||||
return parse_f64(s);
|
||||
}
|
||||
|
||||
ftoa :: append_float;
|
||||
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
||||
}
|
||||
|
||||
|
||||
quote :: proc(buf: []byte, s: string) -> string {
|
||||
quote :: proc(buf: []byte, str: string) -> string {
|
||||
write_byte :: inline proc(buf: []byte, i: ^int, bytes: ..byte) {
|
||||
if i^ >= len(buf) do return;
|
||||
n := copy(buf[i^:], bytes[:]);
|
||||
@@ -222,6 +228,7 @@ quote :: proc(buf: []byte, s: string) -> string {
|
||||
|
||||
c :: '"';
|
||||
i := 0;
|
||||
s := str;
|
||||
|
||||
write_byte(buf, &i, c);
|
||||
for width := 0; len(s) > 0; s = s[width:] {
|
||||
|
||||
+15
-11
@@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) {
|
||||
reserve(&b.buf, cap);
|
||||
}
|
||||
|
||||
reset_builder :: proc(b: ^Builder) {
|
||||
clear(&b.buf);
|
||||
}
|
||||
|
||||
builder_from_slice :: proc(backing: []byte) -> Builder {
|
||||
s := transmute(mem.Raw_Slice)backing;
|
||||
d := mem.Raw_Dynamic_Array{
|
||||
@@ -68,9 +72,9 @@ write_bytes :: proc(b: ^Builder, x: []byte) {
|
||||
@(private, static)
|
||||
DIGITS_LOWER := "0123456789abcdefx";
|
||||
|
||||
write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') {
|
||||
write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') {
|
||||
write_byte(b, quote);
|
||||
for width := 0; len(s) > 0; s = s[width:] {
|
||||
for width, s := 0, str; len(s) > 0; s = s[width:] {
|
||||
r := rune(s[0]);
|
||||
width = 1;
|
||||
if r >= utf8.RUNE_SELF {
|
||||
@@ -166,27 +170,27 @@ write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false
|
||||
case '\t': write_string(b, `\t`);
|
||||
case '\v': write_string(b, `\v`);
|
||||
case:
|
||||
switch {
|
||||
case r < ' ':
|
||||
switch c := r; {
|
||||
case c < ' ':
|
||||
write_byte(b, '\\');
|
||||
write_byte(b, 'x');
|
||||
write_byte(b, DIGITS_LOWER[byte(r)>>4]);
|
||||
write_byte(b, DIGITS_LOWER[byte(r)&0xf]);
|
||||
write_byte(b, DIGITS_LOWER[byte(c)>>4]);
|
||||
write_byte(b, DIGITS_LOWER[byte(c)&0xf]);
|
||||
|
||||
case r > utf8.MAX_RUNE:
|
||||
r = 0xfffd;
|
||||
case c > utf8.MAX_RUNE:
|
||||
c = 0xfffd;
|
||||
fallthrough;
|
||||
case r < 0x10000:
|
||||
case c < 0x10000:
|
||||
write_byte(b, '\\');
|
||||
write_byte(b, 'u');
|
||||
for s := 12; s >= 0; s -= 4 {
|
||||
write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
|
||||
write_byte(b, DIGITS_LOWER[c>>uint(s) & 0xf]);
|
||||
}
|
||||
case:
|
||||
write_byte(b, '\\');
|
||||
write_byte(b, 'U');
|
||||
for s := 28; s >= 0; s -= 4 {
|
||||
write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
|
||||
write_byte(b, DIGITS_LOWER[c>>uint(s) & 0xf]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+173
-21
@@ -67,7 +67,8 @@ rune_count :: proc(s: string) -> int {
|
||||
}
|
||||
|
||||
|
||||
equal_fold :: proc(s, t: string) -> bool {
|
||||
equal_fold :: proc(u, v: string) -> bool {
|
||||
s, t := u, v;
|
||||
loop: for s != "" && t != "" {
|
||||
sr, tr: rune;
|
||||
if s[0] < utf8.RUNE_SELF {
|
||||
@@ -154,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
|
||||
return string(b);
|
||||
}
|
||||
|
||||
@private
|
||||
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
|
||||
s, n := s_, n_;
|
||||
|
||||
if n == 0 {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if sep == "" {
|
||||
l := utf8.rune_count_in_string(s);
|
||||
if n < 0 || n > l {
|
||||
n = l;
|
||||
}
|
||||
|
||||
res := make([dynamic]string, n, allocator);
|
||||
for i := 0; i < n-1; i += 1 {
|
||||
_, w := utf8.decode_rune_in_string(s);
|
||||
res[i] = s[:w];
|
||||
s = s[w:];
|
||||
}
|
||||
if n > 0 {
|
||||
res[n-1] = s;
|
||||
}
|
||||
return res[:];
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
n = count(s, sep) + 1;
|
||||
}
|
||||
|
||||
res := make([dynamic]string, n, allocator);
|
||||
|
||||
n -= 1;
|
||||
|
||||
i := 0;
|
||||
for ; i < n; i += 1 {
|
||||
m := index(s, sep);
|
||||
if m < 0 {
|
||||
break;
|
||||
}
|
||||
res[i] = s[:m+sep_save];
|
||||
s = s[m+len(sep):];
|
||||
}
|
||||
res[i] = s;
|
||||
|
||||
return res[:i+1];
|
||||
}
|
||||
|
||||
split :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, 0, -1, allocator);
|
||||
}
|
||||
|
||||
split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, 0, n, allocator);
|
||||
}
|
||||
|
||||
split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, len(sep), -1, allocator);
|
||||
}
|
||||
|
||||
split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
|
||||
return _split(s, sep, len(sep), n, allocator);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
index_byte :: proc(s: string, c: byte) -> int {
|
||||
for i := 0; i < len(s); i += 1 {
|
||||
if s[i] == c do return i;
|
||||
@@ -169,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@private PRIME_RABIN_KARP :: 16777619;
|
||||
|
||||
index :: proc(s, substr: string) -> int {
|
||||
hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
|
||||
for i := 0; i < len(s); i += 1 {
|
||||
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
sq := u32(PRIME_RABIN_KARP);
|
||||
for i := len(s); i > 0; i >>= 1 {
|
||||
if (i & 1) != 0 {
|
||||
pow *= sq;
|
||||
}
|
||||
sq *= sq;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n := len(substr);
|
||||
switch {
|
||||
case n == 0:
|
||||
@@ -185,9 +271,68 @@ index :: proc(s, substr: string) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for i := 0; i < len(s)-n+1; i += 1 {
|
||||
x := s[i:i+n];
|
||||
if x == substr {
|
||||
hash, pow := hash_str_rabin_karp(substr);
|
||||
h: u32;
|
||||
for i := 0; i < n; i += 1 {
|
||||
h = h*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
if h == hash && s[:n] == substr {
|
||||
return 0;
|
||||
}
|
||||
for i := n; i < len(s); /**/ {
|
||||
h *= PRIME_RABIN_KARP;
|
||||
h += u32(s[i]);
|
||||
h -= pow * u32(s[i-n]);
|
||||
i += 1;
|
||||
if h == hash && s[i-n:i] == substr {
|
||||
return i - n;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
last_index :: proc(s, substr: string) -> int {
|
||||
hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
|
||||
for i := len(s) - 1; i >= 0; i -= 1 {
|
||||
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
sq := u32(PRIME_RABIN_KARP);
|
||||
for i := len(s); i > 0; i >>= 1 {
|
||||
if (i & 1) != 0 {
|
||||
pow *= sq;
|
||||
}
|
||||
sq *= sq;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n := len(substr);
|
||||
switch {
|
||||
case n == 0:
|
||||
return len(s);
|
||||
case n == 1:
|
||||
return last_index_byte(s, substr[0]);
|
||||
case n == len(s):
|
||||
return substr == s ? 0 : -1;
|
||||
case n > len(s):
|
||||
return -1;
|
||||
}
|
||||
|
||||
hash, pow := hash_str_rabin_karp_reverse(substr);
|
||||
last := len(s) - n;
|
||||
h: u32;
|
||||
for i := len(s)-1; i >= last; i -= 1 {
|
||||
h = h*PRIME_RABIN_KARP + u32(s[i]);
|
||||
}
|
||||
if h == hash && s[last:] == substr {
|
||||
return last;
|
||||
}
|
||||
|
||||
for i := last-1; i >= 0; i -= 1 {
|
||||
h *= PRIME_RABIN_KARP;
|
||||
h += u32(s[i]);
|
||||
h -= pow * u32(s[i+n]);
|
||||
if h == hash && s[i:i+n] == substr {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -250,13 +395,14 @@ count :: proc(s, substr: string) -> int {
|
||||
|
||||
// TODO(bill): Use a non-brute for approach
|
||||
n := 0;
|
||||
str := s;
|
||||
for {
|
||||
i := index(s, substr);
|
||||
i := index(str, substr);
|
||||
if i == -1 {
|
||||
return n;
|
||||
}
|
||||
n += 1;
|
||||
s = s[i+len(substr):];
|
||||
str = str[i+len(substr):];
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@@ -289,22 +435,22 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator) ->
|
||||
output = s;
|
||||
return;
|
||||
}
|
||||
|
||||
byte_count := n;
|
||||
if m := count(s, old); m == 0 {
|
||||
was_allocation = false;
|
||||
output = s;
|
||||
return;
|
||||
} else if n < 0 || m < n {
|
||||
n = m;
|
||||
byte_count = m;
|
||||
}
|
||||
|
||||
|
||||
t := make([]byte, len(s) + n*(len(new) - len(old)), allocator);
|
||||
t := make([]byte, len(s) + byte_count*(len(new) - len(old)), allocator);
|
||||
was_allocation = true;
|
||||
|
||||
w := 0;
|
||||
start := 0;
|
||||
for i := 0; i < n; i += 1 {
|
||||
for i := 0; i < byte_count; i += 1 {
|
||||
j := start;
|
||||
if len(old) == 0 {
|
||||
if i > 0 {
|
||||
@@ -475,14 +621,16 @@ trim_left :: proc(s: string, cutset: string) -> string {
|
||||
if s == "" || cutset == "" {
|
||||
return s;
|
||||
}
|
||||
return trim_left_proc_with_state(s, is_in_cutset, &cutset);
|
||||
state := cutset;
|
||||
return trim_left_proc_with_state(s, is_in_cutset, &state);
|
||||
}
|
||||
|
||||
trim_right :: proc(s: string, cutset: string) -> string {
|
||||
if s == "" || cutset == "" {
|
||||
return s;
|
||||
}
|
||||
return trim_right_proc_with_state(s, is_in_cutset, &cutset);
|
||||
state := cutset;
|
||||
return trim_right_proc_with_state(s, is_in_cutset, &state);
|
||||
}
|
||||
|
||||
trim :: proc(s: string, cutset: string) -> string {
|
||||
@@ -515,7 +663,8 @@ trim_null :: proc(s: string) -> string {
|
||||
|
||||
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
|
||||
// Adjacent invalid bytes are only replaced once
|
||||
scrub :: proc(str: string, replacement: string, allocator := context.allocator) -> string {
|
||||
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {
|
||||
str := s;
|
||||
b := make_builder(allocator);;
|
||||
grow_builder(&b, len(str));
|
||||
|
||||
@@ -547,7 +696,8 @@ scrub :: proc(str: string, replacement: string, allocator := context.allocator)
|
||||
}
|
||||
|
||||
|
||||
reverse :: proc(str: string, allocator := context.allocator) -> string {
|
||||
reverse :: proc(s: string, allocator := context.allocator) -> string {
|
||||
str := s;
|
||||
n := len(str);
|
||||
buf := make([]byte, n);
|
||||
i := 0;
|
||||
@@ -560,17 +710,18 @@ reverse :: proc(str: string, allocator := context.allocator) -> string {
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
expand_tabs :: proc(str: string, tab_size: int, allocator := context.allocator) -> string {
|
||||
expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> string {
|
||||
if tab_size <= 0 {
|
||||
panic("tab size must be positive");
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
|
||||
if s == "" {
|
||||
return "";
|
||||
}
|
||||
|
||||
b := make_builder(allocator);
|
||||
|
||||
str := s;
|
||||
column: int;
|
||||
|
||||
for len(str) > 0 {
|
||||
@@ -683,11 +834,12 @@ write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) {
|
||||
write_string(b, pad);
|
||||
}
|
||||
|
||||
remains = remains % pad_len;
|
||||
n := remains % pad_len;
|
||||
p := pad;
|
||||
|
||||
if remains != 0 do for i := 0; i < remains; i += 1 {
|
||||
r, w := utf8.decode_rune_in_string(pad);
|
||||
for i := 0; i < n; i += 1 {
|
||||
r, w := utf8.decode_rune_in_string(p);
|
||||
write_rune(b, r);
|
||||
pad = pad[w:];
|
||||
p = p[w:];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,6 @@ _open_file_dialog :: proc(title: string, dir: string,
|
||||
// Filters need to be passed as a pair of strings (title, filter)
|
||||
filter_len := u32(len(filters));
|
||||
if filter_len % 2 != 0 do return "", false;
|
||||
default_filter = clamp(default_filter, 1, filter_len / 2);
|
||||
|
||||
filter: string;
|
||||
filter = strings.join(filters, "\u0000", context.temp_allocator);
|
||||
@@ -102,7 +101,7 @@ _open_file_dialog :: proc(title: string, dir: string,
|
||||
title = utf8_to_wstring(title, context.temp_allocator),
|
||||
filter = utf8_to_wstring(filter, context.temp_allocator),
|
||||
initial_dir = utf8_to_wstring(dir, context.temp_allocator),
|
||||
filter_index = u32(default_filter),
|
||||
filter_index = u32(clamp(default_filter, 1, filter_len / 2)),
|
||||
def_ext = utf8_to_wstring(default_ext, context.temp_allocator),
|
||||
flags = u32(flags),
|
||||
};
|
||||
@@ -121,7 +120,7 @@ _open_file_dialog :: proc(title: string, dir: string,
|
||||
return "", false;
|
||||
}
|
||||
|
||||
file_name := ucs2_to_utf8(file_buf[:], allocator);
|
||||
file_name := utf16_to_utf8(file_buf[:], allocator);
|
||||
path = strings.trim_right_null(file_name);
|
||||
return;
|
||||
}
|
||||
@@ -143,7 +142,7 @@ select_file_to_save :: proc(title := SAVE_TITLE, dir := ".",
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
|
||||
// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
|
||||
// it output of the form "path\u0000\file1u\0000file2" and turns it into []string with the path + file pre-concatenated for you.
|
||||
|
||||
OFN_ALLOWMULTISELECT :: 0x00000200; // NOTE(Jeroen): Without OFN_EXPLORER it uses the Win3 dialog.
|
||||
@@ -186,4 +185,4 @@ CDERR_LOCKRESFAILURE :: 0x00000008;
|
||||
CDERR_MEMALLOCFAILURE :: 0x00000009;
|
||||
CDERR_MEMLOCKFAILURE :: 0x0000000A;
|
||||
CDERR_NOHOOK :: 0x0000000B;
|
||||
CDERR_REGISTERMSGFAIL :: 0x0000000C;
|
||||
CDERR_REGISTERMSGFAIL :: 0x0000000C;
|
||||
|
||||
@@ -9,6 +9,6 @@ foreign {
|
||||
get_cwd :: proc(allocator := context.temp_allocator) -> string {
|
||||
buffer := make([]u16, MAX_PATH_WIDE, allocator);
|
||||
_get_cwd_wide(Wstring(&buffer[0]), MAX_PATH_WIDE);
|
||||
file := ucs2_to_utf8(buffer[:], allocator);
|
||||
file := utf16_to_utf8(buffer[:], allocator);
|
||||
return strings.trim_right_null(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -728,7 +728,7 @@ CP_UTF8 :: 65001; // UTF-8 translation
|
||||
MB_ERR_INVALID_CHARS :: 8;
|
||||
WC_ERR_INVALID_CHARS :: 128;
|
||||
|
||||
utf8_to_ucs2 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
|
||||
utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
|
||||
if len(s) < 1 {
|
||||
return nil;
|
||||
}
|
||||
@@ -751,13 +751,13 @@ utf8_to_ucs2 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
|
||||
return text[:len(text)-1];
|
||||
}
|
||||
utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> Wstring {
|
||||
if res := utf8_to_ucs2(s, allocator); res != nil {
|
||||
if res := utf8_to_utf16(s, allocator); res != nil {
|
||||
return Wstring(&res[0]);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
ucs2_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> string {
|
||||
utf16_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> string {
|
||||
if len(s) < 1 {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ foreign kernel32 {
|
||||
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
|
||||
@(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
|
||||
|
||||
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
|
||||
@(link_name="Sleep") sleep :: proc(ms: u32) ---;
|
||||
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---;
|
||||
|
||||
@@ -182,7 +182,7 @@ foreign user32 {
|
||||
@(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
|
||||
|
||||
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
|
||||
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
|
||||
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---;
|
||||
@(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---;
|
||||
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package time
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
TimeSpec :: struct {
|
||||
tv_sec : i64, /* seconds */
|
||||
tv_nsec : i64, /* nanoseconds */
|
||||
};
|
||||
|
||||
CLOCK_SYSTEM :: 0;
|
||||
CLOCK_CALENDAR :: 1;
|
||||
|
||||
IS_SUPPORTED :: true;
|
||||
|
||||
foreign libc {
|
||||
@(link_name="clock_gettime") _clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) ---;
|
||||
@(link_name="nanosleep") _nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> int ---;
|
||||
@(link_name="sleep") _sleep :: proc(seconds: u64) -> int ---;
|
||||
}
|
||||
|
||||
clock_gettime :: proc(clock_id: u64) -> TimeSpec {
|
||||
ts : TimeSpec;
|
||||
_clock_gettime(clock_id, &ts);
|
||||
return ts;
|
||||
}
|
||||
|
||||
now :: proc() -> Time {
|
||||
|
||||
time_spec_now := clock_gettime(CLOCK_SYSTEM);
|
||||
ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec;
|
||||
return Time{_nsec=ns};
|
||||
}
|
||||
|
||||
seconds_since_boot :: proc() -> f64 {
|
||||
|
||||
ts_boottime := clock_gettime(CLOCK_SYSTEM);
|
||||
return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9;
|
||||
}
|
||||
|
||||
sleep :: proc(d: Duration) {
|
||||
|
||||
ds := duration_seconds(d);
|
||||
seconds := u64(ds);
|
||||
nanoseconds := i64((ds - f64(seconds)) * 1e9);
|
||||
|
||||
if seconds > 0 do _sleep(seconds);
|
||||
if nanoseconds > 0 do nanosleep(nanoseconds);
|
||||
}
|
||||
|
||||
nanosleep :: proc(nanoseconds: i64) -> int {
|
||||
assert(nanoseconds <= 999999999);
|
||||
requested, remaining : TimeSpec;
|
||||
requested = TimeSpec{tv_nsec = nanoseconds};
|
||||
|
||||
return _nanosleep(&requested, &remaining);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
package time
|
||||
IS_SUPPORTED :: false;
|
||||
@@ -1,3 +0,0 @@
|
||||
package time
|
||||
|
||||
IS_SUPPORTED :: false;
|
||||
@@ -20,5 +20,5 @@ now :: proc() -> Time {
|
||||
|
||||
|
||||
sleep :: proc(d: Duration) {
|
||||
win32.sleep(i32(d/Millisecond));
|
||||
win32.sleep(u32(d/Millisecond));
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ decode_surrogate_pair :: proc(r1, r2: rune) -> rune {
|
||||
}
|
||||
|
||||
|
||||
encode_surrogate_pair :: proc(r: rune) -> (r1, r2: rune) {
|
||||
encode_surrogate_pair :: proc(c: rune) -> (r1, r2: rune) {
|
||||
r := c;
|
||||
if r < _surr_self || r > MAX_RUNE {
|
||||
return REPLACEMENT_CHAR, REPLACEMENT_CHAR;
|
||||
}
|
||||
|
||||
+63
-18
@@ -41,26 +41,22 @@ accept_ranges := [5]Accept_Range{
|
||||
};
|
||||
|
||||
accept_sizes := [256]u8{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
||||
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
|
||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
|
||||
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
|
||||
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
|
||||
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
|
||||
0x00..0x7f = 0xf0,
|
||||
0x80..0xc1 = 0xf1,
|
||||
0xc2..0xdf = 0x02,
|
||||
0xe0 = 0x13,
|
||||
0xe1..0xec = 0x03,
|
||||
0xed = 0x23,
|
||||
0xee..0xef = 0x03,
|
||||
0xf0 = 0x34,
|
||||
0xf1..0xf3 = 0x04,
|
||||
0xf4 = 0x44,
|
||||
0xf5..0xff = 0xf1,
|
||||
};
|
||||
|
||||
encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
||||
encode_rune :: proc(c: rune) -> ([4]u8, int) {
|
||||
r := c;
|
||||
|
||||
buf: [4]u8;
|
||||
i := u32(r);
|
||||
mask :: u8(0x3f);
|
||||
@@ -165,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||
return r, size;
|
||||
}
|
||||
|
||||
rune_at_pos :: proc(s: string, pos: int) -> rune {
|
||||
if pos < 0 {
|
||||
return RUNE_ERROR;
|
||||
}
|
||||
|
||||
i := 0;
|
||||
for r in s {
|
||||
if i == pos {
|
||||
return r;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return RUNE_ERROR;
|
||||
}
|
||||
|
||||
rune_string_at_pos :: proc(s: string, pos: int) -> string {
|
||||
if pos < 0 {
|
||||
return "";
|
||||
}
|
||||
|
||||
i := 0;
|
||||
for c, offset in s {
|
||||
if i == pos {
|
||||
w := rune_size(c);
|
||||
return s[offset:][:w];
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
rune_at :: proc(s: string, byte_index: int) -> rune {
|
||||
r, _ := decode_rune_in_string(s[byte_index:]);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns the byte position of rune at position pos in s with an optional start byte position.
|
||||
// Returns -1 if it runs out of the string.
|
||||
rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
|
||||
if pos < 0 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
i := 0;
|
||||
for _, offset in s[start:] {
|
||||
if i == pos {
|
||||
return offset+start;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
valid_rune :: proc(r: rune) -> bool {
|
||||
if r < 0 {
|
||||
|
||||
+452
-40
@@ -3,14 +3,34 @@ package main
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:reflect"
|
||||
import "intrinsics"
|
||||
|
||||
when os.OS == "windows" {
|
||||
import "core:thread"
|
||||
}
|
||||
|
||||
@(link_name="general_stuff")
|
||||
general_stuff :: proc() {
|
||||
fmt.println("# general_stuff");
|
||||
/*
|
||||
The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
|
||||
* simplicity
|
||||
* high performance
|
||||
* built for modern systems
|
||||
* joy of programming
|
||||
|
||||
# Installing Odin
|
||||
Getting Started - https://odin-lang.org/docs/install/
|
||||
Instructions for downloading and install the Odin compiler and libraries.
|
||||
|
||||
# Learning Odin
|
||||
Overview of Odin - https://odin-lang.org/docs/overview/
|
||||
An overview of the Odin programming language.
|
||||
Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/
|
||||
Answers to common questions about Odin.
|
||||
*/
|
||||
|
||||
@(link_name="extra_general_stuff")
|
||||
extra_general_stuff :: proc() {
|
||||
fmt.println("# extra_general_stuff");
|
||||
{ // `do` for inline statements rather than block
|
||||
foo :: proc() do fmt.println("Foo!");
|
||||
if false do foo();
|
||||
@@ -30,14 +50,12 @@ general_stuff :: proc() {
|
||||
i := i32(137);
|
||||
ptr := &i;
|
||||
|
||||
_ = (^f32)(ptr);
|
||||
_ = (^f32)(ptr); // Call-based syntax
|
||||
// ^f32(ptr) == ^(f32(ptr))
|
||||
_ = cast(^f32)ptr;
|
||||
_ = cast(^f32)ptr; // Operator-based syntax
|
||||
|
||||
_ = (^f32)(ptr)^;
|
||||
_ = (cast(^f32)ptr)^;
|
||||
|
||||
// Questions: Should there be two ways to do it?
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -50,7 +68,7 @@ general_stuff :: proc() {
|
||||
Foo :: struct {
|
||||
x: int,
|
||||
b: bool,
|
||||
}
|
||||
};
|
||||
f := Foo{137, true};
|
||||
x, b := expand_to_tuple(f);
|
||||
fmt.println(f);
|
||||
@@ -191,8 +209,8 @@ union_type :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 :: struct {x, y, z: f32};
|
||||
Quaternion :: struct {x, y, z, w: f32};
|
||||
Vector3 :: distinct [3]f32;
|
||||
Quaternion :: distinct quaternion128;
|
||||
|
||||
// More realistic examples
|
||||
{
|
||||
@@ -209,18 +227,18 @@ union_type :: proc() {
|
||||
orientation: Quaternion,
|
||||
|
||||
derived: any,
|
||||
}
|
||||
};
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity,
|
||||
jump_height: f32,
|
||||
}
|
||||
};
|
||||
|
||||
Monster :: struct {
|
||||
using entity: Entity,
|
||||
is_robot: bool,
|
||||
is_zombie: bool,
|
||||
}
|
||||
};
|
||||
|
||||
// See `parametric_polymorphism` procedure for details
|
||||
new_entity :: proc($T: typeid) -> ^Entity {
|
||||
@@ -254,18 +272,18 @@ union_type :: proc() {
|
||||
orientation: Quaternion,
|
||||
|
||||
derived: union {Frog, Monster},
|
||||
}
|
||||
};
|
||||
|
||||
Frog :: struct {
|
||||
using entity: ^Entity,
|
||||
jump_height: f32,
|
||||
}
|
||||
};
|
||||
|
||||
Monster :: struct {
|
||||
using entity: ^Entity,
|
||||
is_robot: bool,
|
||||
is_zombie: bool,
|
||||
}
|
||||
};
|
||||
|
||||
// See `parametric_polymorphism` procedure for details
|
||||
new_entity :: proc($T: typeid) -> ^Entity {
|
||||
@@ -302,17 +320,17 @@ union_type :: proc() {
|
||||
|
||||
/*
|
||||
Entity :: struct {
|
||||
..
|
||||
...
|
||||
derived: union{^Frog, ^Monster},
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity,
|
||||
..
|
||||
...
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: Entity,
|
||||
..
|
||||
...
|
||||
|
||||
}
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
@@ -325,7 +343,7 @@ union_type :: proc() {
|
||||
}
|
||||
|
||||
parametric_polymorphism :: proc() {
|
||||
fmt.println("# parametric_polymorphism");
|
||||
fmt.println("\n# parametric_polymorphism");
|
||||
|
||||
print_value :: proc(value: $T) {
|
||||
fmt.printf("print_value: %T %v\n", value, value);
|
||||
@@ -383,13 +401,13 @@ parametric_polymorphism :: proc() {
|
||||
hash: u32,
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
};
|
||||
TABLE_SIZE_MIN :: 32;
|
||||
Table :: struct(Key, Value: typeid) {
|
||||
count: int,
|
||||
allocator: mem.Allocator,
|
||||
slots: []Table_Slot(Key, Value),
|
||||
}
|
||||
};
|
||||
|
||||
// Only allow types that are specializations of a (polymorphic) slice
|
||||
make_slice :: proc($T: typeid/[]$E, len: int) -> T {
|
||||
@@ -513,7 +531,7 @@ parametric_polymorphism :: proc() {
|
||||
Foo1,
|
||||
Foo2,
|
||||
Foo3,
|
||||
}
|
||||
};
|
||||
Para_Union :: union(T: typeid) {T, Error};
|
||||
r: Para_Union(int);
|
||||
fmt.println(typeid_of(type_of(r)));
|
||||
@@ -521,7 +539,7 @@ parametric_polymorphism :: proc() {
|
||||
fmt.println(r);
|
||||
r = 123;
|
||||
fmt.println(r);
|
||||
r = Error.Foo0;
|
||||
r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
|
||||
fmt.println(r);
|
||||
}
|
||||
|
||||
@@ -543,6 +561,30 @@ parametric_polymorphism :: proc() {
|
||||
for v, i in array {
|
||||
assert(v == T(i*i));
|
||||
}
|
||||
|
||||
// Matrix multiplication
|
||||
mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) {
|
||||
for i in 0..<M {
|
||||
for j in 0..<P {
|
||||
for k in 0..<N {
|
||||
c[i][j] += a[i][k] * b[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
x := [2][3]f32{
|
||||
{1, 2, 3},
|
||||
{3, 2, 1},
|
||||
};
|
||||
y := [3][2]f32{
|
||||
{0, 8},
|
||||
{6, 2},
|
||||
{8, 4},
|
||||
};
|
||||
z := mul(x, y);
|
||||
assert(z == {{36, 24}, {20, 32}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +602,7 @@ prefix_table := [?]string{
|
||||
|
||||
threading_example :: proc() {
|
||||
when os.OS == "windows" {
|
||||
fmt.println("# threading_example");
|
||||
fmt.println("\n# threading_example");
|
||||
|
||||
worker_proc :: proc(t: ^thread.Thread) -> int {
|
||||
for iteration in 1..5 {
|
||||
@@ -600,7 +642,7 @@ threading_example :: proc() {
|
||||
}
|
||||
|
||||
array_programming :: proc() {
|
||||
fmt.println("# array_programming");
|
||||
fmt.println("\n# array_programming");
|
||||
{
|
||||
a := [3]f32{1, 2, 3};
|
||||
b := [3]f32{5, 6, 7};
|
||||
@@ -645,7 +687,7 @@ array_programming :: proc() {
|
||||
}
|
||||
|
||||
named_proc_return_parameters :: proc() {
|
||||
fmt.println("# named proc return parameters");
|
||||
fmt.println("\n# named proc return parameters");
|
||||
|
||||
foo0 :: proc() -> int {
|
||||
return 123;
|
||||
@@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() {
|
||||
|
||||
|
||||
using_enum :: proc() {
|
||||
fmt.println("# using enum");
|
||||
fmt.println("\n# using enum");
|
||||
|
||||
using Foo :: enum {A, B, C};
|
||||
|
||||
@@ -679,25 +721,25 @@ using_enum :: proc() {
|
||||
}
|
||||
|
||||
map_type :: proc() {
|
||||
fmt.println("# map type");
|
||||
fmt.println("\n# map type");
|
||||
|
||||
// enums of type u16, u32, i16 & i32 also work
|
||||
Enum_u8 :: enum u8 {
|
||||
A = 0,
|
||||
B = 1 << 8 - 1,
|
||||
}
|
||||
};
|
||||
Enum_u64 :: enum u64 {
|
||||
A = 0,
|
||||
B = 1 << 64 - 1,
|
||||
}
|
||||
};
|
||||
Enum_i8 :: enum i8 {
|
||||
A = 0,
|
||||
B = -(1 << 7),
|
||||
}
|
||||
};
|
||||
Enum_i64 :: enum i64 {
|
||||
A = 0,
|
||||
B = -(1 << 63),
|
||||
}
|
||||
};
|
||||
|
||||
map_u8: map[Enum_u8]u8;
|
||||
map_u8[Enum_u8.A] = u8(Enum_u8.B);
|
||||
@@ -721,7 +763,7 @@ map_type :: proc() {
|
||||
|
||||
demo_struct :: struct {
|
||||
member: Enum_i64,
|
||||
}
|
||||
};
|
||||
|
||||
map_string: map[string]demo_struct;
|
||||
map_string["Hellope!"] = demo_struct{Enum_i64.B};
|
||||
@@ -734,7 +776,7 @@ map_type :: proc() {
|
||||
}
|
||||
|
||||
implicit_selector_expression :: proc() {
|
||||
fmt.println("# implicit selector expression");
|
||||
fmt.println("\n# implicit selector expression");
|
||||
|
||||
Foo :: enum {A, B, C};
|
||||
|
||||
@@ -762,7 +804,7 @@ implicit_selector_expression :: proc() {
|
||||
}
|
||||
|
||||
explicit_procedure_overloading :: proc() {
|
||||
fmt.println("# explicit procedure overloading");
|
||||
fmt.println("\n# explicit procedure overloading");
|
||||
|
||||
add_ints :: proc(a, b: int) -> int {
|
||||
x := a + b;
|
||||
@@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() {
|
||||
}
|
||||
|
||||
complete_switch :: proc() {
|
||||
fmt.println("# complete_switch");
|
||||
fmt.println("\n# complete_switch");
|
||||
{ // enum
|
||||
using Foo :: enum {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
}
|
||||
};
|
||||
|
||||
b := Foo.B;
|
||||
f := Foo.A;
|
||||
@@ -829,6 +871,8 @@ complete_switch :: proc() {
|
||||
}
|
||||
|
||||
cstring_example :: proc() {
|
||||
fmt.println("\n# cstring_example");
|
||||
|
||||
W :: "Hellope";
|
||||
X :: cstring(W);
|
||||
Y :: string(X);
|
||||
@@ -860,6 +904,8 @@ deprecated_attribute :: proc() {
|
||||
}
|
||||
|
||||
bit_set_type :: proc() {
|
||||
fmt.println("\n# bit_set_type");
|
||||
|
||||
{
|
||||
using Day :: enum {
|
||||
Sunday,
|
||||
@@ -869,7 +915,7 @@ bit_set_type :: proc() {
|
||||
Thursday,
|
||||
Friday,
|
||||
Saturday,
|
||||
}
|
||||
};
|
||||
|
||||
Days :: distinct bit_set[Day];
|
||||
WEEKEND :: Days{Sunday, Saturday};
|
||||
@@ -921,6 +967,8 @@ bit_set_type :: proc() {
|
||||
}
|
||||
|
||||
diverging_procedures :: proc() {
|
||||
fmt.println("\n# diverging_procedures");
|
||||
|
||||
// Diverging procedures may never return
|
||||
foo :: proc() -> ! {
|
||||
fmt.println("I'm a diverging procedure");
|
||||
@@ -930,6 +978,8 @@ diverging_procedures :: proc() {
|
||||
}
|
||||
|
||||
deferred_procedure_associations :: proc() {
|
||||
fmt.println("\n# deferred_procedure_associations");
|
||||
|
||||
@(deferred_out=closure)
|
||||
open :: proc(s: string) -> bool {
|
||||
fmt.println(s);
|
||||
@@ -945,9 +995,363 @@ deferred_procedure_associations :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
reflection :: proc() {
|
||||
fmt.println("\n# reflection");
|
||||
|
||||
Foo :: struct {
|
||||
x: int `tag1`,
|
||||
y: string `json:"y_field"`,
|
||||
z: bool, // no tag
|
||||
};
|
||||
|
||||
id := typeid_of(Foo);
|
||||
names := reflect.struct_field_names(id);
|
||||
types := reflect.struct_field_types(id);
|
||||
tags := reflect.struct_field_tags(id);
|
||||
|
||||
assert(len(names) == len(types) && len(names) == len(tags));
|
||||
|
||||
fmt.println("Foo :: struct {");
|
||||
for tag, i in tags {
|
||||
name, type := names[i], types[i];
|
||||
if tag != "" {
|
||||
fmt.printf("\t%s: %T `%s`,\n", name, type, tag);
|
||||
} else {
|
||||
fmt.printf("\t%s: %T,\n", name, type);
|
||||
}
|
||||
}
|
||||
fmt.println("}");
|
||||
|
||||
|
||||
for tag, i in tags {
|
||||
if val, ok := reflect.struct_tag_lookup(tag, "json"); ok {
|
||||
fmt.printf("json: %s -> %s\n", names[i], val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quaternions :: proc() {
|
||||
fmt.println("\n# quaternions");
|
||||
|
||||
{ // Quaternion operations
|
||||
q := 1 + 2i + 3j + 4k;
|
||||
r := quaternion(5, 6, 7, 8);
|
||||
t := q * r;
|
||||
fmt.printf("(%v) * (%v) = %v\n", q, r, t);
|
||||
v := q / r;
|
||||
fmt.printf("(%v) / (%v) = %v\n", q, r, v);
|
||||
u := q + r;
|
||||
fmt.printf("(%v) + (%v) = %v\n", q, r, u);
|
||||
s := q - r;
|
||||
fmt.printf("(%v) - (%v) = %v\n", q, r, s);
|
||||
}
|
||||
{ // The quaternion types
|
||||
q128: quaternion128; // 4xf32
|
||||
q256: quaternion256; // 4xf64
|
||||
q128 = quaternion(1, 0, 0, 0);
|
||||
q256 = 1; // quaternion(1, 0, 0, 0);
|
||||
}
|
||||
{ // Built-in procedures
|
||||
q := 1 + 2i + 3j + 4k;
|
||||
fmt.println("q =", q);
|
||||
fmt.println("real(q) =", real(q));
|
||||
fmt.println("imag(q) =", imag(q));
|
||||
fmt.println("jmag(q) =", jmag(q));
|
||||
fmt.println("kmag(q) =", kmag(q));
|
||||
fmt.println("conj(q) =", conj(q));
|
||||
fmt.println("abs(q) =", abs(q));
|
||||
}
|
||||
{ // Conversion of a complex type to a quaternion type
|
||||
c := 1 + 2i;
|
||||
q := quaternion256(c);
|
||||
fmt.println(c);
|
||||
fmt.println(q);
|
||||
}
|
||||
{ // Memory layout of Quaternions
|
||||
q := 1 + 2i + 3j + 4k;
|
||||
a := transmute([4]f64)q;
|
||||
fmt.println("Quaternion memory layout: xyzw/(ijkr)");
|
||||
fmt.println(q); // 1.000+2.000i+3.000j+4.000k
|
||||
fmt.println(a); // [2.000, 3.000, 4.000, 1.000]
|
||||
}
|
||||
}
|
||||
|
||||
inline_for_statement :: proc() {
|
||||
fmt.println("\n#inline for statements");
|
||||
|
||||
// 'inline for' works the same as if the 'inline' prefix did not
|
||||
// exist but these ranged loops are explicitly unrolled which can
|
||||
// be very very useful for certain optimizations
|
||||
|
||||
fmt.println("Ranges");
|
||||
inline for x, i in 1..<4 {
|
||||
fmt.println(x, i);
|
||||
}
|
||||
|
||||
fmt.println("Strings");
|
||||
inline for r, i in "Hello, 世界" {
|
||||
fmt.println(r, i);
|
||||
}
|
||||
|
||||
fmt.println("Arrays");
|
||||
inline for elem, idx in ([4]int{1, 4, 9, 16}) {
|
||||
fmt.println(elem, idx);
|
||||
}
|
||||
|
||||
|
||||
Foo_Enum :: enum {
|
||||
A = 1,
|
||||
B,
|
||||
C = 6,
|
||||
D,
|
||||
};
|
||||
fmt.println("Enum types");
|
||||
inline for elem, idx in Foo_Enum {
|
||||
fmt.println(elem, idx);
|
||||
}
|
||||
}
|
||||
|
||||
where_clauses :: proc() {
|
||||
fmt.println("\n#procedure 'where' clauses");
|
||||
|
||||
{ // Sanity checks
|
||||
simple_sanity_check :: proc(x: [2]int)
|
||||
where len(x) > 1,
|
||||
type_of(x) == [2]int {
|
||||
fmt.println(x);
|
||||
}
|
||||
}
|
||||
{ // Parametric polymorphism checks
|
||||
cross_2d :: proc(a, b: $T/[2]$E) -> E
|
||||
where intrinsics.type_is_numeric(E) {
|
||||
return a.x*b.y - a.y*b.x;
|
||||
}
|
||||
cross_3d :: proc(a, b: $T/[3]$E) -> T
|
||||
where intrinsics.type_is_numeric(E) {
|
||||
x := a.y*b.z - a.z*b.y;
|
||||
y := a.z*b.x - a.x*b.z;
|
||||
z := a.x*b.y - a.y*b.z;
|
||||
return T{x, y, z};
|
||||
}
|
||||
|
||||
a := [2]int{1, 2};
|
||||
b := [2]int{5, -3};
|
||||
fmt.println(cross_2d(a, b));
|
||||
|
||||
x := [3]f32{1, 4, 9};
|
||||
y := [3]f32{-5, 0, 3};
|
||||
fmt.println(cross_3d(x, y));
|
||||
|
||||
// Failure case
|
||||
// i := [2]bool{true, false};
|
||||
// j := [2]bool{false, true};
|
||||
// fmt.println(cross_2d(i, j));
|
||||
|
||||
}
|
||||
|
||||
{ // Procedure groups usage
|
||||
foo :: proc(x: [$N]int) -> bool
|
||||
where N > 2 {
|
||||
fmt.println(#procedure, "was called with the parameter", x);
|
||||
return true;
|
||||
}
|
||||
|
||||
bar :: proc(x: [$N]int) -> bool
|
||||
where 0 < N,
|
||||
N <= 2 {
|
||||
fmt.println(#procedure, "was called with the parameter", x);
|
||||
return false;
|
||||
}
|
||||
|
||||
baz :: proc{foo, bar};
|
||||
|
||||
x := [3]int{1, 2, 3};
|
||||
y := [2]int{4, 9};
|
||||
ok_x := baz(x);
|
||||
ok_y := baz(y);
|
||||
assert(ok_x == true);
|
||||
assert(ok_y == false);
|
||||
}
|
||||
|
||||
{ // Record types
|
||||
Foo :: struct(T: typeid, N: int)
|
||||
where intrinsics.type_is_integer(T),
|
||||
N > 2 {
|
||||
x: [N]T,
|
||||
y: [N-2]T,
|
||||
};
|
||||
|
||||
T :: i32;
|
||||
N :: 5;
|
||||
f: Foo(T, N);
|
||||
#assert(size_of(f) == (N+N-2)*size_of(T));
|
||||
}
|
||||
}
|
||||
|
||||
ranged_fields_for_array_compound_literals :: proc() {
|
||||
fmt.println("\n#ranged fields for array compound literals");
|
||||
{ // Normal Array Literal
|
||||
foo := [?]int{1, 4, 9, 16};
|
||||
fmt.println(foo);
|
||||
}
|
||||
{ // Indexed
|
||||
foo := [?]int{
|
||||
3 = 16,
|
||||
1 = 4,
|
||||
2 = 9,
|
||||
0 = 1,
|
||||
};
|
||||
fmt.println(foo);
|
||||
}
|
||||
{ // Ranges
|
||||
i := 2;
|
||||
foo := [?]int {
|
||||
0 = 123,
|
||||
5..9 = 54,
|
||||
10..<16 = i*3 + (i-1)*2,
|
||||
};
|
||||
#assert(len(foo) == 16);
|
||||
fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
|
||||
}
|
||||
{ // Slice and Dynamic Array support
|
||||
i := 2;
|
||||
foo_slice := []int {
|
||||
0 = 123,
|
||||
5..9 = 54,
|
||||
10..<16 = i*3 + (i-1)*2,
|
||||
};
|
||||
assert(len(foo_slice) == 16);
|
||||
fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
|
||||
|
||||
foo_dynamic_array := [dynamic]int {
|
||||
0 = 123,
|
||||
5..9 = 54,
|
||||
10..<16 = i*3 + (i-1)*2,
|
||||
};
|
||||
assert(len(foo_dynamic_array) == 16);
|
||||
fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
|
||||
}
|
||||
}
|
||||
|
||||
range_statements_with_multiple_return_values :: proc() {
|
||||
// IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed
|
||||
fmt.println("\n#range statements with multiple return values");
|
||||
My_Iterator :: struct {
|
||||
index: int,
|
||||
data: []i32,
|
||||
};
|
||||
make_my_iterator :: proc(data: []i32) -> My_Iterator {
|
||||
return My_Iterator{data = data};
|
||||
}
|
||||
my_iterator :: proc(it: ^My_Iterator) -> (val: i32, idx: int, cond: bool) {
|
||||
if cond = it.index < len(it.data); cond {
|
||||
val = it.data[it.index];
|
||||
idx = it.index;
|
||||
it.index += 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
data := make([]i32, 6);
|
||||
for _, i in data {
|
||||
data[i] = i32(i*i);
|
||||
}
|
||||
|
||||
{
|
||||
it := make_my_iterator(data);
|
||||
for val in my_iterator(&it) {
|
||||
fmt.println(val);
|
||||
}
|
||||
}
|
||||
{
|
||||
it := make_my_iterator(data);
|
||||
for val, idx in my_iterator(&it) {
|
||||
fmt.println(val, idx);
|
||||
}
|
||||
}
|
||||
{
|
||||
it := make_my_iterator(data);
|
||||
for {
|
||||
val, _, cond := my_iterator(&it);
|
||||
if !cond do break;
|
||||
fmt.println(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
soa_struct_layout :: proc() {
|
||||
// IMPORTANT NOTE(bill, 2019-11-03): This feature is subject to be changed/removed
|
||||
fmt.println("\n#SOA Struct Layout");
|
||||
|
||||
{
|
||||
Vector3 :: struct {x, y, z: f32};
|
||||
|
||||
N :: 2;
|
||||
v_aos: [N]Vector3;
|
||||
v_aos[0].x = 1;
|
||||
v_aos[0].y = 4;
|
||||
v_aos[0].z = 9;
|
||||
|
||||
fmt.println(len(v_aos));
|
||||
fmt.println(v_aos[0]);
|
||||
fmt.println(v_aos[0].x);
|
||||
fmt.println(&v_aos[0].x);
|
||||
|
||||
v_aos[1] = {0, 3, 4};
|
||||
v_aos[1].x = 2;
|
||||
fmt.println(v_aos[1]);
|
||||
fmt.println(v_aos);
|
||||
|
||||
v_soa: intrinsics.soa_struct(N, Vector3);
|
||||
|
||||
v_soa[0].x = 1;
|
||||
v_soa[0].y = 4;
|
||||
v_soa[0].z = 9;
|
||||
|
||||
|
||||
// Same syntax as AOS and treat as if it was an array
|
||||
fmt.println(len(v_soa));
|
||||
fmt.println(v_soa[0]);
|
||||
fmt.println(v_soa[0].x);
|
||||
v_soa[1] = {0, 3, 4};
|
||||
v_soa[1].x = 2;
|
||||
fmt.println(v_soa[1]);
|
||||
|
||||
// Can use SOA syntax if necessary
|
||||
v_soa.x[0] = 1;
|
||||
v_soa.y[0] = 4;
|
||||
v_soa.z[0] = 9;
|
||||
fmt.println(v_soa.x[0]);
|
||||
|
||||
// Same pointer addresses with both syntaxes
|
||||
assert(&v_soa[0].x == &v_soa.x[0]);
|
||||
|
||||
|
||||
// Same fmt printing
|
||||
fmt.println(v_aos);
|
||||
fmt.println(v_soa);
|
||||
}
|
||||
{
|
||||
// Works with arrays of length <= 4 which have the implicit fields xyzw/rgba
|
||||
Vector3 :: distinct [3]f32;
|
||||
|
||||
N :: 2;
|
||||
v_aos: [N]Vector3;
|
||||
v_aos[0].x = 1;
|
||||
v_aos[0].y = 4;
|
||||
v_aos[0].z = 9;
|
||||
|
||||
v_soa: intrinsics.soa_struct(N, Vector3);
|
||||
|
||||
v_soa[0].x = 1;
|
||||
v_soa[0].y = 4;
|
||||
v_soa[0].z = 9;
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
general_stuff();
|
||||
extra_general_stuff();
|
||||
union_type();
|
||||
parametric_polymorphism();
|
||||
threading_example();
|
||||
@@ -963,5 +1367,13 @@ main :: proc() {
|
||||
bit_set_type();
|
||||
diverging_procedures();
|
||||
deferred_procedure_associations();
|
||||
reflection();
|
||||
quaternions();
|
||||
inline_for_statement();
|
||||
where_clauses();
|
||||
ranged_fields_for_array_compound_literals();
|
||||
range_statements_with_multiple_return_values();
|
||||
soa_struct_layout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 75 KiB |
+2
-2
@@ -1,8 +1,8 @@
|
||||
@echo off
|
||||
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
|
||||
set _NO_DEBUG_HEAP=1
|
||||
|
||||
+21
-16
@@ -499,7 +499,7 @@ void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
smaller = &neg_abs;
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Invalid bit_int_cmp value");
|
||||
GB_PANIC("Invalid big_int_cmp value");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -530,6 +530,9 @@ void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
if (sub_overflow_u64(v, prev_overflow, &v)) {
|
||||
found_word = true;
|
||||
overflow += 1;
|
||||
} else {
|
||||
// IMPORTANT TODO(bill): Is this mathematics correct here?
|
||||
v += overflow;
|
||||
}
|
||||
dst->d.words[i] = v;
|
||||
i += 1;
|
||||
@@ -1245,15 +1248,15 @@ void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
x = y;
|
||||
y = tmp;
|
||||
}
|
||||
|
||||
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
||||
|
||||
dst->neg = false;
|
||||
BigInt y1 = big_int_make_abs(y);
|
||||
big_int_sub_eq(&y1, &BIG_INT_ONE);
|
||||
big_int__xor_abs(dst, x, &y1);
|
||||
big_int_add_eq(dst, &BIG_INT_ONE);
|
||||
dst->neg = true;
|
||||
if (y->neg) {
|
||||
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
||||
BigInt y1 = big_int_make_abs(y);
|
||||
big_int_sub_eq(&y1, &BIG_INT_ONE);
|
||||
big_int__xor_abs(dst, x, &y1);
|
||||
big_int_add_eq(dst, &BIG_INT_ONE);
|
||||
dst->neg = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1313,13 +1316,15 @@ void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
x = y;
|
||||
y = tmp;
|
||||
}
|
||||
|
||||
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(~((y-1) &~ x) + 1)
|
||||
BigInt y1 = big_int_make_abs(y);
|
||||
big_int_sub_eq(&y1, &BIG_INT_ONE);
|
||||
big_int__and_not_abs(dst, &y1, x);
|
||||
big_int_add_eq(dst, &BIG_INT_ONE);
|
||||
dst->neg = true;
|
||||
dst->neg = false;
|
||||
if (y->neg) {
|
||||
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(~((y-1) &~ x) + 1)
|
||||
BigInt y1 = big_int_make_abs(y);
|
||||
big_int_sub_eq(&y1, &BIG_INT_ONE);
|
||||
big_int__and_not_abs(dst, &y1, x);
|
||||
big_int_add_eq(dst, &BIG_INT_ONE);
|
||||
dst->neg = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+43
-14
@@ -2,7 +2,7 @@ enum TargetOsKind {
|
||||
TargetOs_Invalid,
|
||||
|
||||
TargetOs_windows,
|
||||
TargetOs_osx,
|
||||
TargetOs_darwin,
|
||||
TargetOs_linux,
|
||||
TargetOs_essence,
|
||||
|
||||
@@ -30,7 +30,7 @@ enum TargetEndianKind {
|
||||
String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("windows"),
|
||||
str_lit("osx"),
|
||||
str_lit("darwin"),
|
||||
str_lit("linux"),
|
||||
str_lit("essence"),
|
||||
};
|
||||
@@ -55,9 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||
|
||||
|
||||
|
||||
String const ODIN_VERSION = str_lit("0.10.0");
|
||||
String cross_compile_target = str_lit("");
|
||||
String cross_compile_lib_dir = str_lit("");
|
||||
String const ODIN_VERSION = str_lit("0.11.1");
|
||||
|
||||
|
||||
|
||||
@@ -66,6 +64,7 @@ struct TargetMetrics {
|
||||
TargetArchKind arch;
|
||||
isize word_size;
|
||||
isize max_align;
|
||||
String target_triplet;
|
||||
};
|
||||
|
||||
|
||||
@@ -109,11 +108,13 @@ struct BuildContext {
|
||||
bool has_resource;
|
||||
String opt_flags;
|
||||
String llc_flags;
|
||||
String target_triplet;
|
||||
String link_flags;
|
||||
bool is_dll;
|
||||
bool generate_docs;
|
||||
i32 optimization_level;
|
||||
bool show_timings;
|
||||
bool show_more_timings;
|
||||
bool keep_temp_files;
|
||||
bool ignore_unknown_attributes;
|
||||
bool no_bounds_check;
|
||||
@@ -121,6 +122,7 @@ struct BuildContext {
|
||||
bool no_crt;
|
||||
bool use_lld;
|
||||
bool vet;
|
||||
bool cross_compiling;
|
||||
|
||||
QueryDataSetSettings query_data_set_settings;
|
||||
|
||||
@@ -135,18 +137,19 @@ struct BuildContext {
|
||||
gb_global BuildContext build_context = {0};
|
||||
|
||||
|
||||
|
||||
gb_global TargetMetrics target_windows_386 = {
|
||||
TargetOs_windows,
|
||||
TargetArch_386,
|
||||
4,
|
||||
8,
|
||||
str_lit("i686-pc-windows"),
|
||||
};
|
||||
gb_global TargetMetrics target_windows_amd64 = {
|
||||
TargetOs_windows,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
str_lit("x86_64-pc-windows-gnu"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_linux_386 = {
|
||||
@@ -154,23 +157,47 @@ gb_global TargetMetrics target_linux_386 = {
|
||||
TargetArch_386,
|
||||
4,
|
||||
8,
|
||||
str_lit("i686-pc-linux-gnu"),
|
||||
};
|
||||
gb_global TargetMetrics target_linux_amd64 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
str_lit("x86_64-pc-linux-gnu"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_osx_amd64 = {
|
||||
TargetOs_osx,
|
||||
gb_global TargetMetrics target_darwin_amd64 = {
|
||||
TargetOs_darwin,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
str_lit("x86_64-apple-darwin"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_essence_amd64 = {
|
||||
TargetOs_essence,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
str_lit("x86_64-pc-none-elf"),
|
||||
};
|
||||
|
||||
struct NamedTargetMetrics {
|
||||
String name;
|
||||
TargetMetrics *metrics;
|
||||
};
|
||||
|
||||
gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("essence_amd64"), &target_essence_amd64 },
|
||||
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
|
||||
{ str_lit("linux_386"), &target_linux_386 },
|
||||
{ str_lit("linux_amd64"), &target_linux_amd64 },
|
||||
{ str_lit("windows_386"), &target_windows_386 },
|
||||
{ str_lit("windows_amd64"), &target_windows_amd64 },
|
||||
};
|
||||
|
||||
NamedTargetMetrics *selected_target_metrics;
|
||||
|
||||
TargetOsKind get_target_os_from_string(String str) {
|
||||
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
||||
@@ -522,7 +549,7 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
|
||||
|
||||
|
||||
void init_build_context(void) {
|
||||
void init_build_context(TargetMetrics *cross_target) {
|
||||
BuildContext *bc = &build_context;
|
||||
|
||||
gb_affinity_init(&bc->affinity);
|
||||
@@ -540,7 +567,7 @@ void init_build_context(void) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
metrics = target_windows_amd64;
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
metrics = target_osx_amd64;
|
||||
metrics = target_darwin_amd64;
|
||||
#else
|
||||
metrics = target_linux_amd64;
|
||||
#endif
|
||||
@@ -554,8 +581,9 @@ void init_build_context(void) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (cross_compile_target.len) {
|
||||
bc->ODIN_OS = cross_compile_target;
|
||||
if (cross_target) {
|
||||
metrics = *cross_target;
|
||||
bc->cross_compiling = true;
|
||||
}
|
||||
|
||||
GB_ASSERT(metrics.os != TargetOs_Invalid);
|
||||
@@ -573,6 +601,7 @@ void init_build_context(void) {
|
||||
bc->max_align = metrics.max_align;
|
||||
bc->link_flags = str_lit(" ");
|
||||
bc->opt_flags = str_lit(" ");
|
||||
bc->target_triplet = metrics.target_triplet;
|
||||
|
||||
|
||||
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
|
||||
@@ -590,7 +619,7 @@ void init_build_context(void) {
|
||||
case TargetOs_windows:
|
||||
bc->link_flags = str_lit("/machine:x64 ");
|
||||
break;
|
||||
case TargetOs_osx:
|
||||
case TargetOs_darwin:
|
||||
break;
|
||||
case TargetOs_linux:
|
||||
bc->link_flags = str_lit("-arch x86-64 ");
|
||||
@@ -603,7 +632,7 @@ void init_build_context(void) {
|
||||
case TargetOs_windows:
|
||||
bc->link_flags = str_lit("/machine:x86 ");
|
||||
break;
|
||||
case TargetOs_osx:
|
||||
case TargetOs_darwin:
|
||||
gb_printf_err("Unsupported architecture\n");
|
||||
gb_exit(1);
|
||||
break;
|
||||
|
||||
+217
-85
@@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
gbString t = type_to_string(operand->type);
|
||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
gb_string_free(t);
|
||||
e->type = operand->type;
|
||||
return nullptr;
|
||||
if (e->type != nullptr && is_type_typeid(e->type)) {
|
||||
add_type_info_type(ctx, operand->type);
|
||||
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
|
||||
return e->type;
|
||||
} else {
|
||||
gbString t = type_to_string(operand->type);
|
||||
defer (gb_string_free(t));
|
||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
if (e->type == nullptr) {
|
||||
error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string));
|
||||
}
|
||||
e->type = operand->type;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
if (operands[i].mode == Addressing_Invalid) {
|
||||
rhs_count--;
|
||||
// TODO(bill): Should I ignore invalid parameters?
|
||||
// rhs_count--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
|
||||
}
|
||||
|
||||
|
||||
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
|
||||
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
@@ -247,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
|
||||
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool is_distinct = is_type_distinct(type_expr);
|
||||
Ast *te = remove_type_alias_clutter(type_expr);
|
||||
bool is_distinct = is_type_distinct(init_expr);
|
||||
Ast *te = remove_type_alias_clutter(init_expr);
|
||||
e->type = t_invalid;
|
||||
String name = e->token.string;
|
||||
Type *named = alloc_type_named(name, nullptr, e);
|
||||
@@ -265,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
|
||||
named->Named.base = base_type(bt);
|
||||
|
||||
if (is_distinct && is_type_typeid(e->type)) {
|
||||
error(type_expr, "'distinct' cannot be applied to 'typeid'");
|
||||
error(init_expr, "'distinct' cannot be applied to 'typeid'");
|
||||
is_distinct = false;
|
||||
}
|
||||
if (!is_distinct) {
|
||||
@@ -274,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
|
||||
e->TypeName.is_type_alias = true;
|
||||
}
|
||||
|
||||
|
||||
if (decl->type_expr != nullptr) {
|
||||
Type *t = check_type(ctx, decl->type_expr);
|
||||
if (t != nullptr && !is_type_typeid(t)) {
|
||||
Operand operand = {};
|
||||
operand.mode = Addressing_Type;
|
||||
operand.type = e->type;
|
||||
operand.expr = init_expr;
|
||||
check_assignment(ctx, &operand, t, str_lit("constant declaration"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// using decl
|
||||
if (decl->is_using) {
|
||||
// NOTE(bill): Must be an enum declaration
|
||||
@@ -338,7 +360,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
||||
|
||||
if (type_expr) {
|
||||
Type *t = check_type(ctx, type_expr);
|
||||
if (!is_type_constant_type(t)) {
|
||||
if (!is_type_constant_type(t) && !is_type_proc(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
error(type_expr, "Invalid constant type '%s'", str);
|
||||
gb_string_free(str);
|
||||
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
||||
|
||||
switch (operand.mode) {
|
||||
case Addressing_Type: {
|
||||
if (e->type != nullptr && !is_type_typeid(e->type)) {
|
||||
check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
|
||||
}
|
||||
|
||||
e->kind = Entity_TypeName;
|
||||
e->type = nullptr;
|
||||
|
||||
DeclInfo *d = ctx->decl;
|
||||
if (d->type_expr != nullptr) {
|
||||
error(e->token, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = d->init_expr;
|
||||
check_type_decl(ctx, e, d->type_expr, named_type);
|
||||
check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -392,6 +413,25 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
||||
}
|
||||
|
||||
if (entity != nullptr) {
|
||||
if (e->type != nullptr) {
|
||||
Operand x = {};
|
||||
x.type = entity->type;
|
||||
x.mode = Addressing_Variable;
|
||||
if (!check_is_assignable_to(ctx, &x, e->type)) {
|
||||
gbString expr_str = expr_to_string(init);
|
||||
gbString op_type_str = type_to_string(entity->type);
|
||||
gbString type_str = type_to_string(e->type);
|
||||
error(e->token,
|
||||
"Cannot assign '%s' of type '%s' to '%s'",
|
||||
expr_str,
|
||||
op_type_str,
|
||||
type_str);
|
||||
|
||||
gb_string_free(type_str);
|
||||
gb_string_free(op_type_str);
|
||||
gb_string_free(expr_str);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): Override aliased entity
|
||||
switch (entity->kind) {
|
||||
@@ -583,11 +623,45 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
check_open_scope(ctx, pl->type);
|
||||
defer (check_close_scope(ctx));
|
||||
|
||||
Type *decl_type = nullptr;
|
||||
|
||||
if (d->type_expr != nullptr) {
|
||||
decl_type = check_type(ctx, d->type_expr);
|
||||
if (!is_type_proc(decl_type)) {
|
||||
gbString str = type_to_string(decl_type);
|
||||
error(d->type_expr, "Expected a procedure type, got '%s'", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto tmp_ctx = *ctx;
|
||||
tmp_ctx.allow_polymorphic_types = true;
|
||||
if (decl_type != nullptr) {
|
||||
tmp_ctx.type_hint = decl_type;
|
||||
}
|
||||
check_procedure_type(&tmp_ctx, proc_type, pl->type);
|
||||
|
||||
if (decl_type != nullptr) {
|
||||
Operand x = {};
|
||||
x.type = e->type;
|
||||
x.mode = Addressing_Variable;
|
||||
if (!check_is_assignable_to(ctx, &x, decl_type)) {
|
||||
gbString expr_str = expr_to_string(d->proc_lit);
|
||||
gbString op_type_str = type_to_string(e->type);
|
||||
gbString type_str = type_to_string(decl_type);
|
||||
error(e->token,
|
||||
"Cannot assign '%s' of type '%s' to '%s'",
|
||||
expr_str,
|
||||
op_type_str,
|
||||
type_str);
|
||||
|
||||
gb_string_free(type_str);
|
||||
gb_string_free(op_type_str);
|
||||
gb_string_free(expr_str);
|
||||
}
|
||||
}
|
||||
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
|
||||
|
||||
@@ -601,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
|
||||
bool is_foreign = e->Procedure.is_foreign;
|
||||
bool is_export = e->Procedure.is_export;
|
||||
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
|
||||
|
||||
if (e->pkg != nullptr && e->token.string == "main") {
|
||||
if (pt->param_count != 0 ||
|
||||
@@ -661,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pt->result_count == 0 && is_require_results) {
|
||||
error(pl->type, "'#require_results' is not needed on a procedure with no results");
|
||||
if (pt->result_count == 0 && ac.require_results) {
|
||||
error(pl->type, "'require_results' is not needed on a procedure with no results");
|
||||
} else {
|
||||
pt->require_results = is_require_results;
|
||||
pt->require_results = ac.require_results;
|
||||
}
|
||||
|
||||
if (ac.link_name.len > 0) {
|
||||
@@ -738,7 +811,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
|
||||
void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
@@ -752,6 +825,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
|
||||
ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
GB_ASSERT(decl == ctx->decl);
|
||||
if (decl != nullptr) {
|
||||
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
|
||||
}
|
||||
@@ -883,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
||||
|
||||
ptr_set_destroy(&entity_set);
|
||||
|
||||
|
||||
for_array(j, pge->entities) {
|
||||
Entity *p = pge->entities[j];
|
||||
if (p->type == t_invalid) {
|
||||
@@ -909,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
||||
defer (end_error_block());
|
||||
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
switch (kind) {
|
||||
bool both_have_where_clauses = false;
|
||||
if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
|
||||
GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
|
||||
GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
|
||||
auto pl = &p->decl_info->proc_lit->ProcLit;
|
||||
auto ql = &q->decl_info->proc_lit->ProcLit;
|
||||
|
||||
// Allow collisions if the procedures both have 'where' clauses and are both polymorphic
|
||||
bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
|
||||
bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
|
||||
both_have_where_clauses = pw && qw;
|
||||
}
|
||||
|
||||
if (!both_have_where_clauses) switch (kind) {
|
||||
case ProcOverload_Identical:
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
// case ProcOverload_CallingConvention:
|
||||
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
|
||||
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
// is_invalid = true;
|
||||
// break;
|
||||
case ProcOverload_ParamVariadic:
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_ResultCount:
|
||||
case ProcOverload_ResultTypes:
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
|
||||
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_Polymorphic:
|
||||
#if 0
|
||||
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
|
||||
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
#endif
|
||||
break;
|
||||
@@ -998,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Variable:
|
||||
check_var_decl(&c, e, d->type_expr, d->init_expr);
|
||||
check_global_variable_decl(&c, e, d->type_expr, d->init_expr);
|
||||
break;
|
||||
case Entity_Constant:
|
||||
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
|
||||
break;
|
||||
case Entity_TypeName: {
|
||||
check_type_decl(&c, e, d->type_expr, named_type);
|
||||
check_type_decl(&c, e, d->init_expr, named_type);
|
||||
break;
|
||||
}
|
||||
case Entity_Procedure:
|
||||
@@ -1021,6 +1107,11 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
|
||||
}
|
||||
|
||||
|
||||
struct ProcUsingVar {
|
||||
Entity *e;
|
||||
Entity *uvar;
|
||||
};
|
||||
|
||||
|
||||
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
|
||||
if (body == nullptr) {
|
||||
@@ -1045,76 +1136,117 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
ctx->curr_proc_decl = decl;
|
||||
ctx->curr_proc_sig = type;
|
||||
|
||||
GB_ASSERT(type->kind == Type_Proc);
|
||||
if (type->Proc.param_count > 0) {
|
||||
TypeTuple *params = &type->Proc.params->Tuple;
|
||||
for_array(i, params->variables) {
|
||||
Entity *e = params->variables[i];
|
||||
if (e->kind != Entity_Variable) {
|
||||
continue;
|
||||
}
|
||||
if (!(e->flags & EntityFlag_Using)) {
|
||||
continue;
|
||||
}
|
||||
bool is_immutable = e->Variable.is_immutable;
|
||||
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (t->kind == Type_Struct) {
|
||||
Scope *scope = t->Struct.scope;
|
||||
if (scope == nullptr) {
|
||||
scope = scope_of_node(t->Struct.node);
|
||||
}
|
||||
GB_ASSERT(scope != nullptr);
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||
ast_node(bs, BlockStmt, body);
|
||||
|
||||
Array<ProcUsingVar> using_entities = {};
|
||||
using_entities.allocator = heap_allocator();
|
||||
defer (array_free(&using_entities));
|
||||
|
||||
{
|
||||
GB_ASSERT(type->kind == Type_Proc);
|
||||
if (type->Proc.param_count > 0) {
|
||||
TypeTuple *params = &type->Proc.params->Tuple;
|
||||
for_array(i, params->variables) {
|
||||
Entity *e = params->variables[i];
|
||||
if (e->kind != Entity_Variable) {
|
||||
continue;
|
||||
}
|
||||
if (!(e->flags & EntityFlag_Using)) {
|
||||
continue;
|
||||
}
|
||||
bool is_immutable = e->Variable.is_immutable;
|
||||
bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (t->kind == Type_Struct) {
|
||||
Scope *scope = t->Struct.scope;
|
||||
if (scope == nullptr) {
|
||||
scope = scope_of_node(t->Struct.node);
|
||||
}
|
||||
GB_ASSERT(scope != nullptr);
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||
|
||||
ProcUsingVar puv = {e, uvar};
|
||||
array_add(&using_entities, puv);
|
||||
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(e->token, "'using' can only be applied to variables of type struct");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
error(e->token, "'using' can only be applied to variables of type struct");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast_node(bs, BlockStmt, body);
|
||||
// check_open_scope(ctx, body);
|
||||
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
||||
if (type->Proc.result_count > 0) {
|
||||
if (!check_is_terminating(body)) {
|
||||
if (token.kind == Token_Ident) {
|
||||
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
|
||||
} else {
|
||||
// NOTE(bill): Anonymous procedure (lambda)
|
||||
error(bs->close, "Missing return statement at the end of the procedure");
|
||||
|
||||
for_array(i, using_entities) {
|
||||
Entity *e = using_entities[i].e;
|
||||
Entity *uvar = using_entities[i].uvar;
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
|
||||
if (!where_clause_ok) {
|
||||
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
||||
return;
|
||||
}
|
||||
|
||||
check_open_scope(ctx, body);
|
||||
{
|
||||
for_array(i, using_entities) {
|
||||
Entity *e = using_entities[i].e;
|
||||
Entity *uvar = using_entities[i].uvar;
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
// NOTE(bill): Don't err here
|
||||
}
|
||||
|
||||
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
||||
|
||||
if (type->Proc.result_count > 0) {
|
||||
if (!check_is_terminating(body)) {
|
||||
if (token.kind == Token_Ident) {
|
||||
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
|
||||
} else {
|
||||
// NOTE(bill): Anonymous procedure (lambda)
|
||||
error(bs->close, "Missing return statement at the end of the procedure");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check_close_scope(ctx);
|
||||
check_close_scope(ctx);
|
||||
|
||||
check_scope_usage(ctx->checker, ctx->scope);
|
||||
|
||||
#if 1
|
||||
if (decl->parent != nullptr) {
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
for_array(i, decl->deps.entries) {
|
||||
Entity *e = decl->deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->deps, e);
|
||||
}
|
||||
for_array(i, decl->type_info_deps.entries) {
|
||||
Type *t = decl->type_info_deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->type_info_deps, t);
|
||||
Scope *ps = decl->parent->scope;
|
||||
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
|
||||
return;
|
||||
} else {
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
// But only at the procedure level
|
||||
for_array(i, decl->deps.entries) {
|
||||
Entity *e = decl->deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->deps, e);
|
||||
}
|
||||
for_array(i, decl->type_info_deps.entries) {
|
||||
Type *t = decl->type_info_deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->type_info_deps, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1452
-220
File diff suppressed because it is too large
Load Diff
+269
-136
@@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(rs, InlineRangeStmt, node);
|
||||
return false;
|
||||
case_end;
|
||||
|
||||
case_ast_node(rs, RangeStmt, node);
|
||||
return false;
|
||||
case_end;
|
||||
@@ -172,6 +176,9 @@ bool check_is_terminating(Ast *node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return nullptr;
|
||||
@@ -249,48 +256,19 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
||||
case Addressing_Invalid:
|
||||
return nullptr;
|
||||
|
||||
case Addressing_Variable: {
|
||||
case Addressing_Variable:
|
||||
if (is_type_bit_field_value(lhs->type)) {
|
||||
Type *lt = base_type(lhs->type);
|
||||
i64 lhs_bits = lt->BitFieldValue.bits;
|
||||
if (rhs->mode == Addressing_Constant) {
|
||||
ExactValue v = exact_value_to_integer(rhs->value);
|
||||
if (v.kind == ExactValue_Integer) {
|
||||
BigInt i = v.value_integer;
|
||||
if (!i.neg) {
|
||||
u64 imax_ = ~cast(u64)0ull;
|
||||
if (lhs_bits < 64) {
|
||||
imax_ = (1ull << cast(u64)lhs_bits) - 1ull;
|
||||
}
|
||||
|
||||
BigInt imax = big_int_make_u64(imax_);
|
||||
if (big_int_cmp(&i, &imax) <= 0) {
|
||||
return rhs->type;
|
||||
}
|
||||
}
|
||||
} else if (rhs->value.kind == ExactValue_Bool) {
|
||||
bool b = rhs->value.value_bool;
|
||||
if (lhs_bits == 1) {
|
||||
return rhs->type;
|
||||
}
|
||||
}
|
||||
} else if (is_type_integer(rhs->type)) {
|
||||
// TODO(bill): Any other checks?
|
||||
return rhs->type;
|
||||
} else if (is_type_boolean(rhs->type)) {
|
||||
if (lhs_bits == 1) {
|
||||
return rhs->type;
|
||||
}
|
||||
Type *res = check_assignment_bit_field(ctx, rhs, lhs->type);
|
||||
if (res == nullptr) {
|
||||
gbString lhs_expr = expr_to_string(lhs->expr);
|
||||
gbString rhs_expr = expr_to_string(rhs->expr);
|
||||
error(rhs->expr, "Cannot assign '%s' to bit field '%s'", rhs_expr, lhs_expr);
|
||||
gb_string_free(rhs_expr);
|
||||
gb_string_free(lhs_expr);
|
||||
}
|
||||
gbString lhs_expr = expr_to_string(lhs->expr);
|
||||
gbString rhs_expr = expr_to_string(rhs->expr);
|
||||
error(rhs->expr, "Cannot assign '%s' to bit field '%s'", rhs_expr, lhs_expr);
|
||||
gb_string_free(rhs_expr);
|
||||
gb_string_free(lhs_expr);
|
||||
return nullptr;
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Addressing_MapIndex: {
|
||||
Ast *ln = unparen_expr(lhs->expr);
|
||||
@@ -315,6 +293,9 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
||||
break;
|
||||
}
|
||||
|
||||
case Addressing_SoaVariable:
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (lhs->expr->kind == Ast_SelectorExpr) {
|
||||
// NOTE(bill): Extra error checks
|
||||
@@ -329,9 +310,13 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
Entity *e = entity_of_ident(lhs->expr);
|
||||
|
||||
gbString str = expr_to_string(lhs->expr);
|
||||
if (lhs->mode == Addressing_Immutable) {
|
||||
error(lhs->expr, "Cannot assign to an immutable: '%s'", str);
|
||||
} else if (e != nullptr && e->flags & EntityFlag_Param) {
|
||||
error(lhs->expr, "Cannot assign to '%s' which is a procedure parameter", str);
|
||||
} else {
|
||||
error(lhs->expr, "Cannot assign to '%s'", str);
|
||||
}
|
||||
@@ -514,8 +499,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
|
||||
for_array(i, found->elements.entries) {
|
||||
Entity *f = found->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->using_expr = expr;
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
@@ -609,6 +593,162 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
|
||||
multi_map_insert(seen, key, tap);
|
||||
}
|
||||
|
||||
void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
ast_node(irs, InlineRangeStmt, node);
|
||||
check_open_scope(ctx, node);
|
||||
|
||||
Type *val0 = nullptr;
|
||||
Type *val1 = nullptr;
|
||||
Entity *entities[2] = {};
|
||||
isize entity_count = 0;
|
||||
|
||||
Ast *expr = unparen_expr(irs->expr);
|
||||
|
||||
ExactValue inline_for_depth = exact_value_i64(0);
|
||||
|
||||
if (is_ast_range(expr)) {
|
||||
ast_node(ie, BinaryExpr, expr);
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
|
||||
bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
|
||||
if (!ok) {
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
val0 = x.type;
|
||||
val1 = t_int;
|
||||
} else {
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr_or_type(ctx, &operand, irs->expr);
|
||||
|
||||
if (operand.mode == Addressing_Type) {
|
||||
if (!is_type_enum(operand.type)) {
|
||||
gbString t = type_to_string(operand.type);
|
||||
error(operand.expr, "Cannot iterate over the type '%s'", t);
|
||||
gb_string_free(t);
|
||||
goto skip_expr;
|
||||
} else {
|
||||
val0 = operand.type;
|
||||
val1 = t_int;
|
||||
add_type_info_type(ctx, operand.type);
|
||||
|
||||
Type *bt = base_type(operand.type);
|
||||
inline_for_depth = exact_value_i64(bt->Enum.fields.count);
|
||||
goto skip_expr;
|
||||
}
|
||||
} else if (operand.mode != Addressing_Invalid) {
|
||||
Type *t = base_type(operand.type);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
|
||||
val0 = t_rune;
|
||||
val1 = t_int;
|
||||
inline_for_depth = exact_value_i64(operand.value.value_string.len);
|
||||
}
|
||||
break;
|
||||
case Type_Array:
|
||||
val0 = t->Array.elem;
|
||||
val1 = t_int;
|
||||
inline_for_depth = exact_value_i64(t->Array.count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (val0 == nullptr) {
|
||||
gbString s = expr_to_string(operand.expr);
|
||||
gbString t = type_to_string(operand.type);
|
||||
error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(s);
|
||||
} else if (operand.mode != Addressing_Constant) {
|
||||
error(operand.expr, "An 'inline for' expression must be known at compile time");
|
||||
}
|
||||
}
|
||||
|
||||
skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
|
||||
|
||||
Ast * lhs[2] = {irs->val0, irs->val1};
|
||||
Type *rhs[2] = {val0, val1};
|
||||
|
||||
for (isize i = 0; i < 2; i++) {
|
||||
if (lhs[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
Ast * name = lhs[i];
|
||||
Type *type = rhs[i];
|
||||
|
||||
Entity *entity = nullptr;
|
||||
if (name->kind == Ast_Ident) {
|
||||
Token token = name->Ident.token;
|
||||
String str = token.string;
|
||||
Entity *found = nullptr;
|
||||
|
||||
if (!is_blank_ident(str)) {
|
||||
found = scope_lookup_current(ctx->scope, str);
|
||||
}
|
||||
if (found == nullptr) {
|
||||
bool is_immutable = true;
|
||||
entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved);
|
||||
entity->flags |= EntityFlag_Value;
|
||||
add_entity_definition(&ctx->checker->info, name, entity);
|
||||
} else {
|
||||
TokenPos pos = found->token.pos;
|
||||
error(token,
|
||||
"Redeclaration of '%.*s' in this scope\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(str), LIT(pos.file), pos.line, pos.column);
|
||||
entity = found;
|
||||
}
|
||||
} else {
|
||||
error(name, "A variable declaration must be an identifier");
|
||||
}
|
||||
|
||||
if (entity == nullptr) {
|
||||
entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name));
|
||||
}
|
||||
|
||||
entities[entity_count++] = entity;
|
||||
|
||||
if (type == nullptr) {
|
||||
entity->type = t_invalid;
|
||||
entity->flags |= EntityFlag_Used;
|
||||
}
|
||||
}
|
||||
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): Minimize the amount of nesting of an 'inline for'
|
||||
i64 prev_inline_for_depth = ctx->inline_for_depth;
|
||||
defer (ctx->inline_for_depth = prev_inline_for_depth);
|
||||
{
|
||||
i64 v = exact_value_to_i64(inline_for_depth);
|
||||
if (v <= 0) {
|
||||
// Do nothing
|
||||
} else {
|
||||
ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v;
|
||||
}
|
||||
|
||||
if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
|
||||
if (prev_inline_for_depth > 0) {
|
||||
error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
|
||||
} else {
|
||||
error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
|
||||
}
|
||||
error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n");
|
||||
ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH;
|
||||
}
|
||||
}
|
||||
|
||||
check_stmt(ctx, irs->body, mod_flags);
|
||||
|
||||
|
||||
check_close_scope(ctx);
|
||||
}
|
||||
|
||||
void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
ast_node(ss, SwitchStmt, node);
|
||||
|
||||
@@ -746,6 +886,13 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
if (upper_op == Token_GtEq) {
|
||||
add_constant_switch_case(ctx, &seen, rhs);
|
||||
}
|
||||
|
||||
if (is_type_string(x.type)) {
|
||||
// NOTE(bill): Force dependency for strings here
|
||||
add_package_dependency(ctx, "runtime", "string_le");
|
||||
add_package_dependency(ctx, "runtime", "string_lt");
|
||||
}
|
||||
|
||||
} else {
|
||||
Operand y = {};
|
||||
if (is_type_typeid(x.type)) {
|
||||
@@ -986,7 +1133,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
GB_PANIC("Unknown type to type switch statement");
|
||||
}
|
||||
|
||||
if (ptr_set_exists(&seen, y.type)) {
|
||||
if (type_ptr_set_exists(&seen, y.type)) {
|
||||
TokenPos pos = cc->token.pos;
|
||||
gbString expr_str = expr_to_string(y.expr);
|
||||
error(y.expr,
|
||||
@@ -1038,7 +1185,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
|
||||
for_array(i, variants) {
|
||||
Type *t = variants[i];
|
||||
if (!ptr_set_exists(&seen, t)) {
|
||||
if (!type_ptr_set_exists(&seen, t)) {
|
||||
array_add(&unhandled, t);
|
||||
}
|
||||
}
|
||||
@@ -1147,7 +1294,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
isize rhs_count = rhs_operands.count;
|
||||
for_array(i, rhs_operands) {
|
||||
if (rhs_operands[i].mode == Addressing_Invalid) {
|
||||
rhs_count--;
|
||||
// TODO(bill): Should I ignore invalid parameters?
|
||||
// rhs_count--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1183,7 +1331,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
be->right = as->rhs[0];
|
||||
|
||||
check_expr(ctx, &lhs, as->lhs[0]);
|
||||
check_binary_expr(ctx, &rhs, &binary_expr, true);
|
||||
check_binary_expr(ctx, &rhs, &binary_expr, nullptr, true);
|
||||
if (rhs.mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
@@ -1313,6 +1461,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
check_close_scope(ctx);
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(rs, RangeStmt, node);
|
||||
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
||||
|
||||
@@ -1330,104 +1479,31 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
|
||||
if (is_ast_range(expr)) {
|
||||
ast_node(ie, BinaryExpr, expr);
|
||||
Operand x = {Addressing_Invalid};
|
||||
Operand y = {Addressing_Invalid};
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
|
||||
check_expr(ctx, &x, ie->left);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
bool ok = check_range(ctx, expr, &x, &y, nullptr);
|
||||
if (!ok) {
|
||||
goto skip_expr_range_stmt;
|
||||
}
|
||||
check_expr(ctx, &y, ie->right);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
convert_to_typed(ctx, &x, y.type);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
convert_to_typed(ctx, &y, x.type);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
convert_to_typed(ctx, &x, default_type(y.type));
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
convert_to_typed(ctx, &y, default_type(x.type));
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
if (!are_types_identical(x.type, y.type)) {
|
||||
if (x.type != t_invalid &&
|
||||
y.type != t_invalid) {
|
||||
gbString xt = type_to_string(x.type);
|
||||
gbString yt = type_to_string(y.type);
|
||||
gbString expr_str = expr_to_string(x.expr);
|
||||
error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
|
||||
gb_string_free(expr_str);
|
||||
gb_string_free(yt);
|
||||
gb_string_free(xt);
|
||||
}
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
Type *type = x.type;
|
||||
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
|
||||
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
||||
goto skip_expr;
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Constant &&
|
||||
y.mode == Addressing_Constant) {
|
||||
ExactValue a = x.value;
|
||||
ExactValue b = y.value;
|
||||
|
||||
GB_ASSERT(are_types_identical(x.type, y.type));
|
||||
|
||||
TokenKind op = Token_Lt;
|
||||
switch (ie->op.kind) {
|
||||
case Token_Ellipsis: op = Token_LtEq; break;
|
||||
case Token_RangeHalf: op = Token_Lt; break;
|
||||
default: error(ie->op, "Invalid range operator"); break;
|
||||
}
|
||||
bool ok = compare_exact_values(op, a, b);
|
||||
if (!ok) {
|
||||
// TODO(bill): Better error message
|
||||
error(ie->op, "Invalid interval range");
|
||||
goto skip_expr;
|
||||
}
|
||||
}
|
||||
|
||||
if (x.mode != Addressing_Constant) {
|
||||
x.value = empty_exact_value;
|
||||
}
|
||||
if (y.mode != Addressing_Constant) {
|
||||
y.value = empty_exact_value;
|
||||
}
|
||||
|
||||
|
||||
add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value);
|
||||
add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
|
||||
val0 = type;
|
||||
val0 = x.type;
|
||||
val1 = t_int;
|
||||
} else {
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr_or_type(ctx, &operand, rs->expr);
|
||||
check_expr_base(ctx, &operand, expr, nullptr);
|
||||
error_operand_no_value(&operand);
|
||||
|
||||
if (operand.mode == Addressing_Type) {
|
||||
if (!is_type_enum(operand.type)) {
|
||||
gbString t = type_to_string(operand.type);
|
||||
error(operand.expr, "Cannot iterate over the type '%s'", t);
|
||||
gb_string_free(t);
|
||||
goto skip_expr;
|
||||
goto skip_expr_range_stmt;
|
||||
} else {
|
||||
val0 = operand.type;
|
||||
val1 = t_int;
|
||||
add_type_info_type(ctx, operand.type);
|
||||
goto skip_expr;
|
||||
goto skip_expr_range_stmt;
|
||||
}
|
||||
} else if (operand.mode != Addressing_Invalid) {
|
||||
bool is_ptr = is_type_pointer(operand.type);
|
||||
@@ -1460,6 +1536,45 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
val0 = t->Map.key;
|
||||
val1 = t->Map.value;
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
if (false) {
|
||||
check_not_tuple(ctx, &operand);
|
||||
} else {
|
||||
isize count = t->Tuple.variables.count;
|
||||
if (count < 1 || count > 3) {
|
||||
check_not_tuple(ctx, &operand);
|
||||
error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n");
|
||||
break;
|
||||
}
|
||||
Type *cond_type = t->Tuple.variables[count-1]->type;
|
||||
if (!is_type_boolean(cond_type)) {
|
||||
gbString s = type_to_string(cond_type);
|
||||
error(operand.expr, "The final type of %td-valued tuple must be a boolean, got %s", count, s);
|
||||
gb_string_free(s);
|
||||
break;
|
||||
}
|
||||
|
||||
if (count > 1) val0 = t->Tuple.variables[0]->type;
|
||||
if (count > 2) val1 = t->Tuple.variables[1]->type;
|
||||
|
||||
if (rs->val1 != nullptr && count < 3) {
|
||||
gbString s = type_to_string(t);
|
||||
error(operand.expr, "Expected a 3-value tuple on the rhs, got (%s)", s);
|
||||
gb_string_free(s);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rs->val0 != nullptr && count < 2) {
|
||||
gbString s = type_to_string(t);
|
||||
error(operand.expr, "Expected at least a 2-values tuple on the rhs, got (%s)", s);
|
||||
gb_string_free(s);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1472,7 +1587,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
|
||||
skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
|
||||
skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
|
||||
|
||||
Ast * lhs[2] = {rs->val0, rs->val1};
|
||||
Type *rhs[2] = {val0, val1};
|
||||
|
||||
@@ -1522,7 +1638,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
}
|
||||
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
|
||||
Entity *e = entities[i];
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
GB_ASSERT(d == nullptr);
|
||||
add_entity(ctx->checker, ctx->scope, e->identifier, e);
|
||||
d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl);
|
||||
add_entity_and_decl_info(ctx, e->identifier, e, d);
|
||||
}
|
||||
|
||||
check_stmt(ctx, rs->body, new_flags);
|
||||
@@ -1530,6 +1651,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
check_close_scope(ctx);
|
||||
case_end;
|
||||
|
||||
case_ast_node(irs, InlineRangeStmt, node);
|
||||
check_inline_range_stmt(ctx, node, mod_flags);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ss, SwitchStmt, node);
|
||||
check_switch_stmt(ctx, node, mod_flags);
|
||||
case_end;
|
||||
@@ -1729,11 +1854,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str);
|
||||
gb_string_free(str);
|
||||
init_type = t_invalid;
|
||||
} else if (is_type_empty_union(init_type)) {
|
||||
gbString str = type_to_string(init_type);
|
||||
error(vd->type, "An empty union '%s' cannot be instantiated in variable declaration", str);
|
||||
gb_string_free(str);
|
||||
init_type = t_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1772,6 +1892,19 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
e->flags |= EntityFlag_Static;
|
||||
}
|
||||
}
|
||||
if (ac.thread_local_model != "") {
|
||||
String name = e->token.string;
|
||||
if (name == "_") {
|
||||
error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'");
|
||||
} else {
|
||||
e->flags |= EntityFlag_Static;
|
||||
}
|
||||
e->Variable.thread_local_model = ac.thread_local_model;
|
||||
}
|
||||
|
||||
if (ac.is_static && ac.thread_local_model != "") {
|
||||
error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied");
|
||||
}
|
||||
}
|
||||
|
||||
check_arity_match(ctx, vd);
|
||||
@@ -1834,7 +1967,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
// TODO(bill): Should a 'continue' happen here?
|
||||
}
|
||||
|
||||
for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
|
||||
for (isize entity_index = 0; entity_index < 1; entity_index++) {
|
||||
Entity *e = entities[entity_index];
|
||||
if (e == nullptr) {
|
||||
continue;
|
||||
@@ -1853,7 +1986,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
|
||||
+390
-53
@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const ¶ms,
|
||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Array<Ast *> const ¶ms,
|
||||
isize init_field_capacity, Type *struct_type, String context) {
|
||||
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
||||
*tags = array_make<String>(heap_allocator(), 0, init_field_capacity);
|
||||
|
||||
GB_ASSERT(node->kind == Ast_StructType);
|
||||
GB_ASSERT(struct_type->kind == Type_Struct);
|
||||
@@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
|
||||
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
|
||||
add_entity(ctx->checker, ctx->scope, name, field);
|
||||
array_add(fields, field);
|
||||
array_add(tags, p->tag.string);
|
||||
|
||||
field_src_index += 1;
|
||||
}
|
||||
@@ -246,38 +248,51 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
}
|
||||
|
||||
|
||||
Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
|
||||
Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
|
||||
auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
|
||||
if (found_gen_types != nullptr) {
|
||||
for_array(i, *found_gen_types) {
|
||||
Entity *e = (*found_gen_types)[i];
|
||||
Type *t = base_type(e->type);
|
||||
TypeTuple *tuple = get_record_polymorphic_params(t);
|
||||
bool ok = true;
|
||||
GB_ASSERT(param_count == tuple->variables.count);
|
||||
|
||||
bool skip = false;
|
||||
|
||||
for (isize j = 0; j < param_count; j++) {
|
||||
Entity *p = tuple->variables[j];
|
||||
Operand o = ordered_operands[j];
|
||||
Entity *oe = entity_of_node(o.expr);
|
||||
if (p == oe) {
|
||||
// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
|
||||
// Saves on a lot of checking too below
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->kind == Entity_TypeName) {
|
||||
if (is_type_polymorphic(o.type)) {
|
||||
// NOTE(bill): Do not add polymorphic version to the gen_types
|
||||
ok = false;
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
ok = false;
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
} else if (p->kind == Entity_Constant) {
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
ok = false;
|
||||
}
|
||||
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
|
||||
ok = false;
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GB_PANIC("Unknown entity kind");
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (!skip) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
@@ -439,8 +454,6 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
if (poly_operands != nullptr) {
|
||||
Operand operand = (*poly_operands)[entities.count];
|
||||
if (is_type_param) {
|
||||
GB_ASSERT(operand.mode == Addressing_Type ||
|
||||
operand.mode == Addressing_Invalid);
|
||||
if (is_type_polymorphic(base_type(operand.type))) {
|
||||
is_polymorphic = true;
|
||||
can_check_fields = false;
|
||||
@@ -448,6 +461,10 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
e = alloc_entity_type_name(scope, token, operand.type);
|
||||
e->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
if (is_type_polymorphic(base_type(operand.type))) {
|
||||
is_polymorphic = true;
|
||||
can_check_fields = false;
|
||||
}
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
}
|
||||
} else {
|
||||
@@ -502,9 +519,13 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
struct_type->Struct.polymorphic_params = polymorphic_params;
|
||||
struct_type->Struct.is_poly_specialized = is_poly_specialized;
|
||||
|
||||
|
||||
if (!is_polymorphic) {
|
||||
check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context);
|
||||
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
|
||||
error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
|
||||
} else {
|
||||
bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true);
|
||||
}
|
||||
check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
|
||||
}
|
||||
|
||||
if (st->align != nullptr) {
|
||||
@@ -686,6 +707,13 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
union_type->Union.is_polymorphic = is_polymorphic;
|
||||
union_type->Union.is_poly_specialized = is_poly_specialized;
|
||||
|
||||
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
|
||||
error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
|
||||
} else {
|
||||
bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true);
|
||||
}
|
||||
|
||||
|
||||
for_array(i, ut->variants) {
|
||||
Ast *node = ut->variants[i];
|
||||
Type *t = check_type_expr(ctx, node, nullptr);
|
||||
@@ -715,6 +743,12 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
}
|
||||
|
||||
union_type->Union.variants = variants;
|
||||
union_type->Union.no_nil = ut->no_nil;
|
||||
if (union_type->Union.no_nil) {
|
||||
if (variants.count < 2) {
|
||||
error(ut->align, "A union with #no_nil must have at least 2 variants");
|
||||
}
|
||||
}
|
||||
|
||||
if (ut->align != nullptr) {
|
||||
i64 custom_align = 1;
|
||||
@@ -1246,20 +1280,21 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
|
||||
|
||||
Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) {
|
||||
bool modify_type = !ctx->no_polymorphic_errors;
|
||||
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
|
||||
if (!is_operand_value(operand)) {
|
||||
if (modify_type) {
|
||||
if (show_error) {
|
||||
error(operand.expr, "Cannot determine polymorphic type from parameter");
|
||||
}
|
||||
return t_invalid;
|
||||
}
|
||||
|
||||
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
|
||||
if (modify_type) {
|
||||
set_procedure_abi_types(ctx, poly_type);
|
||||
if (show_error) {
|
||||
set_procedure_abi_types(ctx->allocator, poly_type);
|
||||
}
|
||||
return poly_type;
|
||||
}
|
||||
if (modify_type) {
|
||||
if (show_error) {
|
||||
gbString pts = type_to_string(poly_type);
|
||||
gbString ots = type_to_string(operand.type);
|
||||
defer (gb_string_free(pts));
|
||||
@@ -1513,18 +1548,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
}
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_in) {
|
||||
if (is_type_param) {
|
||||
error(param, "'in' cannot be applied to a type parameter");
|
||||
p->flags &= ~FieldFlag_in;
|
||||
} else if (is_variadic) {
|
||||
error(param, "'in' cannot be applied to a variadic parameter");
|
||||
p->flags &= ~FieldFlag_in;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_in = (p->flags&FieldFlag_in) != 0;
|
||||
|
||||
for_array(j, p->names) {
|
||||
Ast *name = p->names[j];
|
||||
|
||||
@@ -1544,7 +1567,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
}
|
||||
|
||||
if (is_poly_name) {
|
||||
if (type != nullptr && type_expr->kind == Ast_TypeidType) {
|
||||
if (type_expr != nullptr && type_expr->kind == Ast_TypeidType) {
|
||||
is_type_param = true;
|
||||
} else {
|
||||
if (param_value.kind != ParameterValue_Invalid) {
|
||||
@@ -1628,6 +1651,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
if (op.mode == Addressing_Constant) {
|
||||
poly_const = op.value;
|
||||
} else {
|
||||
error(op.expr, "Expected a constant value for this polymorphic name parameter");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
@@ -1664,7 +1688,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
|
||||
param = alloc_entity_const_param(scope, name->Ident.token, type, poly_const, is_type_polymorphic(type));
|
||||
} else {
|
||||
param = alloc_entity_param(scope, name->Ident.token, type, is_using, is_in);
|
||||
param = alloc_entity_param(scope, name->Ident.token, type, is_using, true);
|
||||
param->Variable.param_value = param_value;
|
||||
}
|
||||
}
|
||||
@@ -1831,6 +1855,282 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
||||
return tuple;
|
||||
}
|
||||
|
||||
Array<Type *> systemv_distribute_struct_fields(Type *t) {
|
||||
Type *bt = core_type(t);
|
||||
|
||||
|
||||
isize distributed_cap = 1;
|
||||
if (bt->kind == Type_Struct) {
|
||||
distributed_cap = bt->Struct.fields.count;
|
||||
}
|
||||
auto distributed = array_make<Type *>(heap_allocator(), 0, distributed_cap);
|
||||
|
||||
i64 sz = type_size_of(bt);
|
||||
switch (bt->kind) {
|
||||
case Type_Basic:
|
||||
switch (bt->Basic.kind){
|
||||
case Basic_complex64:
|
||||
array_add(&distributed, t_f32);
|
||||
array_add(&distributed, t_f32);
|
||||
break;
|
||||
case Basic_complex128:
|
||||
array_add(&distributed, t_f64);
|
||||
array_add(&distributed, t_f64);
|
||||
break;
|
||||
case Basic_quaternion128:
|
||||
array_add(&distributed, t_f32);
|
||||
array_add(&distributed, t_f32);
|
||||
array_add(&distributed, t_f32);
|
||||
array_add(&distributed, t_f32);
|
||||
break;
|
||||
case Basic_quaternion256:
|
||||
goto DEFAULT;
|
||||
case Basic_string:
|
||||
array_add(&distributed, t_u8_ptr);
|
||||
array_add(&distributed, t_int);
|
||||
break;
|
||||
case Basic_any:
|
||||
GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid));
|
||||
array_add(&distributed, t_rawptr);
|
||||
array_add(&distributed, t_uintptr);
|
||||
break;
|
||||
|
||||
case Basic_u128:
|
||||
case Basic_i128:
|
||||
if (build_context.ODIN_OS == "windows") {
|
||||
array_add(&distributed, alloc_type_simd_vector(2, t_u64));
|
||||
} else {
|
||||
array_add(&distributed, bt);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Struct:
|
||||
if (bt->Struct.is_raw_union) {
|
||||
goto DEFAULT;
|
||||
} else {
|
||||
// IMPORTANT TOOD(bill): handle #packed structs correctly
|
||||
// IMPORTANT TODO(bill): handle #align structs correctly
|
||||
for_array(field_index, bt->Struct.fields) {
|
||||
Entity *f = bt->Struct.fields[field_index];
|
||||
auto nested = systemv_distribute_struct_fields(f->type);
|
||||
array_add_elems(&distributed, nested.data, nested.count);
|
||||
array_free(&nested);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Array:
|
||||
for (i64 i = 0; i < bt->Array.count; i++) {
|
||||
array_add(&distributed, bt->Array.elem);
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_BitSet:
|
||||
array_add(&distributed, bit_set_to_int(bt));
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
GB_PANIC("Invalid struct field type");
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
array_add(&distributed, t_rawptr);
|
||||
array_add(&distributed, t_int);
|
||||
break;
|
||||
|
||||
case Type_Union:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
case Type_BitField: // TODO(bill): Ignore?
|
||||
// NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet
|
||||
goto DEFAULT;
|
||||
|
||||
case Type_Pointer:
|
||||
case Type_Proc:
|
||||
case Type_SimdVector: // TODO(bill): Is this correct logic?
|
||||
default:
|
||||
DEFAULT:;
|
||||
if (sz > 0) {
|
||||
array_add(&distributed, bt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return distributed;
|
||||
}
|
||||
|
||||
Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) {
|
||||
GB_ASSERT(is_type_tuple(abi_type));
|
||||
Type *final_type = alloc_type_struct();
|
||||
final_type->Struct.fields = abi_type->Tuple.variables;
|
||||
return final_type;
|
||||
}
|
||||
|
||||
|
||||
Type *handle_single_distributed_type_parameter(Array<Type *> const &types, bool packed, isize *offset) {
|
||||
GB_ASSERT(types.count > 0);
|
||||
|
||||
if (types.count == 1) {
|
||||
if (offset) *offset = 1;
|
||||
|
||||
i64 sz = type_size_of(types[0]);
|
||||
|
||||
if (is_type_float(types[0])) {
|
||||
return types[0];
|
||||
}
|
||||
switch (sz) {
|
||||
case 0:
|
||||
GB_PANIC("Zero sized type found!");
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
case 8: return t_u64;
|
||||
default:
|
||||
return types[0];
|
||||
}
|
||||
} else if (types.count >= 2) {
|
||||
if (types[0] == t_f32 && types[1] == t_f32) {
|
||||
if (offset) *offset = 2;
|
||||
return alloc_type_simd_vector(2, t_f32);
|
||||
} else if (type_size_of(types[0]) == 8) {
|
||||
if (offset) *offset = 1;
|
||||
return types[0];
|
||||
}
|
||||
|
||||
i64 total_size = 0;
|
||||
isize i = 0;
|
||||
if (packed) {
|
||||
for (; i < types.count && total_size < 8; i += 1) {
|
||||
Type *t = types[i];
|
||||
i64 s = type_size_of(t);
|
||||
total_size += s;
|
||||
}
|
||||
} else {
|
||||
for (; i < types.count && total_size < 8; i += 1) {
|
||||
Type *t = types[i];
|
||||
i64 s = gb_max(type_size_of(t), 0);
|
||||
i64 a = gb_max(type_align_of(t), 1);
|
||||
isize ts = align_formula(total_size, a);
|
||||
if (ts >= 8) {
|
||||
break;
|
||||
}
|
||||
total_size = ts + s;
|
||||
}
|
||||
}
|
||||
if (offset) *offset = i;
|
||||
switch (total_size) {
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
case 8: return t_u64;
|
||||
}
|
||||
return t_u64;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *handle_struct_system_v_amd64_abi_type(Type *t) {
|
||||
if (type_size_of(t) > 16) {
|
||||
return alloc_type_pointer(t);
|
||||
}
|
||||
Type *original_type = t;
|
||||
Type *bt = core_type(t);
|
||||
t = base_type(t);
|
||||
i64 size = type_size_of(bt);
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Slice:
|
||||
case Type_Struct:
|
||||
break;
|
||||
|
||||
case Type_Basic:
|
||||
switch (bt->Basic.kind) {
|
||||
case Basic_string:
|
||||
case Basic_any:
|
||||
case Basic_complex64:
|
||||
case Basic_complex128:
|
||||
case Basic_quaternion128:
|
||||
break;
|
||||
default:
|
||||
return original_type;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return original_type;
|
||||
}
|
||||
|
||||
bool is_packed = false;
|
||||
if (is_type_struct(bt)) {
|
||||
is_packed = bt->Struct.is_packed;
|
||||
}
|
||||
|
||||
if (is_type_raw_union(bt)) {
|
||||
// TODO(bill): Handle raw union correctly for
|
||||
return t;
|
||||
} else {
|
||||
auto field_types = systemv_distribute_struct_fields(bt);
|
||||
defer (array_free(&field_types));
|
||||
|
||||
GB_ASSERT(field_types.count <= 16);
|
||||
|
||||
Type *final_type = nullptr;
|
||||
|
||||
if (field_types.count == 0) {
|
||||
final_type = t;
|
||||
} else if (field_types.count == 1) {
|
||||
final_type = field_types[0];
|
||||
} else {
|
||||
if (size <= 8) {
|
||||
isize offset = 0;
|
||||
final_type = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
|
||||
} else {
|
||||
isize offset = 0;
|
||||
isize next_offset = 0;
|
||||
Type *two_types[2] = {};
|
||||
|
||||
two_types[0] = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
|
||||
auto remaining = array_slice(field_types, offset, field_types.count);
|
||||
two_types[1] = handle_single_distributed_type_parameter(remaining, is_packed, &next_offset);
|
||||
GB_ASSERT(offset + next_offset == field_types.count);
|
||||
|
||||
auto variables = array_make<Entity *>(heap_allocator(), 2);
|
||||
variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false);
|
||||
variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false);
|
||||
final_type = alloc_type_tuple();
|
||||
final_type->Tuple.variables = variables;
|
||||
if (t->kind == Type_Struct) {
|
||||
// NOTE(bill): Make this packed
|
||||
final_type->Tuple.is_packed = t->Struct.is_packed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GB_ASSERT(final_type != nullptr);
|
||||
i64 ftsz = type_size_of(final_type);
|
||||
i64 otsz = type_size_of(original_type);
|
||||
if (ftsz != otsz) {
|
||||
// TODO(bill): Handle this case which will be caused by #packed most likely
|
||||
switch (otsz) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %s %lld vs %s %lld", type_to_string(final_type), ftsz, type_to_string(original_type), otsz);
|
||||
}
|
||||
}
|
||||
|
||||
return final_type;
|
||||
}
|
||||
}
|
||||
|
||||
Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
|
||||
Type *new_type = original_type;
|
||||
|
||||
@@ -1895,6 +2195,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
||||
{
|
||||
i64 align = type_align_of(original_type);
|
||||
i64 size = type_size_of(original_type);
|
||||
|
||||
switch (8*size) {
|
||||
case 8: new_type = t_u8; break;
|
||||
case 16: new_type = t_u16; break;
|
||||
@@ -1909,7 +2210,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
||||
}
|
||||
}
|
||||
} else if (build_context.ODIN_OS == "linux" ||
|
||||
build_context.ODIN_OS == "osx") {
|
||||
build_context.ODIN_OS == "darwin") {
|
||||
Type *bt = core_type(original_type);
|
||||
switch (bt->kind) {
|
||||
// Okay to pass by value (usually)
|
||||
@@ -1926,18 +2227,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
||||
case Type_Pointer: break;
|
||||
case Type_Proc: break; // NOTE(bill): Just a pointer
|
||||
|
||||
// Odin specific
|
||||
case Type_Slice:
|
||||
case Type_Array:
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
case Type_Union:
|
||||
// Could be in C too
|
||||
case Type_Struct: {
|
||||
i64 align = type_align_of(original_type);
|
||||
i64 size = type_size_of(original_type);
|
||||
if (8*size > 16) {
|
||||
default: {
|
||||
i64 size = type_size_of(original_type);
|
||||
if (size > 16) {
|
||||
new_type = alloc_type_pointer(original_type);
|
||||
} else if (build_context.ODIN_ARCH == "amd64") {
|
||||
// NOTE(bill): System V AMD64 ABI
|
||||
new_type = handle_struct_system_v_amd64_abi_type(bt);
|
||||
if (are_types_identical(core_type(original_type), new_type)) {
|
||||
new_type = original_type;
|
||||
}
|
||||
return new_type;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2010,8 +2310,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (build_context.ODIN_OS == "linux") {
|
||||
} else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") {
|
||||
if (build_context.ODIN_ARCH == "amd64") {
|
||||
|
||||
}
|
||||
} else {
|
||||
// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
|
||||
// their architectures
|
||||
@@ -2077,25 +2379,52 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_procedure_abi_types(CheckerContext *c, Type *type) {
|
||||
void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||
type = base_type(type);
|
||||
if (type->kind != Type_Proc) {
|
||||
return;
|
||||
}
|
||||
|
||||
type->Proc.abi_compat_params = array_make<Type *>(c->allocator, cast(isize)type->Proc.param_count);
|
||||
if (type->Proc.abi_types_set) {
|
||||
return;
|
||||
}
|
||||
|
||||
type->Proc.abi_compat_params = array_make<Type *>(allocator, cast(isize)type->Proc.param_count);
|
||||
for (i32 i = 0; i < type->Proc.param_count; i++) {
|
||||
Entity *e = type->Proc.params->Tuple.variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
Type *original_type = e->type;
|
||||
Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention);
|
||||
Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention);
|
||||
type->Proc.abi_compat_params[i] = new_type;
|
||||
switch (type->Proc.calling_convention) {
|
||||
case ProcCC_Odin:
|
||||
case ProcCC_Contextless:
|
||||
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
|
||||
e->flags |= EntityFlag_ImplicitReference;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < type->Proc.param_count; i++) {
|
||||
Entity *e = type->Proc.params->Tuple.variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
set_procedure_abi_types(allocator, e->type);
|
||||
}
|
||||
}
|
||||
for (i32 i = 0; i < type->Proc.result_count; i++) {
|
||||
Entity *e = type->Proc.results->Tuple.variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
set_procedure_abi_types(allocator, e->type);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): The types are the same
|
||||
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention);
|
||||
type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
|
||||
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention);
|
||||
type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
|
||||
|
||||
type->Proc.abi_types_set = true;
|
||||
}
|
||||
|
||||
// NOTE(bill): 'operands' is for generating non generic procedure type
|
||||
@@ -2191,10 +2520,18 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
Entity *e = results->Tuple.variables[i];
|
||||
if (e->kind != Entity_Variable) {
|
||||
is_polymorphic = true;
|
||||
break;
|
||||
} else if (is_type_polymorphic(e->type)) {
|
||||
is_polymorphic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
type->Proc.is_polymorphic = is_polymorphic;
|
||||
|
||||
set_procedure_abi_types(c, type);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -2543,7 +2880,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
generic_type = o.type;
|
||||
}
|
||||
if (count < 0) {
|
||||
error(at->count, "... can only be used in conjuction with compound literals");
|
||||
error(at->count, "? can only be used in conjuction with compound literals");
|
||||
count = 0;
|
||||
}
|
||||
Type *elem = check_type_expr(ctx, at->elem, nullptr);
|
||||
|
||||
+211
-100
@@ -13,6 +13,7 @@ bool is_operand_value(Operand o) {
|
||||
case Addressing_Constant:
|
||||
case Addressing_MapIndex:
|
||||
case Addressing_OptionalOk:
|
||||
case Addressing_SoaVariable:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -85,9 +86,13 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) {
|
||||
EntityGraphNode *y = data[j];
|
||||
isize a = x->entity->order_in_src;
|
||||
isize b = y->entity->order_in_src;
|
||||
if (x->dep_count < y->dep_count) return -1;
|
||||
if (x->dep_count > y->dep_count) return +1;
|
||||
return a < b ? -1 : b > a;
|
||||
if (x->dep_count < y->dep_count) {
|
||||
return -1;
|
||||
}
|
||||
if (x->dep_count == y->dep_count) {
|
||||
return a < b ? -1 : b > a;
|
||||
}
|
||||
return +1;
|
||||
}
|
||||
|
||||
void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
|
||||
@@ -400,6 +405,15 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
|
||||
Entity **found = map_get(&s->parent->elements, key);
|
||||
if (found) {
|
||||
if ((*found)->flags & EntityFlag_Result) {
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map_set(&s->elements, key, entity);
|
||||
if (entity->scope == nullptr) {
|
||||
entity->scope = s;
|
||||
@@ -790,6 +804,7 @@ void init_checker_info(CheckerInfo *i) {
|
||||
map_init(&i->files, a);
|
||||
map_init(&i->packages, a);
|
||||
array_init(&i->variable_init_order, a);
|
||||
array_init(&i->required_foreign_imports_through_force, a);
|
||||
|
||||
i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions;
|
||||
if (i->allow_identifier_uses) {
|
||||
@@ -810,6 +825,8 @@ void destroy_checker_info(CheckerInfo *i) {
|
||||
map_destroy(&i->packages);
|
||||
array_free(&i->variable_init_order);
|
||||
array_free(&i->identifier_uses);
|
||||
array_free(&i->required_foreign_imports_through_force);
|
||||
|
||||
}
|
||||
|
||||
CheckerContext make_checker_context(Checker *c) {
|
||||
@@ -1017,7 +1034,11 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty
|
||||
|
||||
expr->tav.mode = mode;
|
||||
expr->tav.type = type;
|
||||
expr->tav.value = value;
|
||||
if (mode == Addressing_Constant || mode == Addressing_Invalid) {
|
||||
expr->tav.value = value;
|
||||
} else if (mode == Addressing_Value && is_type_typeid(type)) {
|
||||
expr->tav.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) {
|
||||
@@ -1044,21 +1065,37 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) {
|
||||
// NOTE(bill): Error should have been handled already
|
||||
return false;
|
||||
}
|
||||
error(prev->token,
|
||||
"Redeclaration of '%.*s' in this scope through 'using'\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name),
|
||||
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
|
||||
if (found->flags & EntityFlag_Result) {
|
||||
error(prev->token,
|
||||
"Direct shadowing of the named return value '%.*s' in this scope through 'using'\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name),
|
||||
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
|
||||
} else {
|
||||
error(prev->token,
|
||||
"Redeclaration of '%.*s' in this scope through 'using'\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name),
|
||||
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
|
||||
}
|
||||
} else {
|
||||
if (pos == prev->token.pos) {
|
||||
// NOTE(bill): Error should have been handled already
|
||||
return false;
|
||||
}
|
||||
error(prev->token,
|
||||
"Redeclaration of '%.*s' in this scope\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name),
|
||||
LIT(pos.file), pos.line, pos.column);
|
||||
if (found->flags & EntityFlag_Result) {
|
||||
error(prev->token,
|
||||
"Direct shadowing of the named return value '%.*s' in this scope\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name),
|
||||
LIT(pos.file), pos.line, pos.column);
|
||||
} else {
|
||||
error(prev->token,
|
||||
"Redeclaration of '%.*s' in this scope\n"
|
||||
"\tat %.*s(%td:%td)",
|
||||
LIT(name),
|
||||
LIT(pos.file), pos.line, pos.column);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1139,6 +1176,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec
|
||||
add_entity_definition(&c->checker->info, identifier, e);
|
||||
GB_ASSERT(e->decl_info == nullptr);
|
||||
e->decl_info = d;
|
||||
d->entity = e;
|
||||
array_add(&c->checker->info.entities, e);
|
||||
e->order_in_src = c->checker->info.entities.count;
|
||||
e->pkg = c->pkg;
|
||||
@@ -1220,6 +1258,9 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
break;
|
||||
case Type_Basic:
|
||||
switch (bt->Basic.kind) {
|
||||
case Basic_cstring:
|
||||
add_type_info_type(c, t_u8_ptr);
|
||||
break;
|
||||
case Basic_string:
|
||||
add_type_info_type(c, t_u8_ptr);
|
||||
add_type_info_type(c, t_int);
|
||||
@@ -1239,6 +1280,14 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
add_type_info_type(c, t_type_info_float);
|
||||
add_type_info_type(c, t_f64);
|
||||
break;
|
||||
case Basic_quaternion128:
|
||||
add_type_info_type(c, t_type_info_float);
|
||||
add_type_info_type(c, t_f32);
|
||||
break;
|
||||
case Basic_quaternion256:
|
||||
add_type_info_type(c, t_type_info_float);
|
||||
add_type_info_type(c, t_f64);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1293,7 +1342,11 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
if (bt->Struct.scope != nullptr) {
|
||||
for_array(i, bt->Struct.scope->elements.entries) {
|
||||
Entity *e = bt->Struct.scope->elements.entries[i].value;
|
||||
add_type_info_type(c, e->type);
|
||||
if (bt->Struct.is_soa) {
|
||||
add_type_info_type(c, alloc_type_pointer(e->type));
|
||||
} else {
|
||||
add_type_info_type(c, e->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
for_array(i, bt->Struct.fields) {
|
||||
@@ -1415,6 +1468,14 @@ void add_min_dep_type_info(Checker *c, Type *t) {
|
||||
add_min_dep_type_info(c, t_type_info_float);
|
||||
add_min_dep_type_info(c, t_f64);
|
||||
break;
|
||||
case Basic_quaternion128:
|
||||
add_min_dep_type_info(c, t_type_info_float);
|
||||
add_min_dep_type_info(c, t_f32);
|
||||
break;
|
||||
case Basic_quaternion256:
|
||||
add_min_dep_type_info(c, t_type_info_float);
|
||||
add_min_dep_type_info(c, t_f64);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1577,6 +1638,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
|
||||
str_lit("args__"),
|
||||
str_lit("type_table"),
|
||||
str_lit("__type_info_of"),
|
||||
str_lit("global_scratch_allocator"),
|
||||
|
||||
str_lit("Type_Info"),
|
||||
@@ -1585,9 +1647,17 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
|
||||
str_lit("quo_complex64"),
|
||||
str_lit("quo_complex128"),
|
||||
str_lit("mul_quaternion128"),
|
||||
str_lit("mul_quaternion256"),
|
||||
str_lit("quo_quaternion128"),
|
||||
str_lit("quo_quaternion256"),
|
||||
str_lit("cstring_to_string"),
|
||||
|
||||
str_lit("umodti3"),
|
||||
str_lit("udivti3"),
|
||||
|
||||
str_lit("memory_compare"),
|
||||
str_lit("memory_compare_zero"),
|
||||
};
|
||||
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
|
||||
add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
|
||||
@@ -1649,6 +1719,11 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, c->info.required_foreign_imports_through_force) {
|
||||
Entity *e = c->info.required_foreign_imports_through_force[i];
|
||||
add_dependency_to_set(c, e);
|
||||
}
|
||||
|
||||
add_dependency_to_set(c, start);
|
||||
}
|
||||
|
||||
@@ -1656,9 +1731,10 @@ bool is_entity_a_dependency(Entity *e) {
|
||||
if (e == nullptr) return false;
|
||||
switch (e->kind) {
|
||||
case Entity_Procedure:
|
||||
case Entity_Variable:
|
||||
case Entity_Constant:
|
||||
return true;
|
||||
case Entity_Constant:
|
||||
case Entity_Variable:
|
||||
return e->pkg != nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1679,28 +1755,35 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
||||
}
|
||||
}
|
||||
|
||||
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
|
||||
|
||||
|
||||
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1");
|
||||
// Calculate edges for graph M
|
||||
for_array(i, M.entries) {
|
||||
Entity * e = cast(Entity *)M.entries[i].key.ptr;
|
||||
EntityGraphNode *n = M.entries[i].value;
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
if (decl != nullptr) {
|
||||
for_array(j, decl->deps.entries) {
|
||||
auto entry = decl->deps.entries[j];
|
||||
Entity *dep = entry.ptr;
|
||||
if (dep && is_entity_a_dependency(dep)) {
|
||||
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
|
||||
if (m_ != nullptr) {
|
||||
EntityGraphNode *m = *m_;
|
||||
entity_graph_node_set_add(&n->succ, m);
|
||||
entity_graph_node_set_add(&m->pred, n);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(decl != nullptr);
|
||||
|
||||
for_array(j, decl->deps.entries) {
|
||||
Entity *dep = decl->deps.entries[j].ptr;
|
||||
GB_ASSERT(dep != nullptr);
|
||||
if (is_entity_a_dependency(dep)) {
|
||||
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
|
||||
GB_ASSERT(m_ != nullptr);
|
||||
EntityGraphNode *m = *m_;
|
||||
entity_graph_node_set_add(&n->succ, m);
|
||||
entity_graph_node_set_add(&m->pred, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bill): This could be multithreaded to improve performance
|
||||
// This means that the entity graph node set will have to be thread safe
|
||||
|
||||
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
|
||||
auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count);
|
||||
|
||||
for_array(i, M.entries) {
|
||||
@@ -1737,14 +1820,18 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
||||
}
|
||||
}
|
||||
|
||||
TIME_SECTION("generate_entity_dependency_graph: Dependency Count Checker");
|
||||
for_array(i, G) {
|
||||
EntityGraphNode *n = G[i];
|
||||
n->index = i;
|
||||
n->dep_count = n->succ.entries.count;
|
||||
|
||||
GB_ASSERT(n->dep_count >= 0);
|
||||
}
|
||||
|
||||
return G;
|
||||
|
||||
#undef TIME_SECTION
|
||||
}
|
||||
|
||||
|
||||
@@ -1863,6 +1950,7 @@ void init_core_type_info(Checker *c) {
|
||||
t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer"));
|
||||
t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune"));
|
||||
t_type_info_float = find_core_type(c, str_lit("Type_Info_Float"));
|
||||
t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion"));
|
||||
t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex"));
|
||||
t_type_info_string = find_core_type(c, str_lit("Type_Info_String"));
|
||||
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
|
||||
@@ -1887,6 +1975,7 @@ void init_core_type_info(Checker *c) {
|
||||
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
|
||||
t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune);
|
||||
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
|
||||
t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion);
|
||||
t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex);
|
||||
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
|
||||
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
|
||||
@@ -2138,6 +2227,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "require_results") {
|
||||
if (value != nullptr) {
|
||||
error(elem, "Expected no value for '%.*s'", LIT(name));
|
||||
}
|
||||
ac->require_results = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2151,6 +2246,33 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
|
||||
}
|
||||
ac->is_static = true;
|
||||
return true;
|
||||
} else if (name == "thread_local") {
|
||||
if (ac->init_expr_list_count > 0) {
|
||||
error(elem, "A thread local variable declaration cannot have initialization values");
|
||||
} else if (c->foreign_context.curr_library) {
|
||||
error(elem, "A foreign block variable cannot be thread local");
|
||||
} else if (ac->is_export) {
|
||||
error(elem, "An exported variable cannot be thread local");
|
||||
} else if (ev.kind == ExactValue_Invalid) {
|
||||
ac->thread_local_model = str_lit("default");
|
||||
} else if (ev.kind == ExactValue_String) {
|
||||
String model = ev.value_string;
|
||||
if (model == "default" ||
|
||||
model == "localdynamic" ||
|
||||
model == "initialexec" ||
|
||||
model == "localexec") {
|
||||
ac->thread_local_model = model;
|
||||
} else {
|
||||
error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
|
||||
error_line("\tdefault\n");
|
||||
error_line("\tlocaldynamic\n");
|
||||
error_line("\tinitialexec\n");
|
||||
error_line("\tlocalexec\n");
|
||||
}
|
||||
} else {
|
||||
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c->curr_proc_decl != nullptr) {
|
||||
@@ -2191,33 +2313,6 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
|
||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "thread_local") {
|
||||
if (ac->init_expr_list_count > 0) {
|
||||
error(elem, "A thread local variable declaration cannot have initialization values");
|
||||
} else if (c->foreign_context.curr_library) {
|
||||
error(elem, "A foreign block variable cannot be thread local");
|
||||
} else if (ac->is_export) {
|
||||
error(elem, "An exported variable cannot be thread local");
|
||||
} else if (ev.kind == ExactValue_Invalid) {
|
||||
ac->thread_local_model = str_lit("default");
|
||||
} else if (ev.kind == ExactValue_String) {
|
||||
String model = ev.value_string;
|
||||
if (model == "default" ||
|
||||
model == "localdynamic" ||
|
||||
model == "initialexec" ||
|
||||
model == "localexec") {
|
||||
ac->thread_local_model = model;
|
||||
} else {
|
||||
error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model));
|
||||
error_line("\tdefault\n");
|
||||
error_line("\tlocaldynamic\n");
|
||||
error_line("\tinitialexec\n");
|
||||
error_line("\tlocalexec\n");
|
||||
}
|
||||
} else {
|
||||
error(elem, "Expected either no value or a string for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2528,6 +2623,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
|
||||
Ast *init_expr = value;
|
||||
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
|
||||
d->entity = e;
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init_expr;
|
||||
d->attributes = vd->attributes;
|
||||
@@ -2557,14 +2653,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
Entity *e = nullptr;
|
||||
|
||||
d->attributes = vd->attributes;
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
|
||||
if (is_ast_type(init)) {
|
||||
e = alloc_entity_type_name(d->scope, token, nullptr);
|
||||
if (vd->type != nullptr) {
|
||||
error(name, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = init;
|
||||
d->init_expr = init;
|
||||
// if (vd->type != nullptr) {
|
||||
// error(name, "A type declaration cannot have an type parameter");
|
||||
// }
|
||||
} else if (init->kind == Ast_ProcLit) {
|
||||
if (c->scope->flags&ScopeFlag_Type) {
|
||||
error(name, "Procedure declarations are not allowed within a struct");
|
||||
@@ -2591,18 +2687,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
pl->type->ProcType.calling_convention = cc;
|
||||
}
|
||||
d->proc_lit = init;
|
||||
d->type_expr = pl->type;
|
||||
d->init_expr = init;
|
||||
} else if (init->kind == Ast_ProcGroup) {
|
||||
ast_node(pg, ProcGroup, init);
|
||||
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
||||
if (fl != nullptr) {
|
||||
error(name, "Procedure groups are not allowed within a foreign block");
|
||||
}
|
||||
d->init_expr = init;
|
||||
} else {
|
||||
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
}
|
||||
e->identifier = name;
|
||||
|
||||
@@ -3100,7 +3193,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
Entity *e = scope->elements.entries[elem_index].value;
|
||||
if (e->scope == parent_scope) continue;
|
||||
|
||||
if (is_entity_exported(e)) {
|
||||
if (is_entity_exported(e, true)) {
|
||||
Entity *found = scope_lookup_current(parent_scope, name);
|
||||
if (found != nullptr) {
|
||||
// NOTE(bill):
|
||||
@@ -3118,6 +3211,16 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
scope->flags |= ScopeFlag_HasBeenImported;
|
||||
}
|
||||
|
||||
DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
|
||||
if (name == "force") {
|
||||
if (value != nullptr) {
|
||||
error(elem, "Expected no parameter for '%.*s'", LIT(name));
|
||||
}
|
||||
ac->force_foreign_import = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
if (decl->been_handled) return;
|
||||
@@ -3162,6 +3265,14 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
|
||||
fl->fullpaths, library_name);
|
||||
add_entity(ctx->checker, parent_scope, nullptr, e);
|
||||
|
||||
|
||||
AttributeContext ac = {};
|
||||
check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
|
||||
if (ac.force_foreign_import) {
|
||||
array_add(&ctx->info->required_foreign_imports_through_force, e);
|
||||
add_entity_use(ctx, nullptr, e);
|
||||
}
|
||||
}
|
||||
|
||||
bool collect_checked_packages_from_decl_list(Checker *c, Array<Ast *> const &decls) {
|
||||
@@ -3314,8 +3425,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
|
||||
if (es->expr->kind == Ast_CallExpr) {
|
||||
ast_node(ce, CallExpr, es->expr);
|
||||
if (ce->proc->kind == Ast_BasicDirective) {
|
||||
Operand o = {};
|
||||
check_expr(ctx, &o, es->expr);
|
||||
if (ctx->collect_delayed_decls) {
|
||||
array_add(&ctx->scope->delayed_directives, es->expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
@@ -3472,12 +3584,18 @@ void check_import_entities(Checker *c) {
|
||||
for_array(i, pkg->files) {
|
||||
AstFile *f = pkg->files[i];
|
||||
CheckerContext ctx = c->init_ctx;
|
||||
|
||||
add_curr_ast_file(&ctx, f);
|
||||
|
||||
for_array(j, f->scope->delayed_imports) {
|
||||
Ast *decl = f->scope->delayed_imports[j];
|
||||
check_add_import_decl(&ctx, decl);
|
||||
}
|
||||
}
|
||||
for_array(i, pkg->files) {
|
||||
AstFile *f = pkg->files[i];
|
||||
CheckerContext ctx = c->init_ctx;
|
||||
add_curr_ast_file(&ctx, f);
|
||||
|
||||
for_array(j, f->scope->delayed_directives) {
|
||||
Ast *expr = f->scope->delayed_directives[j];
|
||||
Operand o = {};
|
||||
@@ -3529,22 +3647,11 @@ Array<Entity *> find_entity_path(Entity *start, Entity *end, Map<Entity *> *visi
|
||||
|
||||
|
||||
void calculate_global_init_order(Checker *c) {
|
||||
#if 0
|
||||
Timings timings = {};
|
||||
timings_init(&timings, str_lit("calculate_global_init_order"), 16);
|
||||
defer ({
|
||||
timings_print_all(&timings);
|
||||
timings_destroy(&timings);
|
||||
});
|
||||
#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str))
|
||||
#else
|
||||
#define TIME_SECTION(str)
|
||||
#endif
|
||||
|
||||
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
|
||||
|
||||
CheckerInfo *info = &c->info;
|
||||
|
||||
TIME_SECTION("generate entity dependency graph");
|
||||
TIME_SECTION("calculate_global_init_order: generate entity dependency graph");
|
||||
Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info);
|
||||
defer ({
|
||||
for_array(i, dep_graph) {
|
||||
@@ -3553,7 +3660,7 @@ void calculate_global_init_order(Checker *c) {
|
||||
array_free(&dep_graph);
|
||||
});
|
||||
|
||||
TIME_SECTION("priority queue create");
|
||||
TIME_SECTION("calculate_global_init_order: priority queue create");
|
||||
// NOTE(bill): Priority queue
|
||||
auto pq = priority_queue_create(dep_graph, entity_graph_node_cmp, entity_graph_node_swap);
|
||||
|
||||
@@ -3561,7 +3668,7 @@ void calculate_global_init_order(Checker *c) {
|
||||
ptr_set_init(&emitted, heap_allocator());
|
||||
defer (ptr_set_destroy(&emitted));
|
||||
|
||||
TIME_SECTION("queue sort");
|
||||
TIME_SECTION("calculate_global_init_order: queue sort");
|
||||
while (pq.queue.count > 0) {
|
||||
EntityGraphNode *n = priority_queue_pop(&pq);
|
||||
Entity *e = n->entity;
|
||||
@@ -3583,21 +3690,26 @@ void calculate_global_init_order(Checker *c) {
|
||||
|
||||
for_array(i, n->pred.entries) {
|
||||
EntityGraphNode *p = n->pred.entries[i].ptr;
|
||||
p->dep_count -= gb_max(p->dep_count-1, 0);
|
||||
p->dep_count -= 1;
|
||||
p->dep_count = gb_max(p->dep_count, 0);
|
||||
priority_queue_fix(&pq, p->index);
|
||||
}
|
||||
|
||||
if (e == nullptr || e->kind != Entity_Variable) {
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
if (e->kind != Entity_Variable) {
|
||||
continue;
|
||||
}
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
|
||||
// IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering
|
||||
// because it does not need any initialization other than zero
|
||||
// if (!decl_info_has_init(d)) {
|
||||
// continue;
|
||||
// }
|
||||
if (ptr_set_exists(&emitted, d)) {
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&emitted, d);
|
||||
|
||||
d->entity = e;
|
||||
|
||||
array_add(&info->variable_init_order, d);
|
||||
}
|
||||
|
||||
@@ -3636,6 +3748,14 @@ void check_proc_info(Checker *c, ProcInfo pi) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pt->is_polymorphic && pt->is_poly_specialized) {
|
||||
Entity *e = pi.decl->entity;
|
||||
if ((e->flags & EntityFlag_Used) == 0) {
|
||||
// NOTE(bill, 2019-08-31): It was never used, don't check
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool bounds_check = (pi.tags & ProcTag_bounds_check) != 0;
|
||||
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
|
||||
|
||||
@@ -3660,17 +3780,7 @@ GB_THREAD_PROC(check_proc_info_worker_proc) {
|
||||
|
||||
|
||||
void check_parsed_files(Checker *c) {
|
||||
#if 0
|
||||
Timings timings = {};
|
||||
timings_init(&timings, str_lit("check_parsed_files"), 16);
|
||||
defer ({
|
||||
timings_print_all(&timings);
|
||||
timings_destroy(&timings);
|
||||
});
|
||||
#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str))
|
||||
#else
|
||||
#define TIME_SECTION(str)
|
||||
#endif
|
||||
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
|
||||
|
||||
TIME_SECTION("map full filepaths to scope");
|
||||
add_type_info_type(&c->init_ctx, t_invalid);
|
||||
@@ -3732,6 +3842,7 @@ void check_parsed_files(Checker *c) {
|
||||
check_proc_info(c, pi);
|
||||
}
|
||||
|
||||
TIME_SECTION("check scope usage");
|
||||
for_array(i, c->info.files.entries) {
|
||||
AstFile *f = c->info.files.entries[i].value;
|
||||
check_scope_usage(c, f->scope);
|
||||
|
||||
+10
-211
@@ -59,218 +59,8 @@ struct BuiltinProc {
|
||||
BuiltinProcPkg pkg;
|
||||
};
|
||||
|
||||
enum BuiltinProcId {
|
||||
BuiltinProc_Invalid,
|
||||
|
||||
BuiltinProc_len,
|
||||
BuiltinProc_cap,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_align_of,
|
||||
BuiltinProc_offset_of,
|
||||
BuiltinProc_type_of,
|
||||
BuiltinProc_type_info_of,
|
||||
BuiltinProc_typeid_of,
|
||||
|
||||
BuiltinProc_swizzle,
|
||||
|
||||
BuiltinProc_complex,
|
||||
BuiltinProc_real,
|
||||
BuiltinProc_imag,
|
||||
BuiltinProc_conj,
|
||||
|
||||
BuiltinProc_expand_to_tuple,
|
||||
|
||||
BuiltinProc_min,
|
||||
BuiltinProc_max,
|
||||
BuiltinProc_abs,
|
||||
BuiltinProc_clamp,
|
||||
|
||||
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
||||
|
||||
// "Intrinsics"
|
||||
BuiltinProc_vector,
|
||||
|
||||
BuiltinProc_atomic_fence,
|
||||
BuiltinProc_atomic_fence_acq,
|
||||
BuiltinProc_atomic_fence_rel,
|
||||
BuiltinProc_atomic_fence_acqrel,
|
||||
|
||||
BuiltinProc_atomic_store,
|
||||
BuiltinProc_atomic_store_rel,
|
||||
BuiltinProc_atomic_store_relaxed,
|
||||
BuiltinProc_atomic_store_unordered,
|
||||
|
||||
BuiltinProc_atomic_load,
|
||||
BuiltinProc_atomic_load_acq,
|
||||
BuiltinProc_atomic_load_relaxed,
|
||||
BuiltinProc_atomic_load_unordered,
|
||||
|
||||
BuiltinProc_atomic_add,
|
||||
BuiltinProc_atomic_add_acq,
|
||||
BuiltinProc_atomic_add_rel,
|
||||
BuiltinProc_atomic_add_acqrel,
|
||||
BuiltinProc_atomic_add_relaxed,
|
||||
BuiltinProc_atomic_sub,
|
||||
BuiltinProc_atomic_sub_acq,
|
||||
BuiltinProc_atomic_sub_rel,
|
||||
BuiltinProc_atomic_sub_acqrel,
|
||||
BuiltinProc_atomic_sub_relaxed,
|
||||
BuiltinProc_atomic_and,
|
||||
BuiltinProc_atomic_and_acq,
|
||||
BuiltinProc_atomic_and_rel,
|
||||
BuiltinProc_atomic_and_acqrel,
|
||||
BuiltinProc_atomic_and_relaxed,
|
||||
BuiltinProc_atomic_nand,
|
||||
BuiltinProc_atomic_nand_acq,
|
||||
BuiltinProc_atomic_nand_rel,
|
||||
BuiltinProc_atomic_nand_acqrel,
|
||||
BuiltinProc_atomic_nand_relaxed,
|
||||
BuiltinProc_atomic_or,
|
||||
BuiltinProc_atomic_or_acq,
|
||||
BuiltinProc_atomic_or_rel,
|
||||
BuiltinProc_atomic_or_acqrel,
|
||||
BuiltinProc_atomic_or_relaxed,
|
||||
BuiltinProc_atomic_xor,
|
||||
BuiltinProc_atomic_xor_acq,
|
||||
BuiltinProc_atomic_xor_rel,
|
||||
BuiltinProc_atomic_xor_acqrel,
|
||||
BuiltinProc_atomic_xor_relaxed,
|
||||
|
||||
BuiltinProc_atomic_xchg,
|
||||
BuiltinProc_atomic_xchg_acq,
|
||||
BuiltinProc_atomic_xchg_rel,
|
||||
BuiltinProc_atomic_xchg_acqrel,
|
||||
BuiltinProc_atomic_xchg_relaxed,
|
||||
|
||||
BuiltinProc_atomic_cxchg,
|
||||
BuiltinProc_atomic_cxchg_acq,
|
||||
BuiltinProc_atomic_cxchg_rel,
|
||||
BuiltinProc_atomic_cxchg_acqrel,
|
||||
BuiltinProc_atomic_cxchg_relaxed,
|
||||
BuiltinProc_atomic_cxchg_failrelaxed,
|
||||
BuiltinProc_atomic_cxchg_failacq,
|
||||
BuiltinProc_atomic_cxchg_acq_failrelaxed,
|
||||
BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
|
||||
|
||||
BuiltinProc_atomic_cxchgweak,
|
||||
BuiltinProc_atomic_cxchgweak_acq,
|
||||
BuiltinProc_atomic_cxchgweak_rel,
|
||||
BuiltinProc_atomic_cxchgweak_acqrel,
|
||||
BuiltinProc_atomic_cxchgweak_relaxed,
|
||||
BuiltinProc_atomic_cxchgweak_failrelaxed,
|
||||
BuiltinProc_atomic_cxchgweak_failacq,
|
||||
BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
|
||||
BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
|
||||
|
||||
BuiltinProc_COUNT,
|
||||
};
|
||||
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
|
||||
|
||||
|
||||
// "Intrinsics"
|
||||
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||
|
||||
|
||||
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
};
|
||||
#include "checker_builtin_procs.hpp"
|
||||
|
||||
|
||||
// Operand is used as an intermediate value whilst checking
|
||||
@@ -307,6 +97,8 @@ struct DeferredProcedure {
|
||||
struct AttributeContext {
|
||||
bool is_export;
|
||||
bool is_static;
|
||||
bool require_results;
|
||||
bool force_foreign_import;
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
isize init_expr_list_count;
|
||||
@@ -431,6 +223,7 @@ struct ForeignContext {
|
||||
typedef Array<Entity *> CheckerTypePath;
|
||||
typedef Array<Type *> CheckerPolyPath;
|
||||
|
||||
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
struct CheckerInfo {
|
||||
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
|
||||
@@ -457,6 +250,8 @@ struct CheckerInfo {
|
||||
PtrSet<Entity *> minimum_dependency_set;
|
||||
PtrSet<isize> minimum_dependency_type_info_set;
|
||||
|
||||
Array<Entity *> required_foreign_imports_through_force;
|
||||
|
||||
|
||||
bool allow_identifier_uses;
|
||||
Array<Ast *> identifier_uses; // only used by 'odin query'
|
||||
@@ -486,10 +281,14 @@ struct CheckerContext {
|
||||
CheckerPolyPath *poly_path;
|
||||
isize poly_level; // TODO(bill): Actually handle correctly
|
||||
|
||||
#define MAX_INLINE_FOR_DEPTH 1024ll
|
||||
i64 inline_for_depth;
|
||||
|
||||
bool in_enum_type;
|
||||
bool collect_delayed_decls;
|
||||
bool allow_polymorphic_types;
|
||||
bool no_polymorphic_errors;
|
||||
bool hide_polymorphic_errors;
|
||||
bool in_polymorphic_specialization;
|
||||
Scope * polymorphic_scope;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
// checker_builtin_procs.hpp
|
||||
|
||||
enum BuiltinProcId {
|
||||
BuiltinProc_Invalid,
|
||||
|
||||
BuiltinProc_len,
|
||||
BuiltinProc_cap,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_align_of,
|
||||
BuiltinProc_offset_of,
|
||||
BuiltinProc_type_of,
|
||||
BuiltinProc_type_info_of,
|
||||
BuiltinProc_typeid_of,
|
||||
|
||||
BuiltinProc_swizzle,
|
||||
|
||||
BuiltinProc_complex,
|
||||
BuiltinProc_quaternion,
|
||||
BuiltinProc_real,
|
||||
BuiltinProc_imag,
|
||||
BuiltinProc_jmag,
|
||||
BuiltinProc_kmag,
|
||||
BuiltinProc_conj,
|
||||
|
||||
BuiltinProc_expand_to_tuple,
|
||||
|
||||
BuiltinProc_min,
|
||||
BuiltinProc_max,
|
||||
BuiltinProc_abs,
|
||||
BuiltinProc_clamp,
|
||||
|
||||
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
||||
|
||||
// "Intrinsics"
|
||||
BuiltinProc_vector,
|
||||
BuiltinProc_soa_struct,
|
||||
|
||||
BuiltinProc_atomic_fence,
|
||||
BuiltinProc_atomic_fence_acq,
|
||||
BuiltinProc_atomic_fence_rel,
|
||||
BuiltinProc_atomic_fence_acqrel,
|
||||
|
||||
BuiltinProc_atomic_store,
|
||||
BuiltinProc_atomic_store_rel,
|
||||
BuiltinProc_atomic_store_relaxed,
|
||||
BuiltinProc_atomic_store_unordered,
|
||||
|
||||
BuiltinProc_atomic_load,
|
||||
BuiltinProc_atomic_load_acq,
|
||||
BuiltinProc_atomic_load_relaxed,
|
||||
BuiltinProc_atomic_load_unordered,
|
||||
|
||||
BuiltinProc_atomic_add,
|
||||
BuiltinProc_atomic_add_acq,
|
||||
BuiltinProc_atomic_add_rel,
|
||||
BuiltinProc_atomic_add_acqrel,
|
||||
BuiltinProc_atomic_add_relaxed,
|
||||
BuiltinProc_atomic_sub,
|
||||
BuiltinProc_atomic_sub_acq,
|
||||
BuiltinProc_atomic_sub_rel,
|
||||
BuiltinProc_atomic_sub_acqrel,
|
||||
BuiltinProc_atomic_sub_relaxed,
|
||||
BuiltinProc_atomic_and,
|
||||
BuiltinProc_atomic_and_acq,
|
||||
BuiltinProc_atomic_and_rel,
|
||||
BuiltinProc_atomic_and_acqrel,
|
||||
BuiltinProc_atomic_and_relaxed,
|
||||
BuiltinProc_atomic_nand,
|
||||
BuiltinProc_atomic_nand_acq,
|
||||
BuiltinProc_atomic_nand_rel,
|
||||
BuiltinProc_atomic_nand_acqrel,
|
||||
BuiltinProc_atomic_nand_relaxed,
|
||||
BuiltinProc_atomic_or,
|
||||
BuiltinProc_atomic_or_acq,
|
||||
BuiltinProc_atomic_or_rel,
|
||||
BuiltinProc_atomic_or_acqrel,
|
||||
BuiltinProc_atomic_or_relaxed,
|
||||
BuiltinProc_atomic_xor,
|
||||
BuiltinProc_atomic_xor_acq,
|
||||
BuiltinProc_atomic_xor_rel,
|
||||
BuiltinProc_atomic_xor_acqrel,
|
||||
BuiltinProc_atomic_xor_relaxed,
|
||||
|
||||
BuiltinProc_atomic_xchg,
|
||||
BuiltinProc_atomic_xchg_acq,
|
||||
BuiltinProc_atomic_xchg_rel,
|
||||
BuiltinProc_atomic_xchg_acqrel,
|
||||
BuiltinProc_atomic_xchg_relaxed,
|
||||
|
||||
BuiltinProc_atomic_cxchg,
|
||||
BuiltinProc_atomic_cxchg_acq,
|
||||
BuiltinProc_atomic_cxchg_rel,
|
||||
BuiltinProc_atomic_cxchg_acqrel,
|
||||
BuiltinProc_atomic_cxchg_relaxed,
|
||||
BuiltinProc_atomic_cxchg_failrelaxed,
|
||||
BuiltinProc_atomic_cxchg_failacq,
|
||||
BuiltinProc_atomic_cxchg_acq_failrelaxed,
|
||||
BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
|
||||
|
||||
BuiltinProc_atomic_cxchgweak,
|
||||
BuiltinProc_atomic_cxchgweak_acq,
|
||||
BuiltinProc_atomic_cxchgweak_rel,
|
||||
BuiltinProc_atomic_cxchgweak_acqrel,
|
||||
BuiltinProc_atomic_cxchgweak_relaxed,
|
||||
BuiltinProc_atomic_cxchgweak_failrelaxed,
|
||||
BuiltinProc_atomic_cxchgweak_failacq,
|
||||
BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
|
||||
BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
|
||||
|
||||
|
||||
// Constant type tests
|
||||
BuiltinProc__type_begin,
|
||||
|
||||
BuiltinProc_type_base_type,
|
||||
BuiltinProc_type_core_type,
|
||||
BuiltinProc_type_elem_type,
|
||||
|
||||
BuiltinProc_type_is_boolean,
|
||||
BuiltinProc_type_is_integer,
|
||||
BuiltinProc_type_is_rune,
|
||||
BuiltinProc_type_is_float,
|
||||
BuiltinProc_type_is_complex,
|
||||
BuiltinProc_type_is_quaternion,
|
||||
BuiltinProc_type_is_string,
|
||||
BuiltinProc_type_is_typeid,
|
||||
BuiltinProc_type_is_any,
|
||||
|
||||
BuiltinProc_type_is_endian_little,
|
||||
BuiltinProc_type_is_endian_big,
|
||||
BuiltinProc_type_is_unsigned,
|
||||
BuiltinProc_type_is_numeric,
|
||||
BuiltinProc_type_is_ordered,
|
||||
BuiltinProc_type_is_ordered_numeric,
|
||||
BuiltinProc_type_is_indexable,
|
||||
BuiltinProc_type_is_sliceable,
|
||||
BuiltinProc_type_is_simple_compare, // easily compared using memcmp
|
||||
BuiltinProc_type_is_dereferenceable,
|
||||
BuiltinProc_type_is_valid_map_key,
|
||||
|
||||
BuiltinProc_type_is_named,
|
||||
BuiltinProc_type_is_pointer,
|
||||
BuiltinProc_type_is_opaque,
|
||||
BuiltinProc_type_is_array,
|
||||
BuiltinProc_type_is_slice,
|
||||
BuiltinProc_type_is_dynamic_array,
|
||||
BuiltinProc_type_is_map,
|
||||
BuiltinProc_type_is_struct,
|
||||
BuiltinProc_type_is_union,
|
||||
BuiltinProc_type_is_enum,
|
||||
BuiltinProc_type_is_proc,
|
||||
BuiltinProc_type_is_bit_field,
|
||||
BuiltinProc_type_is_bit_field_value,
|
||||
BuiltinProc_type_is_bit_set,
|
||||
BuiltinProc_type_is_simd_vector,
|
||||
|
||||
BuiltinProc_type_has_nil,
|
||||
|
||||
BuiltinProc_type_proc_parameter_count,
|
||||
BuiltinProc_type_proc_return_count,
|
||||
|
||||
BuiltinProc__type_end,
|
||||
|
||||
|
||||
BuiltinProc_COUNT,
|
||||
};
|
||||
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("quaternion"), 4, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("jmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("kmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
|
||||
|
||||
|
||||
// "Intrinsics"
|
||||
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||
{STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||
|
||||
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_rune"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_float"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_quaternion"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_is_endian_little"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_endian_big"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_unsigned"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_ordered_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_indexable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_sliceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_dereferenceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_valid_map_key"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_is_named"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_opaque"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_slice"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_map"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_struct"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_field_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
};
|
||||
+4
-4
@@ -10,13 +10,11 @@
|
||||
#define GB_IMPLEMENTATION
|
||||
#include "gb/gb.h"
|
||||
|
||||
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
template <typename U, typename V>
|
||||
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
|
||||
|
||||
@@ -145,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
|
||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||
|
||||
#include "range_cache.cpp"
|
||||
|
||||
|
||||
|
||||
u64 fnv64a(void const *data, isize len) {
|
||||
u8 const *bytes = cast(u8 const *)data;
|
||||
@@ -331,7 +332,7 @@ void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
|
||||
#include "ptr_set.cpp"
|
||||
#include "string_set.cpp"
|
||||
#include "priority_queue.cpp"
|
||||
|
||||
#include "thread_pool.cpp"
|
||||
|
||||
|
||||
gb_global String global_module_path = {0};
|
||||
@@ -873,7 +874,6 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
info.size = size;
|
||||
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
array_add(fi, info);
|
||||
|
||||
} while (FindNextFileW(find_file, &file_data));
|
||||
|
||||
if (fi->count == 0) {
|
||||
|
||||
+8
-5
@@ -48,7 +48,8 @@ enum EntityFlag {
|
||||
EntityFlag_NotExported = 1<<14,
|
||||
|
||||
EntityFlag_Static = 1<<16,
|
||||
// EntityFlag_Reference = 1<<17,
|
||||
|
||||
EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++
|
||||
|
||||
EntityFlag_CVarArg = 1<<20,
|
||||
EntityFlag_AutoCast = 1<<21,
|
||||
@@ -183,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
|
||||
}
|
||||
|
||||
String name = e->token.string;
|
||||
if (name.len == 0) {
|
||||
return false;
|
||||
switch (name.len) {
|
||||
case 0: return false;
|
||||
case 1: return name[0] != '_';
|
||||
}
|
||||
return name[0] != '_';
|
||||
return true;
|
||||
}
|
||||
|
||||
bool entity_has_deferred_procedure(Entity *e) {
|
||||
@@ -219,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) {
|
||||
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
|
||||
GB_ASSERT(parent != nullptr);
|
||||
token.pos = parent->token.pos;
|
||||
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
|
||||
entity->using_parent = parent;
|
||||
entity->parent_proc_decl = parent->parent_proc_decl;
|
||||
entity->using_expr = using_expr;
|
||||
entity->flags |= EntityFlag_Using;
|
||||
entity->flags |= EntityFlag_Used;
|
||||
entity->state = EntityState_Resolved;
|
||||
|
||||
+249
-15
@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
|
||||
struct Complex128 {
|
||||
f64 real, imag;
|
||||
};
|
||||
struct Quaternion256 {
|
||||
f64 imag, jmag, kmag, real;
|
||||
};
|
||||
|
||||
Quaternion256 quaternion256_inverse(Quaternion256 x) {
|
||||
f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
|
||||
x.real = +x.real * invmag2;
|
||||
x.imag = -x.imag * invmag2;
|
||||
x.jmag = -x.jmag * invmag2;
|
||||
x.kmag = -x.kmag * invmag2;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
enum ExactValueKind {
|
||||
ExactValue_Invalid,
|
||||
@@ -21,9 +34,11 @@ enum ExactValueKind {
|
||||
ExactValue_Integer,
|
||||
ExactValue_Float,
|
||||
ExactValue_Complex,
|
||||
ExactValue_Quaternion,
|
||||
ExactValue_Pointer,
|
||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
||||
ExactValue_Typeid,
|
||||
|
||||
ExactValue_Count,
|
||||
};
|
||||
@@ -37,8 +52,10 @@ struct ExactValue {
|
||||
f64 value_float;
|
||||
i64 value_pointer;
|
||||
Complex128 value_complex;
|
||||
Quaternion256 value_quaternion;
|
||||
Ast * value_compound;
|
||||
Ast * value_procedure;
|
||||
Type * value_typeid;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -53,25 +70,22 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
return hash_integer(u64(v.value_bool));
|
||||
case ExactValue_String:
|
||||
return hash_string(v.value_string);
|
||||
case ExactValue_Integer: {
|
||||
u64 *d = big_int_ptr(&v.value_integer);
|
||||
u64 x = 0;
|
||||
for (i32 i = 0; i < v.value_integer.len; i++) {
|
||||
x |= d[i];
|
||||
}
|
||||
return hash_integer(x);
|
||||
}
|
||||
case ExactValue_Integer:
|
||||
return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
|
||||
case ExactValue_Float:
|
||||
return hash_f64(v.value_float);
|
||||
case ExactValue_Pointer:
|
||||
return hash_integer(v.value_pointer);
|
||||
case ExactValue_Complex:
|
||||
return hashing_proc(&v.value_complex, gb_size_of(Complex128));
|
||||
|
||||
case ExactValue_Quaternion:
|
||||
return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
|
||||
case ExactValue_Compound:
|
||||
return hash_pointer(v.value_compound);
|
||||
case ExactValue_Procedure:
|
||||
return hash_pointer(v.value_procedure);
|
||||
case ExactValue_Typeid:
|
||||
return hash_pointer(v.value_typeid);
|
||||
}
|
||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
||||
|
||||
@@ -122,6 +136,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
|
||||
ExactValue result = {ExactValue_Quaternion};
|
||||
result.value_quaternion.real = real;
|
||||
result.value_quaternion.imag = imag;
|
||||
result.value_quaternion.jmag = jmag;
|
||||
result.value_quaternion.kmag = kmag;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_pointer(i64 ptr) {
|
||||
ExactValue result = {ExactValue_Pointer};
|
||||
result.value_pointer = ptr;
|
||||
@@ -135,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) {
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_typeid(Type *type) {
|
||||
ExactValue result = {ExactValue_Typeid};
|
||||
result.value_typeid = type;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_integer_from_string(String const &string) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
big_int_from_string(&result.value_integer, string);
|
||||
@@ -259,14 +289,16 @@ ExactValue exact_value_from_basic_literal(Token token) {
|
||||
str.len--; // Ignore the 'i|j|k'
|
||||
f64 imag = float_from_string(str);
|
||||
|
||||
if (last_rune == 'i') {
|
||||
return exact_value_complex(0, imag);
|
||||
switch (last_rune) {
|
||||
case 'i': return exact_value_complex(0, imag);
|
||||
case 'j': return exact_value_quaternion(0, 0, imag, 0);
|
||||
case 'k': return exact_value_quaternion(0, 0, 0, imag);
|
||||
default: GB_PANIC("Invalid imaginary basic literal");
|
||||
}
|
||||
}
|
||||
case Token_Rune: {
|
||||
Rune r = GB_RUNE_INVALID;
|
||||
gb_utf8_decode(token.string.text, token.string.len, &r);
|
||||
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
|
||||
return exact_value_i64(r);
|
||||
}
|
||||
default:
|
||||
@@ -324,11 +356,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
|
||||
return exact_value_complex(v.value_float, 0);
|
||||
case ExactValue_Complex:
|
||||
return v;
|
||||
// case ExactValue_Quaternion:
|
||||
// return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
|
||||
case ExactValue_Float:
|
||||
return exact_value_quaternion(v.value_float, 0, 0, 0);
|
||||
case ExactValue_Complex:
|
||||
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
|
||||
case ExactValue_Quaternion:
|
||||
return v;
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_real(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
@@ -337,6 +384,8 @@ ExactValue exact_value_real(ExactValue v) {
|
||||
return v;
|
||||
case ExactValue_Complex:
|
||||
return exact_value_float(v.value_complex.real);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.real);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -349,6 +398,34 @@ ExactValue exact_value_imag(ExactValue v) {
|
||||
return exact_value_i64(0);
|
||||
case ExactValue_Complex:
|
||||
return exact_value_float(v.value_complex.imag);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.imag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_jmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
case ExactValue_Complex:
|
||||
return exact_value_i64(0);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.jmag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_kmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
case ExactValue_Complex:
|
||||
return exact_value_i64(0);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.kmag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -367,6 +444,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_make_jmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
|
||||
case ExactValue_Float:
|
||||
return exact_value_quaternion(0, 0, v.value_float, 0);
|
||||
default:
|
||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_make_kmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
|
||||
case ExactValue_Float:
|
||||
return exact_value_quaternion(0, 0, 0, v.value_float);
|
||||
default:
|
||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
|
||||
i64 exact_value_to_i64(ExactValue v) {
|
||||
v = exact_value_to_integer(v);
|
||||
if (v.kind == ExactValue_Integer) {
|
||||
@@ -395,6 +498,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
case ExactValue_Complex:
|
||||
case ExactValue_Quaternion:
|
||||
return v;
|
||||
}
|
||||
break;
|
||||
@@ -419,6 +523,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
||||
f64 imag = v.value_complex.imag;
|
||||
return exact_value_complex(-real, -imag);
|
||||
}
|
||||
case ExactValue_Quaternion: {
|
||||
f64 real = v.value_quaternion.real;
|
||||
f64 imag = v.value_quaternion.imag;
|
||||
f64 jmag = v.value_quaternion.jmag;
|
||||
f64 kmag = v.value_quaternion.kmag;
|
||||
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -469,8 +580,10 @@ i32 exact_value_order(ExactValue const &v) {
|
||||
return 3;
|
||||
case ExactValue_Complex:
|
||||
return 4;
|
||||
case ExactValue_Pointer:
|
||||
case ExactValue_Quaternion:
|
||||
return 5;
|
||||
case ExactValue_Pointer:
|
||||
return 6;
|
||||
|
||||
default:
|
||||
GB_PANIC("How'd you get here? Invalid Value.kind");
|
||||
@@ -491,7 +604,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
|
||||
case ExactValue_Bool:
|
||||
case ExactValue_String:
|
||||
case ExactValue_Complex:
|
||||
case ExactValue_Quaternion:
|
||||
return;
|
||||
|
||||
case ExactValue_Integer:
|
||||
@@ -505,6 +618,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
case ExactValue_Complex:
|
||||
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
|
||||
return;
|
||||
case ExactValue_Quaternion:
|
||||
*x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -515,6 +631,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
case ExactValue_Complex:
|
||||
*x = exact_value_to_complex(*x);
|
||||
return;
|
||||
case ExactValue_Quaternion:
|
||||
*x = exact_value_to_quaternion(*x);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case ExactValue_Complex:
|
||||
switch (y->kind) {
|
||||
case ExactValue_Quaternion:
|
||||
*x = exact_value_to_quaternion(*x);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -612,6 +739,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
break;
|
||||
}
|
||||
|
||||
case ExactValue_Quaternion: {
|
||||
y = exact_value_to_quaternion(y);
|
||||
f64 xr = x.value_quaternion.real;
|
||||
f64 xi = x.value_quaternion.imag;
|
||||
f64 xj = x.value_quaternion.jmag;
|
||||
f64 xk = x.value_quaternion.kmag;
|
||||
f64 yr = y.value_quaternion.real;
|
||||
f64 yi = y.value_quaternion.imag;
|
||||
f64 yj = y.value_quaternion.jmag;
|
||||
f64 yk = y.value_quaternion.kmag;
|
||||
|
||||
|
||||
f64 real = 0;
|
||||
f64 imag = 0;
|
||||
f64 jmag = 0;
|
||||
f64 kmag = 0;
|
||||
|
||||
switch (op) {
|
||||
case Token_Add:
|
||||
real = xr + yr;
|
||||
imag = xi + yi;
|
||||
jmag = xj + yj;
|
||||
kmag = xk + yk;
|
||||
break;
|
||||
case Token_Sub:
|
||||
real = xr - yr;
|
||||
imag = xi - yi;
|
||||
jmag = xj - yj;
|
||||
kmag = xk - yk;
|
||||
break;
|
||||
case Token_Mul:
|
||||
imag = xr * yi + xi * yr + xj * yk - xk * yj;
|
||||
jmag = xr * yj - xi * yk + xj * yr + xk * yi;
|
||||
kmag = xr * yk + xi * yj - xj * yi + xk * yr;
|
||||
real = xr * yr - xi * yi - xj * yj - xk * yk;
|
||||
break;
|
||||
case Token_Quo: {
|
||||
f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk);
|
||||
imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2;
|
||||
jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2;
|
||||
kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2;
|
||||
real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2;
|
||||
break;
|
||||
}
|
||||
default: goto error;
|
||||
}
|
||||
return exact_value_quaternion(real, imag, jmag, kmag);
|
||||
break;
|
||||
}
|
||||
|
||||
case ExactValue_String: {
|
||||
if (op != Token_Add) goto error;
|
||||
|
||||
@@ -647,6 +824,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV
|
||||
return exact_binary_operator_value(op, x, y);
|
||||
}
|
||||
|
||||
gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
|
||||
return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
|
||||
}
|
||||
|
||||
|
||||
i32 cmp_f64(f64 a, f64 b) {
|
||||
return (a > b) - (a < b);
|
||||
@@ -719,8 +900,61 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ExactValue_Typeid:
|
||||
switch (op) {
|
||||
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
|
||||
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GB_PANIC("Invalid comparison");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid:
|
||||
return str;
|
||||
case ExactValue_Bool:
|
||||
return gb_string_appendc(str, v.value_bool ? "true" : "false");
|
||||
case ExactValue_String: {
|
||||
String s = quote_to_ascii(heap_allocator(), v.value_string);
|
||||
string_limit = gb_max(string_limit, 36);
|
||||
if (s.len <= string_limit) {
|
||||
str = gb_string_append_length(str, s.text, s.len);
|
||||
} else {
|
||||
isize n = string_limit/5;
|
||||
str = gb_string_append_length(str, s.text, n);
|
||||
str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n));
|
||||
str = gb_string_append_length(str, s.text+s.len-n, n);
|
||||
}
|
||||
gb_free(heap_allocator(), s.text);
|
||||
return str;
|
||||
}
|
||||
case ExactValue_Integer: {
|
||||
String s = big_int_to_string(heap_allocator(), &v.value_integer);
|
||||
str = gb_string_append_length(str, s.text, s.len);
|
||||
gb_free(heap_allocator(), s.text);
|
||||
return str;
|
||||
}
|
||||
case ExactValue_Float:
|
||||
return gb_string_append_fmt(str, "%f", v.value_float);
|
||||
case ExactValue_Complex:
|
||||
return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag);
|
||||
|
||||
case ExactValue_Pointer:
|
||||
return str;
|
||||
case ExactValue_Compound:
|
||||
return str;
|
||||
case ExactValue_Procedure:
|
||||
return str;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
|
||||
return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
|
||||
}
|
||||
|
||||
+19
-11
@@ -918,7 +918,7 @@ GB_DEF void gb_lfence (void);
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
typedef struct gbSemaphore { void *win32_handle; } gbSemaphore;
|
||||
typedef struct gbSemaphore { void *win32_handle;} gbSemaphore;
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore;
|
||||
#elif defined(GB_SYSTEM_UNIX)
|
||||
@@ -930,7 +930,7 @@ typedef struct gbSemaphore { sem_t unix_handle; } gbSemaphore;
|
||||
GB_DEF void gb_semaphore_init (gbSemaphore *s);
|
||||
GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
|
||||
GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count);
|
||||
GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1)
|
||||
GB_DEF void gb_semaphore_release(gbSemaphore *s);
|
||||
GB_DEF void gb_semaphore_wait (gbSemaphore *s);
|
||||
|
||||
|
||||
@@ -975,10 +975,10 @@ typedef struct gbThread {
|
||||
pthread_t posix_handle;
|
||||
#endif
|
||||
|
||||
gbThreadProc *proc;
|
||||
void * user_data;
|
||||
isize user_index;
|
||||
isize return_value;
|
||||
gbThreadProc * proc;
|
||||
void * user_data;
|
||||
isize user_index;
|
||||
isize volatile return_value;
|
||||
|
||||
gbSemaphore semaphore;
|
||||
isize stack_size;
|
||||
@@ -4588,10 +4588,18 @@ gb_inline void gb_lfence(void) {
|
||||
gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); }
|
||||
gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); }
|
||||
gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); }
|
||||
gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); }
|
||||
gb_inline void gb_semaphore_init(gbSemaphore *s) {
|
||||
s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
|
||||
}
|
||||
gb_inline void gb_semaphore_destroy(gbSemaphore *s) {
|
||||
CloseHandle(s->win32_handle);
|
||||
}
|
||||
gb_inline void gb_semaphore_post(gbSemaphore *s, i32 count) {
|
||||
ReleaseSemaphore(s->win32_handle, count, NULL);
|
||||
}
|
||||
gb_inline void gb_semaphore_wait(gbSemaphore *s) {
|
||||
WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
|
||||
}
|
||||
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
|
||||
@@ -8975,7 +8983,7 @@ gb_inline void gb_exit(u32 code) { exit(code); }
|
||||
|
||||
gb_inline void gb_yield(void) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
Sleep(0);
|
||||
YieldProcessor();
|
||||
#else
|
||||
sched_yield();
|
||||
#endif
|
||||
|
||||
+1020
-160
File diff suppressed because it is too large
Load Diff
+237
-61
@@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
||||
|
||||
|
||||
void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
|
||||
set_procedure_abi_types(heap_allocator(), t);
|
||||
|
||||
i64 word_bits = 8*build_context.word_size;
|
||||
t = base_type(t);
|
||||
GB_ASSERT(is_type_proc(t));
|
||||
|
||||
isize param_count = t->Proc.param_count;
|
||||
isize result_count = t->Proc.result_count;
|
||||
|
||||
ir_print_proc_results(f, m, t);
|
||||
ir_write_string(f, str_lit(" ("));
|
||||
if (t->Proc.return_by_pointer) {
|
||||
@@ -418,20 +421,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
||||
}
|
||||
return;
|
||||
|
||||
// case Basic_f16: ir_write_str_lit(f, "half"); return;
|
||||
case Basic_f32: ir_write_str_lit(f, "float"); return;
|
||||
case Basic_f64: ir_write_str_lit(f, "double"); return;
|
||||
// case Basic_f16: ir_write_str_lit(f, "half"); return;
|
||||
case Basic_f32: ir_write_str_lit(f, "float"); return;
|
||||
case Basic_f64: ir_write_str_lit(f, "double"); return;
|
||||
|
||||
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
|
||||
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
|
||||
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
|
||||
// case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
|
||||
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
|
||||
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
|
||||
|
||||
case Basic_any: ir_write_str_lit(f, "%..any"); return;
|
||||
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
|
||||
case Basic_string: ir_write_str_lit(f, "%..string"); return;
|
||||
case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
|
||||
case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return;
|
||||
case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return;
|
||||
|
||||
case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
|
||||
case Basic_any: ir_write_str_lit(f, "%..any"); return;
|
||||
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
|
||||
case Basic_string: ir_write_str_lit(f, "%..string"); return;
|
||||
case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
|
||||
|
||||
case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -767,15 +773,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
case ExactValue_Float: {
|
||||
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
|
||||
type = core_type(type);
|
||||
u64 u = bit_cast<u64>(value.value_float);
|
||||
u64 u_64 = bit_cast<u64>(value.value_float);
|
||||
u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
|
||||
#if 0
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_f32:
|
||||
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
|
||||
// a 64 bit number if bits_of(float type) <= 64.
|
||||
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
|
||||
// 64 bit mantissa: 52 bits
|
||||
// 32 bit mantissa: 23 bits
|
||||
// 16 bit mantissa: 10 bits
|
||||
// 64 bit mantissa: 52 bits ==> 52-52 == 0
|
||||
// 32 bit mantissa: 23 bits ==> 52-23 == 29
|
||||
// 16 bit mantissa: 10 bits ==> 52=10 == 42
|
||||
// 29 == 52-23
|
||||
u >>= 29;
|
||||
u <<= 29;
|
||||
@@ -792,9 +800,24 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_fprintf(f, "0x%016llx", u);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_f32: {
|
||||
ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
|
||||
break;
|
||||
}
|
||||
case Basic_f64:
|
||||
ir_fprintf(f, "0x%016llx", u_64);
|
||||
break;
|
||||
default:
|
||||
ir_fprintf(f, "0x%016llx", u_64);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case ExactValue_Complex: {
|
||||
// xy/ri format
|
||||
type = core_type(type);
|
||||
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
|
||||
Type *ft = base_complex_elem_type(type);
|
||||
@@ -807,6 +830,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_write_byte(f, '}');
|
||||
break;
|
||||
}
|
||||
|
||||
case ExactValue_Quaternion: {
|
||||
// xyzw/ijkr format
|
||||
type = core_type(type);
|
||||
GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
|
||||
Type *ft = base_complex_elem_type(type);
|
||||
ir_write_byte(f, ' ');
|
||||
ir_write_byte(f, '{');
|
||||
ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
|
||||
ir_write_byte(f, '}');
|
||||
break;
|
||||
}
|
||||
|
||||
case ExactValue_Pointer:
|
||||
if (value.value_pointer == 0) {
|
||||
if (is_type_typeid(type)) {
|
||||
@@ -836,22 +879,86 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_write_str_lit(f, "zeroinitializer");
|
||||
break;
|
||||
}
|
||||
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
|
||||
ir_write_byte(f, '[');
|
||||
for (i64 i = 0; i < type->Array.count; i++) {
|
||||
if (i > 0) ir_write_str_lit(f, ", ");
|
||||
|
||||
ir_write_byte(f, '[');
|
||||
bool found = false;
|
||||
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
if (i > 0) ir_write_str_lit(f, ", ");
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||
for (isize j = 0; j < elem_count; j++) {
|
||||
Ast *elem = cl->elems[j];
|
||||
ast_node(fv, FieldValue, elem);
|
||||
if (is_ast_range(fv->field)) {
|
||||
ast_node(ie, BinaryExpr, fv->field);
|
||||
TypeAndValue lo_tav = ie->left->tav;
|
||||
TypeAndValue hi_tav = ie->right->tav;
|
||||
GB_ASSERT(lo_tav.mode == Addressing_Constant);
|
||||
GB_ASSERT(hi_tav.mode == Addressing_Constant);
|
||||
|
||||
TokenKind op = ie->op.kind;
|
||||
i64 lo = exact_value_to_i64(lo_tav.value);
|
||||
i64 hi = exact_value_to_i64(hi_tav.value);
|
||||
if (op == Token_Ellipsis) {
|
||||
hi += 1;
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
if (tav.mode != Addressing_Constant) {
|
||||
break;
|
||||
}
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
if (k > lo) ir_write_str_lit(f, ", ");
|
||||
|
||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||
}
|
||||
|
||||
found = true;
|
||||
i += (hi-lo-1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
TypeAndValue index_tav = fv->field->tav;
|
||||
GB_ASSERT(index_tav.mode == Addressing_Constant);
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
if (tav.mode != Addressing_Constant) {
|
||||
break;
|
||||
}
|
||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ir_print_type(f, m, elem_type);
|
||||
ir_write_byte(f, ' ');
|
||||
ir_write_str_lit(f, "zeroinitializer");
|
||||
}
|
||||
}
|
||||
ir_write_byte(f, ']');
|
||||
} else {
|
||||
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
|
||||
|
||||
ir_write_byte(f, '[');
|
||||
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
if (i > 0) ir_write_str_lit(f, ", ");
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||
}
|
||||
for (isize i = elem_count; i < type->Array.count; i++) {
|
||||
if (i >= elem_count) ir_write_str_lit(f, ", ");
|
||||
ir_print_compound_element(f, m, empty_exact_value, elem_type);
|
||||
}
|
||||
|
||||
ir_write_byte(f, ']');
|
||||
}
|
||||
for (isize i = elem_count; i < type->Array.count; i++) {
|
||||
if (i >= elem_count) ir_write_str_lit(f, ", ");
|
||||
ir_print_compound_element(f, m, empty_exact_value, elem_type);
|
||||
}
|
||||
|
||||
ir_write_byte(f, ']');
|
||||
} else if (is_type_simd_vector(type)) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
|
||||
@@ -927,7 +1034,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
if (type->Struct.is_packed) ir_write_byte(f, '<');
|
||||
ir_write_byte(f, '{');
|
||||
if (type->Struct.custom_align > 0) {
|
||||
ir_fprintf(f, "[0 x <%lld x i8>] zeroinitializer", cast(i64)type->Struct.custom_align);
|
||||
ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align);
|
||||
ir_write_str_lit(f, " zeroinitializer");
|
||||
if (value_count > 0) {
|
||||
ir_write_string(f, str_lit(", "));
|
||||
}
|
||||
@@ -1089,7 +1197,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
||||
break;
|
||||
}
|
||||
case irValue_Param:
|
||||
ir_print_encoded_local(f, value->Param.entity->token.string);
|
||||
if (value->Param.index >= 0) {
|
||||
ir_fprintf(f, "%%_.%d", value->Param.index);
|
||||
} else {
|
||||
ir_print_encoded_local(f, value->Param.entity->token.string);
|
||||
}
|
||||
break;
|
||||
case irValue_SourceCodeLocation: {
|
||||
irValue *file = value->SourceCodeLocation.file;
|
||||
@@ -1124,7 +1236,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
|
||||
switch (cc) {
|
||||
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
|
||||
case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
|
||||
case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
|
||||
// case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
|
||||
case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
|
||||
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
|
||||
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
|
||||
case ProcCC_None: ir_write_str_lit(f, ""); break;
|
||||
@@ -1134,8 +1247,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
|
||||
|
||||
void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
|
||||
ir_print_type(f, m, t_context_ptr);
|
||||
ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
|
||||
// ir_write_str_lit(f, " noalias nonnull nocapture ");
|
||||
// ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
|
||||
ir_write_str_lit(f, " noalias nonnull nocapture ");
|
||||
}
|
||||
|
||||
void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
@@ -1186,6 +1299,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_write_str_lit(f, ", ");
|
||||
ir_print_type(f, m, type);
|
||||
ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
|
||||
// ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1888,11 +2002,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
}
|
||||
if (e->flags&EntityFlag_ImplicitReference) {
|
||||
ir_write_str_lit(f, " nonnull dereferenceable");
|
||||
}
|
||||
ir_write_byte(f, ' ');
|
||||
irValue *arg = call->args[i];
|
||||
if (is_type_boolean(t)) {
|
||||
|
||||
}
|
||||
ir_print_value(f, m, arg, t);
|
||||
param_index++;
|
||||
}
|
||||
@@ -1907,24 +2021,43 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
param_index++;
|
||||
}
|
||||
} else {
|
||||
GB_ASSERT(call->args.count == params->variables.count);
|
||||
// GB_ASSERT(call->args.count == params->variables.count);
|
||||
isize arg_index = 0;
|
||||
for_array(i, params->variables) {
|
||||
Entity *e = params->variables[i];
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->kind != Entity_Variable) continue;
|
||||
if (e->kind != Entity_Variable) {
|
||||
arg_index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (param_index > 0) ir_write_str_lit(f, ", ");
|
||||
|
||||
irValue *arg = call->args[i];
|
||||
Type *t = proc_type->Proc.abi_compat_params[i];
|
||||
if (is_type_tuple(t)) {
|
||||
for_array(j, t->Tuple.variables) {
|
||||
if (j > 0) ir_write_str_lit(f, ", ");
|
||||
|
||||
ir_print_type(f, m, t);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
irValue *arg = call->args[arg_index++];
|
||||
|
||||
ir_print_type(f, m, t->Tuple.variables[j]->type);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
}
|
||||
ir_write_byte(f, ' ');
|
||||
ir_print_value(f, m, arg, t);
|
||||
param_index++;
|
||||
}
|
||||
} else {
|
||||
irValue *arg = call->args[arg_index++];
|
||||
ir_print_type(f, m, t);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
}
|
||||
ir_write_byte(f, ' ');
|
||||
ir_print_value(f, m, arg, t);
|
||||
param_index++;
|
||||
}
|
||||
ir_write_byte(f, ' ');
|
||||
ir_print_value(f, m, arg, t);
|
||||
param_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1995,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
|
||||
|
||||
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
set_procedure_abi_types(heap_allocator(), proc->type);
|
||||
|
||||
if (proc->body == nullptr) {
|
||||
ir_write_str_lit(f, "declare ");
|
||||
// if (proc->tags & ProcTag_dll_import) {
|
||||
@@ -2043,7 +2178,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
|
||||
if (param_count > 0) {
|
||||
TypeTuple *params = &proc_type->params->Tuple;
|
||||
for (isize i = 0; i < param_count; i++) {
|
||||
isize parameter_index = 0;
|
||||
for (isize i = 0; i < param_count; i++, parameter_index++) {
|
||||
Entity *e = params->variables[i];
|
||||
Type *original_type = e->type;
|
||||
Type *abi_type = proc_type->abi_compat_params[i];
|
||||
@@ -2053,16 +2189,29 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
if (i+1 == params->variables.count && proc_type->c_vararg) {
|
||||
ir_write_str_lit(f, " ...");
|
||||
} else {
|
||||
ir_print_type(f, m, abi_type);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
}
|
||||
if (proc->body != nullptr) {
|
||||
if (e->token.string != "" && !is_blank_ident(e->token)) {
|
||||
ir_write_byte(f, ' ');
|
||||
ir_print_encoded_local(f, e->token.string);
|
||||
} else {
|
||||
ir_fprintf(f, " %%_.param_%td", i);
|
||||
if (is_type_tuple(abi_type)) {
|
||||
for_array(j, abi_type->Tuple.variables) {
|
||||
if (j > 0) ir_write_string(f, str_lit(", "));
|
||||
|
||||
Type *tft = abi_type->Tuple.variables[j]->type;
|
||||
ir_print_type(f, m, tft);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
}
|
||||
|
||||
if (proc->body != nullptr) {
|
||||
ir_fprintf(f, " %%_.%td", parameter_index+j);
|
||||
}
|
||||
}
|
||||
parameter_index += abi_type->Tuple.variables.count-1;
|
||||
param_index += abi_type->Tuple.variables.count-1;
|
||||
} else {
|
||||
ir_print_type(f, m, abi_type);
|
||||
if (e->flags&EntityFlag_NoAlias) {
|
||||
ir_write_str_lit(f, " noalias");
|
||||
}
|
||||
if (proc->body != nullptr) {
|
||||
ir_fprintf(f, " %%_.%td", parameter_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2176,6 +2325,22 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
||||
ir_write_byte(f, '\n');
|
||||
}
|
||||
|
||||
bool ir_print_global_type_allowed(Type *t) {
|
||||
if (t == nullptr) {
|
||||
return true;
|
||||
}
|
||||
t = core_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
case Type_Union:
|
||||
case Type_BitField:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_llvm_ir(irGen *ir) {
|
||||
irModule *m = &ir->module;
|
||||
|
||||
@@ -2184,9 +2349,11 @@ void print_llvm_ir(irGen *ir) {
|
||||
defer (ir_file_buffer_destroy(f));
|
||||
|
||||
i32 word_bits = cast(i32)(8*build_context.word_size);
|
||||
if (build_context.ODIN_OS == "osx" || build_context.ODIN_OS == "macos") {
|
||||
if (build_context.ODIN_OS == "darwin") {
|
||||
GB_ASSERT(word_bits == 64);
|
||||
ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n\n");
|
||||
ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n");
|
||||
ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n");
|
||||
ir_write_str_lit(f, "\n");
|
||||
} else if (build_context.ODIN_OS == "windows") {
|
||||
ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
|
||||
if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
|
||||
@@ -2210,6 +2377,13 @@ void print_llvm_ir(irGen *ir) {
|
||||
ir_print_encoded_local(f, str_lit("..complex128"));
|
||||
ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
|
||||
|
||||
ir_print_encoded_local(f, str_lit("..quaternion64"));
|
||||
ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
|
||||
ir_print_encoded_local(f, str_lit("..quaternion128"));
|
||||
ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
|
||||
ir_print_encoded_local(f, str_lit("..quaternion256"));
|
||||
ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
|
||||
|
||||
ir_print_encoded_local(f, str_lit("..typeid"));
|
||||
ir_write_str_lit(f, " = type ");
|
||||
ir_print_type(f, m, t_uintptr);
|
||||
@@ -2339,7 +2513,7 @@ void print_llvm_ir(irGen *ir) {
|
||||
ir_print_type(f, m, g->entity->type);
|
||||
ir_write_byte(f, ' ');
|
||||
if (!g->is_foreign) {
|
||||
if (g->value != nullptr) {
|
||||
if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) {
|
||||
ir_print_value(f, m, g->value, g->entity->type);
|
||||
} else {
|
||||
ir_write_string(f, str_lit("zeroinitializer"));
|
||||
@@ -2383,11 +2557,13 @@ void print_llvm_ir(irGen *ir) {
|
||||
|
||||
for_array(di_index, m->debug_info.entries) {
|
||||
irDebugInfo *di = m->debug_info.entries[di_index].value;
|
||||
GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
|
||||
ir_fprintf(f, "!%d = ", di->id);
|
||||
|
||||
switch (di->kind) {
|
||||
case irDebugInfo_CompileUnit: {
|
||||
irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||
irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
|
||||
GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath));
|
||||
irDebugInfo *file = *found;
|
||||
ir_fprintf(f,
|
||||
"distinct !DICompileUnit("
|
||||
"language: DW_LANG_C_plus_plus" // Is this good enough?
|
||||
|
||||
+98
-90
@@ -1,5 +1,6 @@
|
||||
// #define NO_ARRAY_BOUNDS_CHECK
|
||||
|
||||
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
#include "tokenizer.cpp"
|
||||
@@ -7,6 +8,10 @@
|
||||
#include "exact_value.cpp"
|
||||
#include "build_settings.cpp"
|
||||
|
||||
|
||||
gb_global Timings global_timings = {0};
|
||||
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "checker.hpp"
|
||||
|
||||
@@ -75,7 +80,7 @@ i32 system_exec_command_line_app(char *name, char *fmt, ...) {
|
||||
va_end(va);
|
||||
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
|
||||
|
||||
//printf("do: %s\n", cmd_line);
|
||||
// printf("do: %s\n", cmd_line);
|
||||
exit_code = system(&cmd_line[0]);
|
||||
|
||||
// pid_t pid = fork();
|
||||
@@ -160,8 +165,9 @@ void usage(String argv0) {
|
||||
print_usage_line(0, "Usage:");
|
||||
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
||||
print_usage_line(0, "Commands:");
|
||||
print_usage_line(1, "build compile .odin file as executable");
|
||||
print_usage_line(1, "run compile and run .odin file");
|
||||
print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
|
||||
print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
|
||||
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
|
||||
print_usage_line(1, "check parse and type check .odin file");
|
||||
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
|
||||
print_usage_line(1, "docs generate documentation for a .odin file");
|
||||
@@ -205,14 +211,14 @@ enum BuildFlagKind {
|
||||
BuildFlag_OutFile,
|
||||
BuildFlag_OptimizationLevel,
|
||||
BuildFlag_ShowTimings,
|
||||
BuildFlag_ShowMoreTimings,
|
||||
BuildFlag_ThreadCount,
|
||||
BuildFlag_KeepTempFiles,
|
||||
BuildFlag_Collection,
|
||||
BuildFlag_Define,
|
||||
BuildFlag_BuildMode,
|
||||
BuildFlag_Target,
|
||||
BuildFlag_Debug,
|
||||
BuildFlag_CrossCompile,
|
||||
BuildFlag_CrossLibDir,
|
||||
BuildFlag_NoBoundsCheck,
|
||||
BuildFlag_NoCRT,
|
||||
BuildFlag_UseLLD,
|
||||
@@ -290,21 +296,21 @@ ExactValue build_param_to_exact_value(String name, String param) {
|
||||
|
||||
bool parse_build_flags(Array<String> args) {
|
||||
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
||||
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String);
|
||||
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None);
|
||||
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None);
|
||||
@@ -375,7 +381,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
param == "0") {
|
||||
value = exact_value_bool(false);
|
||||
} else {
|
||||
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
|
||||
gb_printf_err("Invalid flag parameter for '%.*s' : '%.*s'\n", LIT(name), LIT(param));
|
||||
}
|
||||
} break;
|
||||
case BuildFlagParam_Integer:
|
||||
@@ -447,7 +453,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
path = substring(path, 0, string_extension_position(path));
|
||||
}
|
||||
#endif
|
||||
build_context.out_filepath = path;
|
||||
build_context.out_filepath = path_to_full_path(heap_allocator(), path);
|
||||
} else {
|
||||
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
|
||||
bad_flags = true;
|
||||
@@ -462,6 +468,11 @@ bool parse_build_flags(Array<String> args) {
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.show_timings = true;
|
||||
break;
|
||||
case BuildFlag_ShowMoreTimings:
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
build_context.show_timings = true;
|
||||
build_context.show_more_timings = true;
|
||||
break;
|
||||
case BuildFlag_ThreadCount: {
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
isize count = cast(isize)big_int_to_i64(&value.value_integer);
|
||||
@@ -478,33 +489,6 @@ bool parse_build_flags(Array<String> args) {
|
||||
build_context.keep_temp_files = true;
|
||||
break;
|
||||
|
||||
case BuildFlag_CrossCompile: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
cross_compile_target = value.value_string;
|
||||
#if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
|
||||
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
|
||||
gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_CrossLibDir: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
if (cross_compile_lib_dir.len) {
|
||||
gb_printf_err("Multiple cross compilation library directories\n");
|
||||
bad_flags = true;
|
||||
} else {
|
||||
cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_Collection: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
String str = value.value_string;
|
||||
@@ -623,7 +607,25 @@ bool parse_build_flags(Array<String> args) {
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_Target: {
|
||||
String str = value.value_string;
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) {
|
||||
if (str_eq_ignore_case(str, named_targets[i].name)) {
|
||||
found = true;
|
||||
selected_target_metrics = named_targets + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
gb_printf_err("Unknown target '%.*s'\n", LIT(str));
|
||||
bad_flags = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BuildFlag_BuildMode: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
@@ -635,7 +637,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (str == "dll") {
|
||||
if (str == "dll" || str == "shared") {
|
||||
build_context.is_dll = true;
|
||||
} else if (str == "exe") {
|
||||
build_context.is_dll = false;
|
||||
@@ -889,8 +891,8 @@ i32 exec_llvm_opt(String output_base) {
|
||||
}
|
||||
|
||||
i32 exec_llvm_llc(String output_base) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
return system_exec_command_line_app("llvm-llc",
|
||||
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
||||
"-o \"%.*s.obj\" "
|
||||
@@ -903,30 +905,29 @@ i32 exec_llvm_llc(String output_base) {
|
||||
LIT(build_context.llc_flags));
|
||||
#else
|
||||
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
|
||||
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||
return system_exec_command_line_app("llc",
|
||||
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
|
||||
"%.*s "
|
||||
"%s"
|
||||
"",
|
||||
"%s%.*s",
|
||||
LIT(output_base),
|
||||
build_context.optimization_level,
|
||||
LIT(build_context.llc_flags),
|
||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
|
||||
build_context.cross_compiling ? "-mtriple=" : "",
|
||||
(int) (build_context.cross_compiling ? build_context.target_triplet.len : 0),
|
||||
build_context.target_triplet.text);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int arg_count, char **arg_ptr) {
|
||||
if (arg_count < 2) {
|
||||
usage(make_string_c(arg_ptr[0]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
Timings timings = {0};
|
||||
timings_init(&timings, str_lit("Total Time"), 128);
|
||||
defer (timings_destroy(&timings));
|
||||
Timings *timings = &global_timings;
|
||||
|
||||
timings_init(timings, str_lit("Total Time"), 128);
|
||||
defer (timings_destroy(timings));
|
||||
|
||||
init_string_buffer_memory();
|
||||
init_global_error_collector();
|
||||
@@ -1026,7 +1027,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
}
|
||||
|
||||
|
||||
init_build_context();
|
||||
init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr);
|
||||
if (build_context.word_size == 4) {
|
||||
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
|
||||
return 1;
|
||||
@@ -1035,7 +1036,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
init_universal();
|
||||
// TODO(bill): prevent compiling without a linker
|
||||
|
||||
timings_start_section(&timings, str_lit("parse files"));
|
||||
timings_start_section(timings, str_lit("parse files"));
|
||||
|
||||
Parser parser = {0};
|
||||
if (!init_parser(&parser)) {
|
||||
@@ -1051,7 +1052,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// generate_documentation(&parser);
|
||||
return 0;
|
||||
}
|
||||
timings_start_section(&timings, str_lit("type check"));
|
||||
timings_start_section(timings, str_lit("type check"));
|
||||
|
||||
Checker checker = {0};
|
||||
|
||||
@@ -1067,10 +1068,10 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
if (build_context.no_output_files) {
|
||||
if (build_context.query_data_set_settings.ok) {
|
||||
generate_and_print_query_data(&checker, &timings);
|
||||
generate_and_print_query_data(&checker, timings);
|
||||
} else {
|
||||
if (build_context.show_timings) {
|
||||
show_timings(&checker, &timings);
|
||||
show_timings(&checker, timings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1092,13 +1093,13 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// defer (ir_gen_destroy(&ir_gen));
|
||||
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm ir gen"));
|
||||
timings_start_section(timings, str_lit("llvm ir gen"));
|
||||
ir_gen_tree(&ir_gen);
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm ir opt tree"));
|
||||
timings_start_section(timings, str_lit("llvm ir opt tree"));
|
||||
ir_opt_tree(&ir_gen);
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm ir print"));
|
||||
timings_start_section(timings, str_lit("llvm ir print"));
|
||||
print_llvm_ir(&ir_gen);
|
||||
|
||||
|
||||
@@ -1109,20 +1110,31 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
i32 exit_code = 0;
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm-opt"));
|
||||
timings_start_section(timings, str_lit("llvm-opt"));
|
||||
exit_code = exec_llvm_opt(output_base);
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
timings_start_section(&timings, str_lit("llvm-llc"));
|
||||
timings_start_section(timings, str_lit("llvm-llc"));
|
||||
exit_code = exec_llvm_llc(output_base);
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
if (build_context.cross_compiling) {
|
||||
if (0) {
|
||||
#ifdef GB_SYSTEM_UNIX
|
||||
} else if (selected_target_metrics->metrics == &target_essence_amd64) {
|
||||
system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
|
||||
LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
|
||||
#endif
|
||||
} else {
|
||||
gb_printf_err("Don't know how to cross compile to selected target.\n");
|
||||
}
|
||||
} else {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
timings_start_section(&timings, str_lit("msvc-link"));
|
||||
timings_start_section(timings, str_lit("msvc-link"));
|
||||
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(lib_str));
|
||||
@@ -1213,16 +1225,16 @@ int main(int arg_count, char **arg_ptr) {
|
||||
}
|
||||
|
||||
if (build_context.show_timings) {
|
||||
show_timings(&checker, &timings);
|
||||
show_timings(&checker, timings);
|
||||
}
|
||||
|
||||
remove_temp_files(output_base);
|
||||
|
||||
if (run_output) {
|
||||
system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
|
||||
return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
|
||||
}
|
||||
#else
|
||||
timings_start_section(&timings, str_lit("ld-link"));
|
||||
timings_start_section(timings, str_lit("ld-link"));
|
||||
|
||||
// NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe
|
||||
char cwd[256];
|
||||
@@ -1241,15 +1253,17 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// This allows you to specify '-f' in a #foreign_system_library,
|
||||
// without having to implement any new syntax specifically for MacOS.
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
||||
if (string_ends_with(lib, str_lit(".framework"))) {
|
||||
// framework thingie
|
||||
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
|
||||
String lib_name = lib;
|
||||
lib_name = remove_extension_from_path(lib_name);
|
||||
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
|
||||
} else if (string_ends_with(lib, str_lit(".a"))) {
|
||||
// static libs, absolute full path relative to the file in which the lib was imported from
|
||||
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
|
||||
} else if (string_ends_with(lib, str_lit(".dylib"))) {
|
||||
// dynamic lib, relative path to executable
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
|
||||
// dynamic lib
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||
} else {
|
||||
// dynamic or static system lib, just link regularly searching system library paths
|
||||
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||
@@ -1309,11 +1323,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
// It probably has to do with including the entire CRT, but
|
||||
// that's quite a complicated issue to solve while remaining distro-agnostic.
|
||||
// Clang can figure out linker flags for us, and that's good enough _for now_.
|
||||
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
|
||||
linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
|
||||
} else {
|
||||
linker = "clang -Wno-unused-command-line-argument";
|
||||
}
|
||||
linker = "clang -Wno-unused-command-line-argument";
|
||||
#endif
|
||||
|
||||
exit_code = system_exec_command_line_app("ld-link",
|
||||
@@ -1321,7 +1331,6 @@ int main(int arg_count, char **arg_ptr) {
|
||||
" %s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
" %.*s "
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
||||
@@ -1332,11 +1341,9 @@ int main(int arg_count, char **arg_ptr) {
|
||||
#endif
|
||||
, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
|
||||
lib_str,
|
||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm",
|
||||
"-lc -lm",
|
||||
LIT(build_context.link_flags),
|
||||
link_settings,
|
||||
LIT(cross_compile_lib_dir)
|
||||
);
|
||||
link_settings);
|
||||
if (exit_code != 0) {
|
||||
return exit_code;
|
||||
}
|
||||
@@ -1357,7 +1364,7 @@ int main(int arg_count, char **arg_ptr) {
|
||||
|
||||
|
||||
if (build_context.show_timings) {
|
||||
show_timings(&checker, &timings);
|
||||
show_timings(&checker, timings);
|
||||
}
|
||||
|
||||
remove_temp_files(output_base);
|
||||
@@ -1366,9 +1373,10 @@ int main(int arg_count, char **arg_ptr) {
|
||||
//NOTE(thebirk): This whole thing is a little leaky
|
||||
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
|
||||
complete_path = path_to_full_path(heap_allocator(), complete_path);
|
||||
system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
|
||||
return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+387
-284
File diff suppressed because it is too large
Load Diff
+48
-15
@@ -21,6 +21,7 @@ enum AddressingMode {
|
||||
// lhs: acts like a Variable
|
||||
// rhs: acts like OptionalOk
|
||||
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||
Addressing_SoaVariable, // Struct-Of-Arrays indexed variable
|
||||
};
|
||||
|
||||
struct TypeAndValue {
|
||||
@@ -134,13 +135,26 @@ struct Parser {
|
||||
Map<AstPackage *> package_map; // Key: String (package name)
|
||||
Array<AstPackage *> packages;
|
||||
Array<ImportedPackage> package_imports;
|
||||
Array<ImportedFile> files_to_process;
|
||||
isize file_to_process_count;
|
||||
isize total_token_count;
|
||||
isize total_line_count;
|
||||
gbMutex file_add_mutex;
|
||||
gbMutex file_decl_mutex;
|
||||
};
|
||||
|
||||
|
||||
gb_global ThreadPool parser_thread_pool = {};
|
||||
|
||||
struct ParserWorkerData {
|
||||
Parser *parser;
|
||||
ImportedFile imported_file;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum ProcInlining {
|
||||
ProcInlining_none = 0,
|
||||
ProcInlining_inline = 1,
|
||||
@@ -186,13 +200,12 @@ enum FieldFlag {
|
||||
FieldFlag_c_vararg = 1<<3,
|
||||
FieldFlag_auto_cast = 1<<4,
|
||||
|
||||
FieldFlag_in = 1<<5,
|
||||
|
||||
FieldFlag_Tags = 1<<10,
|
||||
|
||||
FieldFlag_Results = 1<<16,
|
||||
|
||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
|
||||
FieldFlag_Struct = FieldFlag_using,
|
||||
FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
|
||||
};
|
||||
|
||||
enum StmtAllowFlag {
|
||||
@@ -210,6 +223,7 @@ enum StmtAllowFlag {
|
||||
AST_KIND(Undef, "undef", Token) \
|
||||
AST_KIND(BasicLit, "basic literal", struct { \
|
||||
Token token; \
|
||||
ExactValue value; \
|
||||
}) \
|
||||
AST_KIND(BasicDirective, "basic directive", struct { \
|
||||
Token token; \
|
||||
@@ -230,11 +244,14 @@ enum StmtAllowFlag {
|
||||
Ast *body; \
|
||||
u64 tags; \
|
||||
ProcInlining inlining; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
}) \
|
||||
AST_KIND(CompoundLit, "compound literal", struct { \
|
||||
Ast *type; \
|
||||
Array<Ast *> elems; \
|
||||
Token open, close; \
|
||||
i64 max_count; \
|
||||
}) \
|
||||
AST_KIND(_ExprBegin, "", bool) \
|
||||
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
|
||||
@@ -327,6 +344,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
||||
Ast *expr; \
|
||||
Ast *body; \
|
||||
}) \
|
||||
AST_KIND(InlineRangeStmt, "inline range statement", struct { \
|
||||
Token inline_token; \
|
||||
Token for_token; \
|
||||
Ast *val0; \
|
||||
Ast *val1; \
|
||||
Token in_token; \
|
||||
Ast *expr; \
|
||||
Ast *body; \
|
||||
}) \
|
||||
AST_KIND(CaseClause, "case clause", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> list; \
|
||||
@@ -401,6 +427,7 @@ AST_KIND(_DeclBegin, "", bool) \
|
||||
Token library_name; \
|
||||
String collection_name; \
|
||||
Array<String> fullpaths; \
|
||||
Array<Ast *> attributes; \
|
||||
CommentGroup *docs; \
|
||||
CommentGroup *comment; \
|
||||
}) \
|
||||
@@ -414,6 +441,7 @@ AST_KIND(_DeclEnd, "", bool) \
|
||||
Array<Ast *> names; \
|
||||
Ast * type; \
|
||||
Ast * default_value; \
|
||||
Token tag; \
|
||||
u32 flags; \
|
||||
CommentGroup * docs; \
|
||||
CommentGroup * comment; \
|
||||
@@ -467,19 +495,24 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
Ast *elem; \
|
||||
}) \
|
||||
AST_KIND(StructType, "struct type", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> fields; \
|
||||
isize field_count; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast *align; \
|
||||
bool is_packed; \
|
||||
bool is_raw_union; \
|
||||
Token token; \
|
||||
Array<Ast *> fields; \
|
||||
isize field_count; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast *align; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
bool is_packed; \
|
||||
bool is_raw_union; \
|
||||
}) \
|
||||
AST_KIND(UnionType, "union type", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> variants; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast * align; \
|
||||
Token token; \
|
||||
Array<Ast *> variants; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast * align; \
|
||||
bool no_nil; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
}) \
|
||||
AST_KIND(EnumType, "enum type", struct { \
|
||||
Token token; \
|
||||
|
||||
@@ -20,7 +20,7 @@ bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
|
||||
if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
|
||||
j = j2;
|
||||
}
|
||||
if (pq->cmp(&pq->queue[0], i, j) < 0) break;
|
||||
if (pq->cmp(&pq->queue[0], j, i) >= 0) break;
|
||||
|
||||
pq->swap(&pq->queue[0], i, j);
|
||||
i = j;
|
||||
@@ -32,7 +32,7 @@ template <typename T>
|
||||
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
||||
while (0 <= j && j < pq->queue.count) {
|
||||
isize i = (j-1)/2;
|
||||
if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) {
|
||||
if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
|
||||
break;
|
||||
}
|
||||
pq->swap(&pq->queue[0], i, j);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
// Integers only
|
||||
struct RangeValue {
|
||||
i64 lo;
|
||||
i64 hi;
|
||||
};
|
||||
|
||||
struct RangeCache {
|
||||
Array<RangeValue> ranges;
|
||||
};
|
||||
|
||||
|
||||
RangeCache range_cache_make(gbAllocator a) {
|
||||
RangeCache cache = {};
|
||||
array_init(&cache.ranges, a);
|
||||
return cache;
|
||||
}
|
||||
|
||||
void range_cache_destroy(RangeCache *c) {
|
||||
array_free(&c->ranges);
|
||||
}
|
||||
|
||||
bool range_cache_add_index(RangeCache *c, i64 index) {
|
||||
for_array(i, c->ranges) {
|
||||
RangeValue v = c->ranges[i];
|
||||
if (v.lo <= index && index <= v.hi) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
RangeValue v = {index, index};
|
||||
array_add(&c->ranges, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
|
||||
GB_ASSERT(lo <= hi);
|
||||
for_array(i, c->ranges) {
|
||||
RangeValue v = c->ranges[i];
|
||||
if (hi < v.lo) {
|
||||
continue;
|
||||
}
|
||||
if (lo > v.hi) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v.hi < hi) {
|
||||
v.hi = hi;
|
||||
}
|
||||
if (lo < v.lo) {
|
||||
v.lo = lo;
|
||||
}
|
||||
c->ranges[i] = v;
|
||||
return false;
|
||||
}
|
||||
RangeValue v = {lo, hi};
|
||||
array_add(&c->ranges, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool range_cache_index_exists(RangeCache *c, i64 index) {
|
||||
for_array(i, c->ranges) {
|
||||
RangeValue v = c->ranges[i];
|
||||
if (v.lo <= index && index <= v.hi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
+86
-4
@@ -404,7 +404,7 @@ String16 string_to_string16(gbAllocator a, String s) {
|
||||
}
|
||||
text[len] = 0;
|
||||
|
||||
return make_string16(text, len-1);
|
||||
return make_string16(text, len);
|
||||
}
|
||||
|
||||
|
||||
@@ -440,12 +440,94 @@ String string16_to_string(gbAllocator a, String16 s) {
|
||||
|
||||
|
||||
|
||||
bool is_printable(Rune r) {
|
||||
if (r <= 0xff) {
|
||||
if (0x20 <= r && r <= 0x7e) {
|
||||
return true;
|
||||
}
|
||||
if (0xa1 <= r && r <= 0xff) {
|
||||
return r != 0xad;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_global char const lower_hex[] = "0123456789abcdef";
|
||||
|
||||
String quote_to_ascii(gbAllocator a, String str, u8 quote='"') {
|
||||
u8 *s = str.text;
|
||||
isize n = str.len;
|
||||
auto buf = array_make<u8>(a, 0, n);
|
||||
array_add(&buf, quote);
|
||||
for (isize width = 0; n > 0; s += width, n -= width) {
|
||||
Rune r = cast(Rune)s[0];
|
||||
width = 1;
|
||||
if (r >= 0x80) {
|
||||
width = gb_utf8_decode(s, n, &r);
|
||||
}
|
||||
if (width == 1 && r == GB_RUNE_INVALID) {
|
||||
array_add(&buf, cast(u8)'\\');
|
||||
array_add(&buf, cast(u8)'x');
|
||||
array_add(&buf, cast(u8)lower_hex[s[0]>>4]);
|
||||
array_add(&buf, cast(u8)lower_hex[s[0]&0xf]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r == quote || r == '\\') {
|
||||
array_add(&buf, cast(u8)'\\');
|
||||
array_add(&buf, u8(r));
|
||||
continue;
|
||||
}
|
||||
if (r < 0x80 && is_printable(r)) {
|
||||
array_add(&buf, u8(r));
|
||||
continue;
|
||||
}
|
||||
switch (r) {
|
||||
case '\a':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
default:
|
||||
if (r < ' ') {
|
||||
u8 b = cast(u8)r;
|
||||
array_add(&buf, cast(u8)'\\');
|
||||
array_add(&buf, cast(u8)'x');
|
||||
array_add(&buf, cast(u8)lower_hex[b>>4]);
|
||||
array_add(&buf, cast(u8)lower_hex[b&0xf]);
|
||||
}
|
||||
if (r > GB_RUNE_MAX) {
|
||||
r = 0XFFFD;
|
||||
}
|
||||
if (r < 0x10000) {
|
||||
u8 b = cast(u8)r;
|
||||
array_add(&buf, cast(u8)'\\');
|
||||
array_add(&buf, cast(u8)'u');
|
||||
for (isize i = 12; i >= 0; i -= 4) {
|
||||
array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
|
||||
}
|
||||
} else {
|
||||
u8 b = cast(u8)r;
|
||||
array_add(&buf, cast(u8)'\\');
|
||||
array_add(&buf, cast(u8)'U');
|
||||
for (isize i = 28; i >= 0; i -= 4) {
|
||||
array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
array_add(&buf, quote);
|
||||
String res = {};
|
||||
res.text = buf.data;
|
||||
res.len = buf.count;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
// worker_queue.cpp
|
||||
|
||||
#define WORKER_TASK_PROC(name) isize name(void *data)
|
||||
typedef WORKER_TASK_PROC(WorkerTaskProc);
|
||||
|
||||
struct WorkerTask {
|
||||
WorkerTaskProc *do_work;
|
||||
void *data;
|
||||
isize result;
|
||||
};
|
||||
|
||||
|
||||
struct ThreadPool {
|
||||
gbMutex mutex;
|
||||
gbSemaphore sem_available;
|
||||
gbAtomic32 processing_work_count;
|
||||
bool is_running;
|
||||
|
||||
gbAllocator allocator;
|
||||
|
||||
WorkerTask *tasks;
|
||||
isize volatile task_head;
|
||||
isize volatile task_tail;
|
||||
isize volatile task_capacity;
|
||||
|
||||
gbThread *threads;
|
||||
isize thread_count;
|
||||
|
||||
char worker_prefix[10];
|
||||
i32 worker_prefix_len;
|
||||
};
|
||||
|
||||
void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix = nullptr);
|
||||
void thread_pool_destroy(ThreadPool *pool);
|
||||
void thread_pool_start(ThreadPool *pool);
|
||||
void thread_pool_join(ThreadPool *pool);
|
||||
void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data);
|
||||
void thread_pool_kick(ThreadPool *pool);
|
||||
void thread_pool_kick_and_wait(ThreadPool *pool);
|
||||
GB_THREAD_PROC(worker_thread_internal);
|
||||
|
||||
void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) {
|
||||
pool->allocator = a;
|
||||
pool->task_head = 0;
|
||||
pool->task_tail = 0;
|
||||
pool->task_capacity = 1024;
|
||||
pool->tasks = gb_alloc_array(a, WorkerTask, pool->task_capacity);
|
||||
pool->thread_count = gb_max(thread_count, 0);
|
||||
pool->threads = gb_alloc_array(a, gbThread, pool->thread_count);
|
||||
gb_mutex_init(&pool->mutex);
|
||||
gb_semaphore_init(&pool->sem_available);
|
||||
pool->is_running = true;
|
||||
|
||||
pool->worker_prefix_len = 0;
|
||||
if (worker_prefix) {
|
||||
i32 worker_prefix_len = cast(i32)gb_strlen(worker_prefix);
|
||||
worker_prefix_len = gb_min(worker_prefix_len, 10);
|
||||
gb_memmove(pool->worker_prefix, worker_prefix, worker_prefix_len);
|
||||
pool->worker_prefix_len = worker_prefix_len;
|
||||
}
|
||||
|
||||
for (isize i = 0; i < pool->thread_count; i++) {
|
||||
gbThread *t = &pool->threads[i];
|
||||
gb_thread_init(t);
|
||||
t->user_index = i;
|
||||
#if 0
|
||||
// TODO(bill): Fix this on Linux as it causes a seg-fault
|
||||
if (pool->worker_prefix_len > 0) {
|
||||
char worker_name[16] = {};
|
||||
gb_snprintf(worker_name, gb_size_of(worker_name), "%.*s%u", pool->worker_prefix_len, pool->worker_prefix, cast(u16)i);
|
||||
gb_thread_set_name(t, worker_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void thread_pool_start(ThreadPool *pool) {
|
||||
for (isize i = 0; i < pool->thread_count; i++) {
|
||||
gbThread *t = &pool->threads[i];
|
||||
gb_thread_start(t, worker_thread_internal, pool);
|
||||
}
|
||||
}
|
||||
|
||||
void thread_pool_join(ThreadPool *pool) {
|
||||
pool->is_running = false;
|
||||
|
||||
gb_semaphore_post(&pool->sem_available, cast(i32)pool->thread_count);
|
||||
|
||||
gb_yield();
|
||||
|
||||
for (isize i = 0; i < pool->thread_count; i++) {
|
||||
gbThread *t = &pool->threads[i];
|
||||
gb_thread_join(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_pool_destroy(ThreadPool *pool) {
|
||||
thread_pool_join(pool);
|
||||
|
||||
gb_semaphore_destroy(&pool->sem_available);
|
||||
gb_mutex_destroy(&pool->mutex);
|
||||
gb_free(pool->allocator, pool->threads);
|
||||
pool->thread_count = 0;
|
||||
gb_free(pool->allocator, pool->tasks);
|
||||
pool->task_head = 0;
|
||||
pool->task_tail = 0;
|
||||
pool->task_capacity = 0;
|
||||
}
|
||||
|
||||
|
||||
void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) {
|
||||
gb_mutex_lock(&pool->mutex);
|
||||
|
||||
if (pool->task_tail == pool->task_capacity) {
|
||||
isize new_cap = 2*pool->task_capacity + 8;
|
||||
WorkerTask *new_tasks = gb_alloc_array(pool->allocator, WorkerTask, new_cap);
|
||||
gb_memmove(new_tasks, pool->tasks, (pool->task_tail)*gb_size_of(WorkerTask));
|
||||
pool->tasks = new_tasks;
|
||||
pool->task_capacity = new_cap;
|
||||
}
|
||||
WorkerTask task = {};
|
||||
task.do_work = proc;
|
||||
task.data = data;
|
||||
|
||||
pool->tasks[pool->task_tail++] = task;
|
||||
gb_semaphore_post(&pool->sem_available, 1);
|
||||
gb_mutex_unlock(&pool->mutex);
|
||||
}
|
||||
|
||||
bool thread_pool_try_and_pop_task(ThreadPool *pool, WorkerTask *task) {
|
||||
bool got_task = false;
|
||||
if (gb_mutex_try_lock(&pool->mutex)) {
|
||||
if (pool->task_tail > pool->task_head) {
|
||||
gb_atomic32_fetch_add(&pool->processing_work_count, +1);
|
||||
*task = pool->tasks[pool->task_head++];
|
||||
got_task = true;
|
||||
}
|
||||
gb_mutex_unlock(&pool->mutex);
|
||||
}
|
||||
return got_task;
|
||||
}
|
||||
void thread_pool_do_work(ThreadPool *pool, WorkerTask *task) {
|
||||
task->result = task->do_work(task->data);
|
||||
gb_atomic32_fetch_add(&pool->processing_work_count, -1);
|
||||
}
|
||||
|
||||
void thread_pool_wait_to_process(ThreadPool *pool) {
|
||||
while (pool->task_tail > pool->task_head || gb_atomic32_load(&pool->processing_work_count) != 0) {
|
||||
WorkerTask task = {};
|
||||
if (thread_pool_try_and_pop_task(pool, &task)) {
|
||||
thread_pool_do_work(pool, &task);
|
||||
}
|
||||
|
||||
// Safety-kick
|
||||
if (pool->task_tail > pool->task_head && gb_atomic32_load(&pool->processing_work_count) == 0) {
|
||||
gb_mutex_lock(&pool->mutex);
|
||||
gb_semaphore_post(&pool->sem_available, cast(i32)(pool->task_tail-pool->task_head));
|
||||
gb_mutex_unlock(&pool->mutex);
|
||||
}
|
||||
|
||||
gb_yield();
|
||||
}
|
||||
|
||||
thread_pool_join(pool);
|
||||
}
|
||||
|
||||
|
||||
GB_THREAD_PROC(worker_thread_internal) {
|
||||
ThreadPool *pool = cast(ThreadPool *)thread->user_data;
|
||||
while (pool->is_running) {
|
||||
gb_semaphore_wait(&pool->sem_available);
|
||||
|
||||
WorkerTask task = {};
|
||||
if (thread_pool_try_and_pop_task(pool, &task)) {
|
||||
thread_pool_do_work(pool, &task);
|
||||
}
|
||||
}
|
||||
// Cascade
|
||||
gb_semaphore_release(&pool->sem_available);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
-4
@@ -159,19 +159,21 @@ f64 time_stamp(TimeStamp const &ts, u64 freq, TimingUnit unit) {
|
||||
}
|
||||
|
||||
void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Millisecond) {
|
||||
char const SPACES[] = " ";
|
||||
isize max_len;
|
||||
isize const SPACES_LEN = 256;
|
||||
char SPACES[SPACES_LEN+1] = {0};
|
||||
gb_memset(SPACES, ' ', SPACES_LEN);
|
||||
|
||||
|
||||
timings__stop_current_section(t);
|
||||
t->total.finish = time_stamp_time_now();
|
||||
|
||||
max_len = gb_min(36, t->total.label.len);
|
||||
isize max_len = gb_min(36, t->total.label.len);
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
max_len = gb_max(max_len, ts.label.len);
|
||||
}
|
||||
|
||||
GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
|
||||
GB_ASSERT(max_len <= SPACES_LEN);
|
||||
|
||||
t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
|
||||
|
||||
|
||||
+13
-1
@@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
||||
TOKEN_KIND(Token_package, "package"), \
|
||||
TOKEN_KIND(Token_typeid, "typeid"), \
|
||||
TOKEN_KIND(Token_when, "when"), \
|
||||
TOKEN_KIND(Token_where, "where"), \
|
||||
TOKEN_KIND(Token_if, "if"), \
|
||||
TOKEN_KIND(Token_else, "else"), \
|
||||
TOKEN_KIND(Token_for, "for"), \
|
||||
@@ -400,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) {
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_error(TokenPos pos, char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
Token token = {};
|
||||
token.pos = pos;
|
||||
syntax_error_va(token, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_warning(Token token, char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
@@ -745,9 +755,11 @@ exponent:
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
|
||||
if (t->curr_rune == 'i') {
|
||||
switch (t->curr_rune) {
|
||||
case 'i': case 'j': case 'k':
|
||||
token.kind = Token_Imag;
|
||||
advance_to_next_rune(t);
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
+233
-75
@@ -32,6 +32,9 @@ enum BasicKind {
|
||||
Basic_complex64,
|
||||
Basic_complex128,
|
||||
|
||||
Basic_quaternion128,
|
||||
Basic_quaternion256,
|
||||
|
||||
Basic_int,
|
||||
Basic_uint,
|
||||
Basic_uintptr,
|
||||
@@ -66,6 +69,7 @@ enum BasicKind {
|
||||
Basic_UntypedInteger,
|
||||
Basic_UntypedFloat,
|
||||
Basic_UntypedComplex,
|
||||
Basic_UntypedQuaternion,
|
||||
Basic_UntypedString,
|
||||
Basic_UntypedRune,
|
||||
Basic_UntypedNil,
|
||||
@@ -82,17 +86,18 @@ enum BasicFlag {
|
||||
BasicFlag_Unsigned = GB_BIT(2),
|
||||
BasicFlag_Float = GB_BIT(3),
|
||||
BasicFlag_Complex = GB_BIT(4),
|
||||
BasicFlag_Pointer = GB_BIT(5),
|
||||
BasicFlag_String = GB_BIT(6),
|
||||
BasicFlag_Rune = GB_BIT(7),
|
||||
BasicFlag_Untyped = GB_BIT(8),
|
||||
BasicFlag_Quaternion = GB_BIT(5),
|
||||
BasicFlag_Pointer = GB_BIT(6),
|
||||
BasicFlag_String = GB_BIT(7),
|
||||
BasicFlag_Rune = GB_BIT(8),
|
||||
BasicFlag_Untyped = GB_BIT(9),
|
||||
|
||||
BasicFlag_LLVM = GB_BIT(10),
|
||||
BasicFlag_LLVM = GB_BIT(11),
|
||||
|
||||
BasicFlag_EndianLittle = GB_BIT(13),
|
||||
BasicFlag_EndianBig = GB_BIT(14),
|
||||
|
||||
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex,
|
||||
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion,
|
||||
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
||||
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
|
||||
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
||||
@@ -107,21 +112,26 @@ struct BasicType {
|
||||
|
||||
struct TypeStruct {
|
||||
Array<Entity *> fields;
|
||||
Ast *node;
|
||||
Scope * scope;
|
||||
Array<String> tags;
|
||||
Array<i64> offsets;
|
||||
Ast * node;
|
||||
Scope * scope;
|
||||
|
||||
Array<i64> offsets;
|
||||
bool are_offsets_set;
|
||||
bool are_offsets_being_processed;
|
||||
bool is_packed;
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
|
||||
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
||||
i64 custom_align;
|
||||
Entity * names;
|
||||
|
||||
bool are_offsets_set;
|
||||
bool are_offsets_being_processed;
|
||||
bool is_packed;
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
bool is_soa;
|
||||
Type *soa_elem;
|
||||
i64 soa_count;
|
||||
};
|
||||
|
||||
struct TypeUnion {
|
||||
@@ -131,11 +141,11 @@ struct TypeUnion {
|
||||
i64 variant_block_size;
|
||||
i64 custom_align;
|
||||
i64 tag_size;
|
||||
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
Type * polymorphic_params; // Type_Tuple
|
||||
Type * polymorphic_parent;
|
||||
bool no_nil;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
};
|
||||
|
||||
#define TYPE_KINDS \
|
||||
@@ -183,7 +193,9 @@ struct TypeUnion {
|
||||
TYPE_KIND(Tuple, struct { \
|
||||
Array<Entity *> variables; /* Entity_Variable */ \
|
||||
Array<i64> offsets; \
|
||||
bool are_offsets_being_processed; \
|
||||
bool are_offsets_set; \
|
||||
bool is_packed; \
|
||||
}) \
|
||||
TYPE_KIND(Proc, struct { \
|
||||
Ast *node; \
|
||||
@@ -194,9 +206,9 @@ struct TypeUnion {
|
||||
i32 result_count; \
|
||||
Array<Type *> abi_compat_params; \
|
||||
Type * abi_compat_result_type; \
|
||||
bool return_by_pointer; \
|
||||
bool variadic; \
|
||||
i32 variadic_index; \
|
||||
bool variadic; \
|
||||
bool abi_types_set; \
|
||||
bool require_results; \
|
||||
bool c_vararg; \
|
||||
bool is_polymorphic; \
|
||||
@@ -204,6 +216,7 @@ struct TypeUnion {
|
||||
bool has_proc_default_values; \
|
||||
bool has_named_results; \
|
||||
bool diverging; /* no return */ \
|
||||
bool return_by_pointer; \
|
||||
u64 tags; \
|
||||
isize specialization_count; \
|
||||
ProcCallingConvention calling_convention; \
|
||||
@@ -340,6 +353,9 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
|
||||
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
|
||||
|
||||
{Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}},
|
||||
{Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}},
|
||||
|
||||
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
|
||||
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
|
||||
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
|
||||
@@ -375,6 +391,7 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
|
||||
{Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
|
||||
{Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}},
|
||||
{Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}},
|
||||
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
|
||||
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
|
||||
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
|
||||
@@ -410,6 +427,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64];
|
||||
gb_global Type *t_complex64 = &basic_types[Basic_complex64];
|
||||
gb_global Type *t_complex128 = &basic_types[Basic_complex128];
|
||||
|
||||
gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128];
|
||||
gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256];
|
||||
|
||||
gb_global Type *t_int = &basic_types[Basic_int];
|
||||
gb_global Type *t_uint = &basic_types[Basic_uint];
|
||||
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
|
||||
@@ -444,6 +464,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
|
||||
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
|
||||
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
|
||||
gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex];
|
||||
gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
|
||||
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
|
||||
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
|
||||
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
|
||||
@@ -470,6 +491,7 @@ gb_global Type *t_type_info_integer = nullptr;
|
||||
gb_global Type *t_type_info_rune = nullptr;
|
||||
gb_global Type *t_type_info_float = nullptr;
|
||||
gb_global Type *t_type_info_complex = nullptr;
|
||||
gb_global Type *t_type_info_quaternion = nullptr;
|
||||
gb_global Type *t_type_info_any = nullptr;
|
||||
gb_global Type *t_type_info_typeid = nullptr;
|
||||
gb_global Type *t_type_info_string = nullptr;
|
||||
@@ -494,6 +516,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr;
|
||||
gb_global Type *t_type_info_rune_ptr = nullptr;
|
||||
gb_global Type *t_type_info_float_ptr = nullptr;
|
||||
gb_global Type *t_type_info_complex_ptr = nullptr;
|
||||
gb_global Type *t_type_info_quaternion_ptr = nullptr;
|
||||
gb_global Type *t_type_info_any_ptr = nullptr;
|
||||
gb_global Type *t_type_info_typeid_ptr = nullptr;
|
||||
gb_global Type *t_type_info_string_ptr = nullptr;
|
||||
@@ -534,8 +557,27 @@ i64 type_offset_of (Type *t, i32 index);
|
||||
gbString type_to_string (Type *type);
|
||||
void init_map_internal_types(Type *type);
|
||||
Type * bit_set_to_int(Type *t);
|
||||
bool are_types_identical(Type *x, Type *y);
|
||||
|
||||
|
||||
bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
|
||||
if (ptr_set_exists(s, t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(bill, 2019-10-05): This is very slow and it's probably a lot
|
||||
// faster to cache types correctly
|
||||
for_array(i, s->entries) {
|
||||
Type *f = s->entries[i].ptr;
|
||||
if (are_types_identical(t, f)) {
|
||||
ptr_set_add(s, t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *base_type(Type *t) {
|
||||
for (;;) {
|
||||
if (t == nullptr) {
|
||||
@@ -922,6 +964,13 @@ bool is_type_complex(Type *t) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_quaternion(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_f32(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
@@ -1036,14 +1085,40 @@ Type *core_array_type(Type *t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
// NOTE(bill): type can be easily compared using memcmp
|
||||
bool is_type_simple_compare(Type *t) {
|
||||
t = core_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Array:
|
||||
return is_type_simple_compare(t->Array.elem);
|
||||
|
||||
case Type_Basic:
|
||||
if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Type_Pointer:
|
||||
case Type_Proc:
|
||||
case Type_BitSet:
|
||||
case Type_BitField:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *base_complex_elem_type(Type *t) {
|
||||
t = core_type(t);
|
||||
if (is_type_complex(t)) {
|
||||
if (t->kind == Type_Basic) {
|
||||
switch (t->Basic.kind) {
|
||||
// case Basic_complex32: return t_f16;
|
||||
case Basic_complex64: return t_f32;
|
||||
case Basic_complex128: return t_f64;
|
||||
case Basic_UntypedComplex: return t_untyped_float;
|
||||
// case Basic_complex32: return t_f16;
|
||||
case Basic_complex64: return t_f32;
|
||||
case Basic_complex128: return t_f64;
|
||||
case Basic_quaternion128: return t_f32;
|
||||
case Basic_quaternion256: return t_f64;
|
||||
case Basic_UntypedComplex: return t_untyped_float;
|
||||
case Basic_UntypedQuaternion: return t_untyped_float;
|
||||
}
|
||||
}
|
||||
GB_PANIC("Invalid complex type");
|
||||
@@ -1058,6 +1133,10 @@ bool is_type_union(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Union;
|
||||
}
|
||||
bool is_type_soa_struct(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Struct && t->Struct.is_soa;
|
||||
}
|
||||
|
||||
bool is_type_raw_union(Type *t) {
|
||||
t = base_type(t);
|
||||
@@ -1098,12 +1177,11 @@ bool is_type_integer_endian_big(Type *t) {
|
||||
return is_type_integer_endian_big(bit_set_to_int(t));
|
||||
} else if (t->kind == Type_Pointer) {
|
||||
return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
|
||||
} else {
|
||||
GB_PANIC("Unsupported type: %s", type_to_string(t));
|
||||
}
|
||||
return build_context.endian_kind == TargetEndian_Big;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_integer_endian_little(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
@@ -1117,11 +1195,24 @@ bool is_type_integer_endian_little(Type *t) {
|
||||
return is_type_integer_endian_little(bit_set_to_int(t));
|
||||
} else if (t->kind == Type_Pointer) {
|
||||
return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
|
||||
} else {
|
||||
GB_PANIC("Unsupported type: %s", type_to_string(t));
|
||||
}
|
||||
return build_context.endian_kind == TargetEndian_Little;
|
||||
}
|
||||
bool is_type_endian_big(Type *t) {
|
||||
return is_type_integer_endian_big(t);
|
||||
}
|
||||
bool is_type_endian_little(Type *t) {
|
||||
return is_type_integer_endian_little(t);
|
||||
}
|
||||
|
||||
bool is_type_dereferenceable(Type *t) {
|
||||
if (is_type_rawptr(t)) {
|
||||
return false;
|
||||
}
|
||||
return is_type_pointer(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_type_different_to_arch_endianness(Type *t) {
|
||||
switch (build_context.endian_kind) {
|
||||
@@ -1283,6 +1374,19 @@ bool is_type_indexable(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_type_sliceable(Type *t) {
|
||||
Type *bt = base_type(t);
|
||||
switch (bt->kind) {
|
||||
case Type_Basic:
|
||||
return bt->Basic.kind == Basic_string;
|
||||
case Type_Array:
|
||||
case Type_Slice:
|
||||
case Type_DynamicArray:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_polymorphic_record(Type *t) {
|
||||
t = base_type(t);
|
||||
@@ -1468,7 +1572,7 @@ bool type_has_nil(Type *t) {
|
||||
case Type_Map:
|
||||
return true;
|
||||
case Type_Union:
|
||||
return true;
|
||||
return !t->Union.no_nil;
|
||||
case Type_Struct:
|
||||
return false;
|
||||
case Type_Opaque:
|
||||
@@ -1625,7 +1729,8 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
case Type_Union:
|
||||
if (y->kind == Type_Union) {
|
||||
if (x->Union.variants.count == y->Union.variants.count &&
|
||||
x->Union.custom_align == y->Union.custom_align) {
|
||||
x->Union.custom_align == y->Union.custom_align &&
|
||||
x->Union.no_nil == y->Union.no_nil) {
|
||||
// NOTE(bill): zeroth variant is nullptr
|
||||
for_array(i, x->Union.variants) {
|
||||
if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) {
|
||||
@@ -1661,6 +1766,12 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
if (xf_is_using ^ yf_is_using) {
|
||||
return false;
|
||||
}
|
||||
if (x->Struct.tags.count != y->Struct.tags.count) {
|
||||
return false;
|
||||
}
|
||||
if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1681,7 +1792,8 @@ bool are_types_identical(Type *x, Type *y) {
|
||||
|
||||
case Type_Tuple:
|
||||
if (y->kind == Type_Tuple) {
|
||||
if (x->Tuple.variables.count == y->Tuple.variables.count) {
|
||||
if (x->Tuple.variables.count == y->Tuple.variables.count &&
|
||||
x->Tuple.is_packed == y->Tuple.is_packed) {
|
||||
for_array(i, x->Tuple.variables) {
|
||||
Entity *xe = x->Tuple.variables[i];
|
||||
Entity *ye = y->Tuple.variables[i];
|
||||
@@ -1761,6 +1873,7 @@ Type *default_type(Type *type) {
|
||||
case Basic_UntypedInteger: return t_int;
|
||||
case Basic_UntypedFloat: return t_f64;
|
||||
case Basic_UntypedComplex: return t_complex128;
|
||||
case Basic_UntypedQuaternion: return t_quaternion256;
|
||||
case Basic_UntypedString: return t_string;
|
||||
case Basic_UntypedRune: return t_rune;
|
||||
}
|
||||
@@ -1778,7 +1891,11 @@ i64 union_variant_index(Type *u, Type *v) {
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *vt = u->Union.variants[i];
|
||||
if (are_types_identical(v, vt)) {
|
||||
return cast(i64)(i+1);
|
||||
if (u->Union.no_nil) {
|
||||
return cast(i64)(i+0);
|
||||
} else {
|
||||
return cast(i64)(i+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -2081,6 +2198,19 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
||||
sel.index.count = prev_count;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_soa = type->Struct.is_soa;
|
||||
bool is_soa_of_array = is_soa && is_type_array(type->Struct.soa_elem);
|
||||
|
||||
if (is_soa_of_array) {
|
||||
String mapped_field_name = {};
|
||||
if (field_name == "r") mapped_field_name = str_lit("x");
|
||||
else if (field_name == "g") mapped_field_name = str_lit("y");
|
||||
else if (field_name == "b") mapped_field_name = str_lit("z");
|
||||
else if (field_name == "a") mapped_field_name = str_lit("w");
|
||||
return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident);
|
||||
}
|
||||
|
||||
} else if (type->kind == Type_BitField) {
|
||||
for_array(i, type->BitField.fields) {
|
||||
Entity *f = type->BitField.fields[i];
|
||||
@@ -2125,19 +2255,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
||||
if (type->Array.count <= 4) {
|
||||
// HACK(bill): Memory leak
|
||||
switch (type->Array.count) {
|
||||
#define _ARRAY_FIELD_CASE(_length, _name) \
|
||||
case (_length): \
|
||||
if (field_name == _name) { \
|
||||
#define _ARRAY_FIELD_CASE_IF(_length, _name) \
|
||||
if (field_name == (_name)) { \
|
||||
selection_add_index(&sel, (_length)-1); \
|
||||
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
|
||||
return sel; \
|
||||
} \
|
||||
}
|
||||
#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
|
||||
case (_length): \
|
||||
_ARRAY_FIELD_CASE_IF(_length, _name0); \
|
||||
_ARRAY_FIELD_CASE_IF(_length, _name1); \
|
||||
/*fallthrough*/
|
||||
|
||||
_ARRAY_FIELD_CASE(4, "w");
|
||||
_ARRAY_FIELD_CASE(3, "z");
|
||||
_ARRAY_FIELD_CASE(2, "y");
|
||||
_ARRAY_FIELD_CASE(1, "x");
|
||||
_ARRAY_FIELD_CASE(4, "w", "a");
|
||||
_ARRAY_FIELD_CASE(3, "z", "b");
|
||||
_ARRAY_FIELD_CASE(2, "y", "g");
|
||||
_ARRAY_FIELD_CASE(1, "x", "r");
|
||||
default: break;
|
||||
|
||||
#undef _ARRAY_FIELD_CASE
|
||||
@@ -2248,7 +2381,9 @@ i64 type_size_of(Type *t) {
|
||||
return 0;
|
||||
}
|
||||
// NOTE(bill): Always calculate the size when it is a Type_Basic
|
||||
if (t->kind != Type_Basic && t->cached_size >= 0) {
|
||||
if (t->kind == Type_Named && t->cached_size >= 0) {
|
||||
|
||||
} else if (t->kind != Type_Basic && t->cached_size >= 0) {
|
||||
return t->cached_size;
|
||||
}
|
||||
TypePath path = {0};
|
||||
@@ -2263,7 +2398,9 @@ i64 type_align_of(Type *t) {
|
||||
return 1;
|
||||
}
|
||||
// NOTE(bill): Always calculate the size when it is a Type_Basic
|
||||
if (t->kind != Type_Basic && t->cached_align > 0) {
|
||||
if (t->kind == Type_Named && t->cached_align >= 0) {
|
||||
|
||||
} if (t->kind != Type_Basic && t->cached_align > 0) {
|
||||
return t->cached_align;
|
||||
}
|
||||
|
||||
@@ -2297,6 +2434,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
|
||||
case Basic_complex64: case Basic_complex128:
|
||||
return type_size_of_internal(t, path) / 2;
|
||||
case Basic_quaternion128: case Basic_quaternion256:
|
||||
return type_size_of_internal(t, path) / 4;
|
||||
}
|
||||
} break;
|
||||
|
||||
@@ -2482,9 +2621,9 @@ bool type_set_offsets(Type *t) {
|
||||
}
|
||||
} else if (is_type_tuple(t)) {
|
||||
if (!t->Tuple.are_offsets_set) {
|
||||
t->Struct.are_offsets_being_processed = true;
|
||||
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false);
|
||||
t->Struct.are_offsets_being_processed = false;
|
||||
t->Tuple.are_offsets_being_processed = true;
|
||||
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
|
||||
t->Tuple.are_offsets_being_processed = false;
|
||||
t->Tuple.are_offsets_set = true;
|
||||
return true;
|
||||
}
|
||||
@@ -2907,35 +3046,54 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
isize comma_index = 0;
|
||||
for_array(i, type->Tuple.variables) {
|
||||
Entity *var = type->Tuple.variables[i];
|
||||
if (var != nullptr) {
|
||||
if (var->kind == Entity_Constant) {
|
||||
// Ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
if (comma_index++ > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
|
||||
if (var->kind == Entity_Variable) {
|
||||
if (var->flags&EntityFlag_CVarArg) {
|
||||
str = gb_string_appendc(str, "#c_vararg ");
|
||||
}
|
||||
if (var->flags&EntityFlag_Ellipsis) {
|
||||
Type *slice = base_type(var->type);
|
||||
str = gb_string_appendc(str, "..");
|
||||
GB_ASSERT(var->type->kind == Type_Slice);
|
||||
str = write_type_to_string(str, slice->Slice.elem);
|
||||
} else {
|
||||
str = write_type_to_string(str, var->type);
|
||||
}
|
||||
if (var == nullptr) {
|
||||
continue;
|
||||
}
|
||||
String name = var->token.string;
|
||||
if (var->kind == Entity_Constant) {
|
||||
str = gb_string_appendc(str, "$");
|
||||
str = gb_string_append_length(str, name.text, name.len);
|
||||
if (!is_type_untyped(var->type)) {
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_type_to_string(str, var->type);
|
||||
str = gb_string_appendc(str, " = ");
|
||||
str = write_exact_value_to_string(str, var->Constant.value);
|
||||
} else {
|
||||
GB_ASSERT(var->kind == Entity_TypeName);
|
||||
if (var->type->kind == Type_Generic) {
|
||||
str = gb_string_appendc(str, "type/");
|
||||
str = gb_string_appendc(str, "=");
|
||||
str = write_exact_value_to_string(str, var->Constant.value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (comma_index++ > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
|
||||
if (var->kind == Entity_Variable) {
|
||||
if (var->flags&EntityFlag_CVarArg) {
|
||||
str = gb_string_appendc(str, "#c_vararg ");
|
||||
}
|
||||
if (var->flags&EntityFlag_Ellipsis) {
|
||||
Type *slice = base_type(var->type);
|
||||
str = gb_string_appendc(str, "..");
|
||||
GB_ASSERT(var->type->kind == Type_Slice);
|
||||
str = write_type_to_string(str, slice->Slice.elem);
|
||||
} else {
|
||||
str = write_type_to_string(str, var->type);
|
||||
}
|
||||
} else {
|
||||
GB_ASSERT(var->kind == Entity_TypeName);
|
||||
if (var->type->kind == Type_Generic) {
|
||||
str = gb_string_appendc(str, "typeid/");
|
||||
str = write_type_to_string(str, var->type);
|
||||
} else {
|
||||
if (var->kind == Entity_TypeName) {
|
||||
str = gb_string_appendc(str, "$");
|
||||
str = gb_string_append_length(str, name.text, name.len);
|
||||
str = gb_string_appendc(str, "=");
|
||||
str = write_type_to_string(str, var->type);
|
||||
} else {
|
||||
str = gb_string_appendc(str, "type");
|
||||
str = gb_string_appendc(str, "typeid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#pragma warning(disable: 4245)
|
||||
|
||||
extern "C" {
|
||||
#include "utf8proc/utf8proc.h"
|
||||
#include "utf8proc/utf8proc.c"
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
* Implementation of libutf8proc.
|
||||
*/
|
||||
|
||||
|
||||
#include "utf8proc.h"
|
||||
#include "utf8proc_data.c"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user