Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
153e7525b5
83 files changed
+10048
-2578
No files matched your search
@@ -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">
|
<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">
|
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
||||||
</a>
|
</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>
|
<br>
|
||||||
<a href="https://ci.appveyor.com/project/ThisDrunkDane/odin-vf0ap">
|
<a href="https://discord.gg/hnwN2Rj">
|
||||||
<img src="https://ci.appveyor.com/api/projects/status/qss6l921c0eu85u6/branch/master?svg=true">
|
<img src="https://img.shields.io/discord/568138951836172421?logo=discord">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://travis-ci.org/odin-lang/Odin">
|
<a href="https://github.com/odin-lang/odin/actions">
|
||||||
<img src="https://travis-ci.org/odin-lang/Odin.svg?branch=master">
|
<img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -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 *.pdb > NUL 2> NUL
|
||||||
del *.ilk > NUL 2> NUL
|
del *.ilk > NUL 2> NUL
|
||||||
|
|
||||||
|
|
||||||
cl %compiler_settings% "src\main.cpp" ^
|
cl %compiler_settings% "src\main.cpp" ^
|
||||||
/link %linker_settings% -OUT:%exe_name% ^
|
/link %linker_settings% -OUT:%exe_name% ^
|
||||||
&& odin run examples/demo/demo.odin
|
&& 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;
|
ptrdiff_t :: b.int;
|
||||||
uintptr_t :: b.uintptr;
|
uintptr_t :: b.uintptr;
|
||||||
intptr_t :: b.int;
|
intptr_t :: b.int;
|
||||||
|
|
||||||
|
wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32;
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
|
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
|
||||||
fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
|
fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
|
||||||
fmt.printf_err(msg, ..args);
|
fmt.eprintf(msg, ..args);
|
||||||
fmt.println_err();
|
fmt.eprintln();
|
||||||
|
|
||||||
p.error_count += 1;
|
p.error_count += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
|
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.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
|
||||||
fmt.printf_err(msg, ..args);
|
fmt.eprintf(msg, ..args);
|
||||||
fmt.println_err();
|
fmt.eprintln();
|
||||||
t.error_count += 1;
|
t.error_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import "core:math/bits"
|
|||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
import "core:strconv"
|
import "core:strconv"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:types"
|
import "core:reflect"
|
||||||
|
|
||||||
Marshal_Error :: enum {
|
Marshal_Error :: enum {
|
||||||
None,
|
None,
|
||||||
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
|||||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||||
header := cast(^Map_Entry_Header)data;
|
header := cast(^Map_Entry_Header)data;
|
||||||
|
|
||||||
if types.is_string(info.key) {
|
if reflect.is_string(info.key) {
|
||||||
marshal_arg(b, header.key.str);
|
marshal_arg(b, header.key.str);
|
||||||
} else {
|
} else {
|
||||||
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
|
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
|
||||||
@@ -284,11 +284,10 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
|
|||||||
t := runtime.type_info_base(ti);
|
t := runtime.type_info_base(ti);
|
||||||
switch info in t.variant {
|
switch info in t.variant {
|
||||||
case runtime.Type_Info_Integer:
|
case runtime.Type_Info_Integer:
|
||||||
using runtime.Type_Info_Endianness;
|
|
||||||
switch info.endianness {
|
switch info.endianness {
|
||||||
case Platform: return false;
|
case .Platform: return false;
|
||||||
case Little: return ODIN_ENDIAN != "little";
|
case .Little: return ODIN_ENDIAN != "little";
|
||||||
case Big: return ODIN_ENDIAN != "big";
|
case .Big: return ODIN_ENDIAN != "big";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+54
-228
@@ -5,9 +5,9 @@ import "core:os"
|
|||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:math/bits"
|
import "core:math/bits"
|
||||||
import "core:unicode/utf8"
|
import "core:unicode/utf8"
|
||||||
import "core:types"
|
|
||||||
import "core:strconv"
|
import "core:strconv"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
import "core:reflect"
|
||||||
|
|
||||||
|
|
||||||
@private
|
@private
|
||||||
@@ -60,11 +60,17 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
|||||||
|
|
||||||
// print* procedures return the number of bytes written
|
// print* procedures return the number of bytes written
|
||||||
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
|
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 :: 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 :: 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); }
|
|
||||||
|
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
|
// 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) {
|
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
|
||||||
data: [DEFAULT_BUFFER_SIZE]byte;
|
data: [DEFAULT_BUFFER_SIZE]byte;
|
||||||
buf := strings.builder_from_slice(data[:]);
|
buf := strings.builder_from_slice(data[:]);
|
||||||
write_type(&buf, info);
|
reflect.write_type(&buf, info);
|
||||||
os.write_string(fd, strings.to_string(buf));
|
os.write_string(fd, strings.to_string(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
|
|||||||
fi.buf = buf;
|
fi.buf = buf;
|
||||||
|
|
||||||
for arg, i in args {
|
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 {
|
if i > 0 && !is_string && !prev_string {
|
||||||
strings.write_byte(buf, ' ');
|
strings.write_byte(buf, ' ');
|
||||||
}
|
}
|
||||||
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
|
|||||||
strings.write_rune(buf, verb);
|
strings.write_rune(buf, verb);
|
||||||
strings.write_byte(buf, '(');
|
strings.write_byte(buf, '(');
|
||||||
if arg.id != nil {
|
if arg.id != nil {
|
||||||
write_typeid(buf, arg.id);
|
reflect.write_typeid(buf, arg.id);
|
||||||
strings.write_byte(buf, '=');
|
strings.write_byte(buf, '=');
|
||||||
fmt_value(fi, arg, 'v');
|
fmt_value(fi, arg, 'v');
|
||||||
} else {
|
} else {
|
||||||
@@ -792,7 +798,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) {
|
|||||||
case: return "", false;
|
case: return "", false;
|
||||||
case runtime.Type_Info_Enum:
|
case runtime.Type_Info_Enum:
|
||||||
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
|
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 {
|
for val, idx in e.values {
|
||||||
if v, ok := val.(T); ok && v == i {
|
if v, ok := val.(T); ok && v == i {
|
||||||
return e.names[idx], true;
|
return e.names[idx], true;
|
||||||
@@ -947,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
|||||||
if name != "" {
|
if name != "" {
|
||||||
strings.write_string(fi.buf, name);
|
strings.write_string(fi.buf, name);
|
||||||
} else {
|
} else {
|
||||||
write_type(fi.buf, type_info);
|
reflect.write_type(fi.buf, type_info);
|
||||||
}
|
}
|
||||||
strings.write_byte(fi.buf, '{');
|
strings.write_byte(fi.buf, '{');
|
||||||
defer strings.write_byte(fi.buf, '}');
|
defer strings.write_byte(fi.buf, '}');
|
||||||
@@ -1042,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 {
|
if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
|
||||||
elem := rt.type_info_base(ot.elem);
|
elem := rt.type_info_base(ot.elem);
|
||||||
if elem == nil do return;
|
if elem == nil do return;
|
||||||
write_type(fi.buf, type_info);
|
reflect.write_type(fi.buf, type_info);
|
||||||
strings.write_byte(fi.buf, '{');
|
strings.write_byte(fi.buf, '{');
|
||||||
defer strings.write_byte(fi.buf, '}');
|
defer strings.write_byte(fi.buf, '}');
|
||||||
|
|
||||||
@@ -1053,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
|
|||||||
// Okay
|
// Okay
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write_type(fi.buf, type_info);
|
reflect.write_type(fi.buf, type_info);
|
||||||
strings.write_byte(fi.buf, '{');
|
strings.write_byte(fi.buf, '{');
|
||||||
strings.write_byte(fi.buf, '}');
|
strings.write_byte(fi.buf, '}');
|
||||||
}
|
}
|
||||||
@@ -1101,7 +1107,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
strings.write_string(fi.buf, name);
|
strings.write_string(fi.buf, name);
|
||||||
strings.write_string(fi.buf, " = ");
|
strings.write_string(fi.buf, " = ");
|
||||||
|
|
||||||
if t := b.types[i]; types.is_any(t) {
|
if t := b.types[i]; reflect.is_any(t) {
|
||||||
strings.write_string(fi.buf, "any{}");
|
strings.write_string(fi.buf, "any{}");
|
||||||
} else {
|
} else {
|
||||||
data := rawptr(uintptr(v.data) + b.offsets[i]);
|
data := rawptr(uintptr(v.data) + b.offsets[i]);
|
||||||
@@ -1129,11 +1135,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
|
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
|
||||||
case runtime.Type_Info_Float: 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_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_String: fmt_arg(fi, v, verb);
|
||||||
|
|
||||||
case runtime.Type_Info_Pointer:
|
case runtime.Type_Info_Pointer:
|
||||||
if v.id == typeid_of(^runtime.Type_Info) {
|
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 {
|
} else {
|
||||||
ptr := (^rawptr)(v.data)^;
|
ptr := (^rawptr)(v.data)^;
|
||||||
if verb != 'p' && info.elem != nil {
|
if verb != 'p' && info.elem != nil {
|
||||||
@@ -1256,7 +1263,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||||
header := cast(^runtime.Map_Entry_Header)data;
|
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);
|
strings.write_string(fi.buf, header.key.str);
|
||||||
} else {
|
} else {
|
||||||
fi := Info{buf = fi.buf};
|
fi := Info{buf = fi.buf};
|
||||||
@@ -1297,7 +1304,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
strings.write_string(fi.buf, info.names[i]);
|
strings.write_string(fi.buf, info.names[i]);
|
||||||
strings.write_string(fi.buf, " = ");
|
strings.write_string(fi.buf, " = ");
|
||||||
|
|
||||||
if t := info.types[i]; types.is_any(t) {
|
if t := info.types[i]; reflect.is_any(t) {
|
||||||
strings.write_string(fi.buf, "any{}");
|
strings.write_string(fi.buf, "any{}");
|
||||||
} else {
|
} else {
|
||||||
data := uintptr(v.data) + info.offsets[i];
|
data := uintptr(v.data) + info.offsets[i];
|
||||||
@@ -1349,14 +1356,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
if ptr == nil {
|
if ptr == nil {
|
||||||
strings.write_string(fi.buf, "nil");
|
strings.write_string(fi.buf, "nil");
|
||||||
} else {
|
} else {
|
||||||
write_typeid(fi.buf, v.id);
|
reflect.write_typeid(fi.buf, v.id);
|
||||||
strings.write_string(fi.buf, " @ ");
|
strings.write_string(fi.buf, " @ ");
|
||||||
fmt_pointer(fi, ptr, 'p');
|
fmt_pointer(fi, ptr, 'p');
|
||||||
}
|
}
|
||||||
|
|
||||||
case runtime.Type_Info_Type_Id:
|
case runtime.Type_Info_Type_Id:
|
||||||
id := (^typeid)(v.data)^;
|
id := (^typeid)(v.data)^;
|
||||||
write_typeid(fi.buf, id);
|
reflect.write_typeid(fi.buf, id);
|
||||||
|
|
||||||
case runtime.Type_Info_Bit_Field:
|
case runtime.Type_Info_Bit_Field:
|
||||||
fmt_bit_field(fi, v);
|
fmt_bit_field(fi, v);
|
||||||
@@ -1386,6 +1393,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) {
|
fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
||||||
if arg == nil {
|
if arg == nil {
|
||||||
strings.write_string(fi.buf, "<nil>");
|
strings.write_string(fi.buf, "<nil>");
|
||||||
@@ -1398,7 +1430,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
|||||||
switch a in arg {
|
switch a in arg {
|
||||||
case ^runtime.Type_Info: ti = a;
|
case ^runtime.Type_Info: ti = a;
|
||||||
}
|
}
|
||||||
write_type(fi.buf, ti);
|
reflect.write_type(fi.buf, ti);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1434,6 +1466,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
|||||||
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
case complex64: fmt_complex(fi, complex128(a), 64, verb);
|
||||||
case complex128: fmt_complex(fi, a, 128, 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 i8: fmt_int(fi, u64(a), true, 8, verb);
|
||||||
case u8: fmt_int(fi, u64(a), false, 8, verb);
|
case u8: fmt_int(fi, u64(a), false, 8, verb);
|
||||||
case i16: fmt_int(fi, u64(a), true, 16, verb);
|
case i16: fmt_int(fi, u64(a), true, 16, verb);
|
||||||
@@ -1449,7 +1484,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
|
|||||||
case string: fmt_string(fi, a, verb);
|
case string: fmt_string(fi, a, verb);
|
||||||
case cstring: fmt_cstring(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 i16le: fmt_int(fi, u64(a), true, 16, verb);
|
||||||
case u16le: fmt_int(fi, u64(a), false, 16, verb);
|
case u16le: fmt_int(fi, u64(a), false, 16, verb);
|
||||||
@@ -1482,212 +1517,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,126 @@
|
|||||||
|
// 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_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{
|
Default_Console_Logger_Opts :: Options{
|
||||||
Option.Level,
|
.Level,
|
||||||
Option.Terminal_Color,
|
.Terminal_Color,
|
||||||
Option.Short_File_Path,
|
.Short_File_Path,
|
||||||
Option.Line,
|
.Line,
|
||||||
Option.Procedure,
|
.Procedure,
|
||||||
} | Full_Timestamp_Opts;
|
} | Full_Timestamp_Opts;
|
||||||
|
|
||||||
Default_File_Logger_Opts :: Options{
|
Default_File_Logger_Opts :: Options{
|
||||||
Option.Level,
|
.Level,
|
||||||
Option.Short_File_Path,
|
.Short_File_Path,
|
||||||
Option.Line,
|
.Line,
|
||||||
Option.Procedure,
|
.Procedure,
|
||||||
} | Full_Timestamp_Opts;
|
} | 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;
|
case Level.Error, Level.Fatal : col = RED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if Option.Level in opts {
|
if .Level in opts {
|
||||||
if Option.Terminal_Color in opts do fmt.sbprint(str, col);
|
if .Terminal_Color in opts do fmt.sbprint(str, col);
|
||||||
fmt.sbprint(str, Level_Headers[level]);
|
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;
|
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
|
||||||
|
|
||||||
file := location.file_path;
|
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 := '/';
|
when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
|
||||||
last := 0;
|
last := 0;
|
||||||
for r, i in location.file_path do if r == delimiter do last = i+1;
|
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 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, ".");
|
if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
|
||||||
fmt.sbprintf(buf, "%s()", location.procedure);
|
fmt.sbprintf(buf, "%s()", location.procedure);
|
||||||
}
|
}
|
||||||
|
|
||||||
if Option.Line in opts {
|
if .Line in opts {
|
||||||
if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":");
|
if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
|
||||||
fmt.sbprint(buf, location.line);
|
fmt.sbprint(buf, location.line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-10
@@ -23,18 +23,18 @@ Option :: enum {
|
|||||||
|
|
||||||
Options :: bit_set[Option];
|
Options :: bit_set[Option];
|
||||||
Full_Timestamp_Opts :: Options{
|
Full_Timestamp_Opts :: Options{
|
||||||
Option.Date,
|
.Date,
|
||||||
Option.Time
|
.Time
|
||||||
};
|
};
|
||||||
Location_Header_Opts :: Options{
|
Location_Header_Opts :: Options{
|
||||||
Option.Short_File_Path,
|
.Short_File_Path,
|
||||||
Option.Long_File_Path,
|
.Long_File_Path,
|
||||||
Option.Line,
|
.Line,
|
||||||
Option.Procedure,
|
.Procedure,
|
||||||
};
|
};
|
||||||
Location_File_Opts :: Options{
|
Location_File_Opts :: Options{
|
||||||
Option.Short_File_Path,
|
.Short_File_Path,
|
||||||
Option.Long_File_Path
|
.Long_File_Path
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
|
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
|
||||||
@@ -64,8 +64,12 @@ destroy_multi_logger ::proc(log : ^Logger) {
|
|||||||
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
|
||||||
options: Options, location := #caller_location) {
|
options: Options, location := #caller_location) {
|
||||||
data := cast(^Multi_Logger_Data)logger_data;
|
data := cast(^Multi_Logger_Data)logger_data;
|
||||||
if data.loggers == nil || len(data.loggers) == 0 do return;
|
if data.loggers == nil || len(data.loggers) == 0 {
|
||||||
for log in data.loggers do log.procedure(log.data, level, text, log.options, location);
|
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) {
|
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};
|
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);
|
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);
|
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);
|
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
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[3] - b[2]*a[3]);
|
||||||
|
c[2] = +(a[3]*b[1] - b[3]*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[i][k] += a[i][j] * b[j][k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mul_matrix_differ :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: [I][K]E)
|
||||||
|
where !intrinsics.type_is_array(E),
|
||||||
|
intrinsics.type_is_numeric(E),
|
||||||
|
I != J {
|
||||||
|
for i in 0..<I {
|
||||||
|
for k in 0..<K {
|
||||||
|
for j in 0..<J {
|
||||||
|
c[i][k] += a[i][j] * b[j][k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
+386
-387
@@ -1,36 +1,41 @@
|
|||||||
package math
|
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;
|
TAU :: 6.28318530717958647692528676655900576;
|
||||||
PI :: 3.14159265358979323846264338327950288;
|
PI :: 3.14159265358979323846264338327950288;
|
||||||
|
|
||||||
E :: 2.71828182845904523536;
|
E :: 2.71828182845904523536;
|
||||||
|
|
||||||
|
τ :: TAU;
|
||||||
|
π :: PI;
|
||||||
|
e :: E;
|
||||||
|
|
||||||
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
SQRT_TWO :: 1.41421356237309504880168872420969808;
|
||||||
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
SQRT_THREE :: 1.73205080756887729352744634150587236;
|
||||||
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
||||||
|
|
||||||
LOG_TWO :: 0.693147180559945309417232121458176568;
|
LN2 :: 0.693147180559945309417232121458176568;
|
||||||
LOG_TEN :: 2.30258509299404568401799145468436421;
|
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;
|
RAD_PER_DEG :: TAU/360.0;
|
||||||
π :: PI;
|
DEG_PER_RAD :: 360.0/TAU;
|
||||||
|
|
||||||
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};
|
|
||||||
|
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="none")
|
||||||
foreign _ {
|
foreign _ {
|
||||||
@(link_name="llvm.sqrt.f32")
|
@(link_name="llvm.sqrt.f32")
|
||||||
sqrt_f32 :: proc(x: f32) -> f32 ---;
|
sqrt_f32 :: proc(x: f32) -> f32 ---;
|
||||||
@@ -58,9 +63,9 @@ foreign _ {
|
|||||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
|
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
|
||||||
|
|
||||||
@(link_name="llvm.log.f32")
|
@(link_name="llvm.log.f32")
|
||||||
log_f32 :: proc(x: f32) -> f32 ---;
|
ln_f32 :: proc(x: f32) -> f32 ---;
|
||||||
@(link_name="llvm.log.f64")
|
@(link_name="llvm.log.f64")
|
||||||
log_f64 :: proc(x: f64) -> f64 ---;
|
ln_f64 :: proc(x: f64) -> f64 ---;
|
||||||
|
|
||||||
@(link_name="llvm.exp.f32")
|
@(link_name="llvm.exp.f32")
|
||||||
exp_f32 :: proc(x: f32) -> f32 ---;
|
exp_f32 :: proc(x: f32) -> f32 ---;
|
||||||
@@ -68,20 +73,40 @@ foreign _ {
|
|||||||
exp_f64 :: proc(x: f64) -> f64 ---;
|
exp_f64 :: proc(x: f64) -> f64 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
log :: proc{log_f32, log_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};
|
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_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
|
||||||
tan_f64 :: proc "c" (θ: f64) -> f64 { 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; }
|
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_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_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 f32(int(0 < x) - int(x < 0)); }
|
||||||
sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
|
||||||
sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
sign :: proc{sign_f32, sign_f64};
|
||||||
|
|
||||||
copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
||||||
ix := transmute(u32)x;
|
ix := transmute(u32)x;
|
||||||
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
|
|||||||
ix |= iy & 0x8000_0000;
|
ix |= iy & 0x8000_0000;
|
||||||
return transmute(f32)ix;
|
return transmute(f32)ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
||||||
ix := transmute(u64)x;
|
ix := transmute(u64)x;
|
||||||
iy := transmute(u64)y;
|
iy := transmute(u64)y;
|
||||||
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
|
|||||||
ix |= iy & 0x8000_0000_0000_0000;
|
ix |= iy & 0x8000_0000_0000_0000;
|
||||||
return transmute(f64)ix;
|
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};
|
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); }
|
to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
|
||||||
round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
|
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};
|
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 {
|
floor_f32 :: proc(x: f32) -> f32 {
|
||||||
if x == 0 || is_nan(x) || is_inf(x) {
|
if x == 0 || is_nan(x) || is_inf(x) {
|
||||||
return x;
|
return x;
|
||||||
@@ -144,33 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
floor :: proc{floor_f32, floor_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; }
|
floor_div :: proc(x, y: $T) -> T
|
||||||
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
|
where intrinsics.type_is_integer(T) {
|
||||||
remainder :: proc{remainder_f32, remainder_f64};
|
a := x / y;
|
||||||
|
r := x % y;
|
||||||
|
if (r > 0 && y < 0) || (r < 0 && y > 0) {
|
||||||
|
a -= 1;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
mod_f32 :: proc(x, y: f32) -> (n: f32) {
|
floor_mod :: proc(x, y: $T) -> T
|
||||||
z := abs(y);
|
where intrinsics.type_is_integer(T) {
|
||||||
n = remainder(abs(x), z);
|
r := x % y;
|
||||||
if sign(n) < 0 {
|
if (r > 0 && y < 0) || (r < 0 && y > 0) {
|
||||||
n += z;
|
r += y;
|
||||||
}
|
}
|
||||||
return copy_sign(n, x);
|
return r;
|
||||||
}
|
}
|
||||||
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};
|
|
||||||
|
|
||||||
// TODO(bill): These need to implemented with the actual instructions
|
|
||||||
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
||||||
shift :: 32 - 8 - 1;
|
shift :: 32 - 8 - 1;
|
||||||
mask :: 0xff;
|
mask :: 0xff;
|
||||||
@@ -190,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
|
|||||||
i := transmute(u32)x;
|
i := transmute(u32)x;
|
||||||
e := uint(i>>shift)&mask - bias;
|
e := uint(i>>shift)&mask - bias;
|
||||||
|
|
||||||
if e < 32-9 {
|
if e < shift {
|
||||||
i &~= 1<<(32-9-e) - 1;
|
i &~= 1<<(shift-e) - 1;
|
||||||
}
|
}
|
||||||
int = transmute(f32)i;
|
int = transmute(f32)i;
|
||||||
frac = x - int;
|
frac = x - int;
|
||||||
@@ -216,360 +301,274 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
|
|||||||
i := transmute(u64)x;
|
i := transmute(u64)x;
|
||||||
e := uint(i>>shift)&mask - bias;
|
e := uint(i>>shift)&mask - bias;
|
||||||
|
|
||||||
if e < 64-12 {
|
if e < shift {
|
||||||
i &~= 1<<(64-12-e) - 1;
|
i &~= 1<<(shift-e) - 1;
|
||||||
}
|
}
|
||||||
int = transmute(f64)i;
|
int = transmute(f64)i;
|
||||||
frac = x - int;
|
frac = x - int;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
modf :: proc{modf_f32, modf_f64};
|
modf :: proc{modf_f32, modf_f64};
|
||||||
|
split_decimal :: modf;
|
||||||
|
|
||||||
is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; }
|
mod_f32 :: proc(x, y: f32) -> (n: f32) {
|
||||||
is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; }
|
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_nan :: proc{is_nan_f32, is_nan_f64};
|
||||||
|
|
||||||
is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); }
|
is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; }
|
||||||
is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); }
|
is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; }
|
||||||
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 :: proc{is_inf_f32, is_inf_f64};
|
is_inf :: proc{is_inf_f32, is_inf_f64};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
|
is_power_of_two :: proc(x: int) -> bool {
|
||||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
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];
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cross2 :: proc(a, b: $T/[2]$E) -> E {
|
next_power_of_two :: proc(x: int) -> int {
|
||||||
return a[0]*b[1] - a[1]*b[0];
|
k := x -1;
|
||||||
|
when size_of(int) == 8 {
|
||||||
|
k = k | (k >> 32);
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
cross3 :: proc(a, b: $T/[3]$E) -> T {
|
sum :: proc(x: $T/[]$E) -> (res: E)
|
||||||
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
|
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||||
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
|
for i in x {
|
||||||
return T(i - j);
|
res += i;
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prod :: proc(x: $T/[]$E) -> (res: E)
|
||||||
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }
|
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||||
|
for i in x {
|
||||||
norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); }
|
res *= i;
|
||||||
|
}
|
||||||
norm0 :: proc(v: $T/[$N]$E) -> T {
|
return;
|
||||||
m := length(v);
|
|
||||||
return m == 0 ? 0 : v/m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cumsum_inplace :: proc(x: $T/[]$E) -> T
|
||||||
|
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||||
identity :: proc($T: typeid/[$N][N]$E) -> T {
|
for i in 1..<len(x) {
|
||||||
m: T;
|
x[i] = x[i-1] + x[i];
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat3_mul :: proc(a, b: Mat3) -> Mat3 {
|
|
||||||
c: Mat3;
|
cumsum :: proc(dst, src: $T/[]$E) -> T
|
||||||
for j in 0..<3 {
|
where intrinsics.BuiltinProc_type_is_numeric(E) {
|
||||||
for i in 0..<3 {
|
N := min(len(dst), len(src));
|
||||||
c[j][i] = a[0][i]*b[j][0] +
|
if N > 0 {
|
||||||
a[1][i]*b[j][1] +
|
dst[0] = src[0];
|
||||||
a[2][i]*b[j][2];
|
for i in 1..<N {
|
||||||
|
dst[i] = dst[i-1] + src[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c;
|
return dst[:N];
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|
||||||
mm := m;
|
|
||||||
mm[0][0] *= v[0];
|
|
||||||
mm[1][1] *= v[1];
|
|
||||||
mm[2][2] *= v[2];
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 {
|
|
||||||
mm := m;
|
|
||||||
mm[0][0] *= s;
|
|
||||||
mm[1][1] *= s;
|
|
||||||
mm[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_DIG :: 6;
|
||||||
F32_EPSILON :: 1.192092896e-07;
|
F32_EPSILON :: 1.192092896e-07;
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
|
|||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
for {
|
for {
|
||||||
x = -math.log(float64(r)) * (1.0/ rn);
|
x = -math.ln(float64(r)) * (1.0/ rn);
|
||||||
y := -math.log(float64(r));
|
y := -math.ln(float64(r));
|
||||||
if y+y >= x*x {
|
if y+y >= x*x {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package mem
|
package mem
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ Raw_Map :: struct {
|
|||||||
entries: Raw_Dynamic_Array,
|
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 {
|
make_any :: inline proc(data: rawptr, id: typeid) -> any {
|
||||||
return transmute(any)Raw_Any{data, id};
|
return transmute(any)Raw_Any{data, id};
|
||||||
|
|||||||
+110
-101
@@ -1,11 +1,10 @@
|
|||||||
package odin_ast
|
package odin_ast
|
||||||
|
|
||||||
import "core:odin/token"
|
import "core:odin/tokenizer"
|
||||||
|
|
||||||
Proc_Tag :: enum {
|
Proc_Tag :: enum {
|
||||||
Bounds_Check,
|
Bounds_Check,
|
||||||
No_Bounds_Check,
|
No_Bounds_Check,
|
||||||
Require_Results,
|
|
||||||
}
|
}
|
||||||
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
|
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
|
||||||
|
|
||||||
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
|
|||||||
|
|
||||||
|
|
||||||
Comment_Group :: struct {
|
Comment_Group :: struct {
|
||||||
list: []token.Token,
|
list: []tokenizer.Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
Node :: struct {
|
Node :: struct {
|
||||||
pos: token.Pos,
|
pos: tokenizer.Pos,
|
||||||
end: token.Pos,
|
end: tokenizer.Pos,
|
||||||
derived: any,
|
derived: any,
|
||||||
state_flags: Node_State_Flags,
|
state_flags: Node_State_Flags,
|
||||||
}
|
}
|
||||||
@@ -68,29 +67,29 @@ Ident :: struct {
|
|||||||
|
|
||||||
Implicit :: struct {
|
Implicit :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Undef :: struct {
|
Undef :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
}
|
}
|
||||||
|
|
||||||
Basic_Lit :: struct {
|
Basic_Lit :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
Basic_Directive :: struct {
|
Basic_Directive :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
name: string,
|
name: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ellipsis :: struct {
|
Ellipsis :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
|
|||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
tags: Proc_Tags,
|
tags: Proc_Tags,
|
||||||
inlining: Proc_Inlining,
|
inlining: Proc_Inlining,
|
||||||
|
where_token: tokenizer.Token,
|
||||||
|
where_clauses: []^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Comp_Lit :: struct {
|
Comp_Lit :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
elems: []^Expr,
|
elems: []^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Tag_Expr :: struct {
|
Tag_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
name: string,
|
name: string,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Unary_Expr :: struct {
|
Unary_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Binary_Expr :: struct {
|
Binary_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
left: ^Expr,
|
left: ^Expr,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
right: ^Expr,
|
right: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Paren_Expr :: struct {
|
Paren_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Selector_Expr :: struct {
|
Selector_Expr :: struct {
|
||||||
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
|
|||||||
Index_Expr :: struct {
|
Index_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
index: ^Expr,
|
index: ^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Deref_Expr :: struct {
|
Deref_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
Slice_Expr :: struct {
|
Slice_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
low: ^Expr,
|
low: ^Expr,
|
||||||
interval: token.Token,
|
interval: tokenizer.Token,
|
||||||
high: ^Expr,
|
high: ^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Call_Expr :: struct {
|
Call_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
inlining: Proc_Inlining,
|
inlining: Proc_Inlining,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
args: []^Expr,
|
args: []^Expr,
|
||||||
ellipsis: token.Token,
|
ellipsis: tokenizer.Token,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Field_Value :: struct {
|
Field_Value :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
field: ^Expr,
|
field: ^Expr,
|
||||||
sep: token.Pos,
|
sep: tokenizer.Pos,
|
||||||
value: ^Expr,
|
value: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ternary_Expr :: struct {
|
Ternary_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
op1: token.Token,
|
op1: tokenizer.Token,
|
||||||
x: ^Expr,
|
x: ^Expr,
|
||||||
op2: token.Token,
|
op2: tokenizer.Token,
|
||||||
y: ^Expr,
|
y: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Assertion :: struct {
|
Type_Assertion :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
dot: token.Pos,
|
dot: tokenizer.Pos,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Cast :: struct {
|
Type_Cast :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Auto_Cast :: struct {
|
Auto_Cast :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
|
|||||||
|
|
||||||
Empty_Stmt :: struct {
|
Empty_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
semicolon: token.Pos, // Position of the following ';'
|
semicolon: tokenizer.Pos, // Position of the following ';'
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr_Stmt :: struct {
|
Expr_Stmt :: struct {
|
||||||
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
|
|||||||
|
|
||||||
Tag_Stmt :: struct {
|
Tag_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
name: string,
|
name: string,
|
||||||
stmt: ^Stmt,
|
stmt: ^Stmt,
|
||||||
}
|
}
|
||||||
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
|
|||||||
Assign_Stmt :: struct {
|
Assign_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
lhs: []^Expr,
|
lhs: []^Expr,
|
||||||
op: token.Token,
|
op: tokenizer.Token,
|
||||||
rhs: []^Expr,
|
rhs: []^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
|
|||||||
Block_Stmt :: struct {
|
Block_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
label: ^Expr,
|
label: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
stmts: []^Stmt,
|
stmts: []^Stmt,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
If_Stmt :: struct {
|
If_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
label: ^Expr,
|
label: ^Expr,
|
||||||
if_pos: token.Pos,
|
if_pos: tokenizer.Pos,
|
||||||
init: ^Stmt,
|
init: ^Stmt,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
@@ -277,7 +278,7 @@ If_Stmt :: struct {
|
|||||||
|
|
||||||
When_Stmt :: struct {
|
When_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
when_pos: token.Pos,
|
when_pos: tokenizer.Pos,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
else_stmt: ^Stmt,
|
else_stmt: ^Stmt,
|
||||||
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
|
|||||||
For_Stmt :: struct {
|
For_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
label: ^Expr,
|
label: ^Expr,
|
||||||
for_pos: token.Pos,
|
for_pos: tokenizer.Pos,
|
||||||
init: ^Stmt,
|
init: ^Stmt,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
post: ^Stmt,
|
post: ^Stmt,
|
||||||
@@ -306,10 +307,10 @@ For_Stmt :: struct {
|
|||||||
Range_Stmt :: struct {
|
Range_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
label: ^Expr,
|
label: ^Expr,
|
||||||
for_pos: token.Pos,
|
for_pos: tokenizer.Pos,
|
||||||
val0: ^Expr,
|
val0: ^Expr,
|
||||||
val1: ^Expr,
|
val1: ^Expr,
|
||||||
in_pos: token.Pos,
|
in_pos: tokenizer.Pos,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
}
|
}
|
||||||
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
|
|||||||
|
|
||||||
Case_Clause :: struct {
|
Case_Clause :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
case_pos: token.Pos,
|
case_pos: tokenizer.Pos,
|
||||||
list: []^Expr,
|
list: []^Expr,
|
||||||
terminator: token.Token,
|
terminator: tokenizer.Token,
|
||||||
body: []^Stmt,
|
body: []^Stmt,
|
||||||
}
|
}
|
||||||
|
|
||||||
Switch_Stmt :: struct {
|
Switch_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
label: ^Expr,
|
label: ^Expr,
|
||||||
switch_pos: token.Pos,
|
switch_pos: tokenizer.Pos,
|
||||||
init: ^Stmt,
|
init: ^Stmt,
|
||||||
cond: ^Expr,
|
cond: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
|
|||||||
Type_Switch_Stmt :: struct {
|
Type_Switch_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
label: ^Expr,
|
label: ^Expr,
|
||||||
switch_pos: token.Pos,
|
switch_pos: tokenizer.Pos,
|
||||||
tag: ^Stmt,
|
tag: ^Stmt,
|
||||||
expr: ^Expr,
|
expr: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
|
|||||||
|
|
||||||
Branch_Stmt :: struct {
|
Branch_Stmt :: struct {
|
||||||
using node: Stmt,
|
using node: Stmt,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
label: ^Ident,
|
label: ^Ident,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +377,7 @@ Value_Decl :: struct {
|
|||||||
Package_Decl :: struct {
|
Package_Decl :: struct {
|
||||||
using node: Decl,
|
using node: Decl,
|
||||||
docs: ^Comment_Group,
|
docs: ^Comment_Group,
|
||||||
token: token.Token,
|
token: tokenizer.Token,
|
||||||
name: string,
|
name: string,
|
||||||
comment: ^Comment_Group,
|
comment: ^Comment_Group,
|
||||||
}
|
}
|
||||||
@@ -385,9 +386,9 @@ Import_Decl :: struct {
|
|||||||
using node: Decl,
|
using node: Decl,
|
||||||
docs: ^Comment_Group,
|
docs: ^Comment_Group,
|
||||||
is_using: bool,
|
is_using: bool,
|
||||||
import_tok: token.Token,
|
import_tok: tokenizer.Token,
|
||||||
name: token.Token,
|
name: tokenizer.Token,
|
||||||
relpath: token.Token,
|
relpath: tokenizer.Token,
|
||||||
fullpath: string,
|
fullpath: string,
|
||||||
comment: ^Comment_Group,
|
comment: ^Comment_Group,
|
||||||
}
|
}
|
||||||
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
|
|||||||
using node: Decl,
|
using node: Decl,
|
||||||
docs: ^Comment_Group,
|
docs: ^Comment_Group,
|
||||||
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
|
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
foreign_library: ^Expr,
|
foreign_library: ^Expr,
|
||||||
body: ^Stmt,
|
body: ^Stmt,
|
||||||
}
|
}
|
||||||
@@ -404,8 +405,8 @@ Foreign_Block_Decl :: struct {
|
|||||||
Foreign_Import_Decl :: struct {
|
Foreign_Import_Decl :: struct {
|
||||||
using node: Decl,
|
using node: Decl,
|
||||||
docs: ^Comment_Group,
|
docs: ^Comment_Group,
|
||||||
foreign_tok: token.Token,
|
foreign_tok: tokenizer.Token,
|
||||||
import_tok: token.Token,
|
import_tok: tokenizer.Token,
|
||||||
name: ^Ident,
|
name: ^Ident,
|
||||||
collection_name: string,
|
collection_name: string,
|
||||||
fullpaths: []string,
|
fullpaths: []string,
|
||||||
@@ -435,7 +436,9 @@ Field_Flag :: enum {
|
|||||||
C_Vararg,
|
C_Vararg,
|
||||||
Auto_Cast,
|
Auto_Cast,
|
||||||
In,
|
In,
|
||||||
|
|
||||||
Results,
|
Results,
|
||||||
|
Tags,
|
||||||
Default_Parameters,
|
Default_Parameters,
|
||||||
Typeid_Token,
|
Typeid_Token,
|
||||||
}
|
}
|
||||||
@@ -443,18 +446,19 @@ Field_Flag :: enum {
|
|||||||
Field_Flags :: distinct bit_set[Field_Flag];
|
Field_Flags :: distinct bit_set[Field_Flag];
|
||||||
|
|
||||||
Field_Flags_Struct :: Field_Flags{
|
Field_Flags_Struct :: Field_Flags{
|
||||||
Field_Flag.Using,
|
.Using,
|
||||||
|
.Tags,
|
||||||
};
|
};
|
||||||
Field_Flags_Record_Poly_Params :: Field_Flags{
|
Field_Flags_Record_Poly_Params :: Field_Flags{
|
||||||
Field_Flag.Typeid_Token,
|
.Typeid_Token,
|
||||||
};
|
};
|
||||||
Field_Flags_Signature :: Field_Flags{
|
Field_Flags_Signature :: Field_Flags{
|
||||||
Field_Flag.Ellipsis,
|
.Ellipsis,
|
||||||
Field_Flag.Using,
|
.Using,
|
||||||
Field_Flag.No_Alias,
|
.No_Alias,
|
||||||
Field_Flag.C_Vararg,
|
.C_Vararg,
|
||||||
Field_Flag.Auto_Cast,
|
.Auto_Cast,
|
||||||
Field_Flag.Default_Parameters,
|
.Default_Parameters,
|
||||||
};
|
};
|
||||||
|
|
||||||
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
|
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
|
||||||
@@ -463,18 +467,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
|
|||||||
|
|
||||||
Proc_Group :: struct {
|
Proc_Group :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
args: []^Expr,
|
args: []^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Attribute :: struct {
|
Attribute :: struct {
|
||||||
using node: Node,
|
using node: Node,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
elems: []^Expr,
|
elems: []^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Field :: struct {
|
Field :: struct {
|
||||||
@@ -483,56 +487,57 @@ Field :: struct {
|
|||||||
names: []^Expr, // Could be polymorphic
|
names: []^Expr, // Could be polymorphic
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
default_value: ^Expr,
|
default_value: ^Expr,
|
||||||
|
tag: tokenizer.Token,
|
||||||
flags: Field_Flags,
|
flags: Field_Flags,
|
||||||
comment: ^Comment_Group,
|
comment: ^Comment_Group,
|
||||||
}
|
}
|
||||||
|
|
||||||
Field_List :: struct {
|
Field_List :: struct {
|
||||||
using node: Node,
|
using node: Node,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
list: []^Field,
|
list: []^Field,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
Typeid_Type :: struct {
|
Typeid_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
specialization: ^Expr,
|
specialization: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Helper_Type :: struct {
|
Helper_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Distinct_Type :: struct {
|
Distinct_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Opaque_Type :: struct {
|
Opaque_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Kind,
|
tok: tokenizer.Token_Kind,
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Poly_Type :: struct {
|
Poly_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
dollar: token.Pos,
|
dollar: tokenizer.Pos,
|
||||||
type: ^Ident,
|
type: ^Ident,
|
||||||
specialization: ^Expr,
|
specialization: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Proc_Type :: struct {
|
Proc_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok: token.Token,
|
tok: tokenizer.Token,
|
||||||
calling_convention: Proc_Calling_Convention,
|
calling_convention: Proc_Calling_Convention,
|
||||||
params: ^Field_List,
|
params: ^Field_List,
|
||||||
arrow: token.Pos,
|
arrow: tokenizer.Pos,
|
||||||
results: ^Field_List,
|
results: ^Field_List,
|
||||||
tags: Proc_Tags,
|
tags: Proc_Tags,
|
||||||
generic: bool,
|
generic: bool,
|
||||||
@@ -541,77 +546,81 @@ Proc_Type :: struct {
|
|||||||
|
|
||||||
Pointer_Type :: struct {
|
Pointer_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
pointer: token.Pos,
|
pointer: tokenizer.Pos,
|
||||||
elem: ^Expr,
|
elem: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Array_Type :: struct {
|
Array_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
|
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
elem: ^Expr,
|
elem: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynamic_Array_Type :: struct {
|
Dynamic_Array_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
dynamic_pos: token.Pos,
|
dynamic_pos: tokenizer.Pos,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
elem: ^Expr,
|
elem: ^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct_Type :: struct {
|
Struct_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: token.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
poly_params: ^Field_List,
|
poly_params: ^Field_List,
|
||||||
align: ^Expr,
|
align: ^Expr,
|
||||||
is_packed: bool,
|
|
||||||
is_raw_union: bool,
|
|
||||||
fields: ^Field_List,
|
fields: ^Field_List,
|
||||||
name_count: int,
|
name_count: int,
|
||||||
|
where_token: tokenizer.Token,
|
||||||
|
where_clauses: []^Expr,
|
||||||
|
is_packed: bool,
|
||||||
|
is_raw_union: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
Union_Type :: struct {
|
Union_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: token.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
poly_params: ^Field_List,
|
poly_params: ^Field_List,
|
||||||
align: ^Expr,
|
align: ^Expr,
|
||||||
variants: []^Expr,
|
variants: []^Expr,
|
||||||
|
where_token: tokenizer.Token,
|
||||||
|
where_clauses: []^Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Enum_Type :: struct {
|
Enum_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: token.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
base_type: ^Expr,
|
base_type: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
fields: []^Expr,
|
fields: []^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
|
|
||||||
is_using: bool,
|
is_using: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bit_Field_Type :: struct {
|
Bit_Field_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: token.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
align: ^Expr,
|
align: ^Expr,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
fields: []^Field_Value, // Field_Value with ':' rather than '='
|
fields: []^Field_Value, // Field_Value with ':' rather than '='
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Bit_Set_Type :: struct {
|
Bit_Set_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: token.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
open: token.Pos,
|
open: tokenizer.Pos,
|
||||||
elem: ^Expr,
|
elem: ^Expr,
|
||||||
underlying: ^Expr,
|
underlying: ^Expr,
|
||||||
close: token.Pos,
|
close: tokenizer.Pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
Map_Type :: struct {
|
Map_Type :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
tok_pos: token.Pos,
|
tok_pos: tokenizer.Pos,
|
||||||
key: ^Expr,
|
key: ^Expr,
|
||||||
value: ^Expr,
|
value: ^Expr,
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,9 @@ package odin_ast
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:fmt"
|
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 := mem.new(T);
|
||||||
n.pos = pos;
|
n.pos = pos;
|
||||||
n.end = end;
|
n.end = end;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package odin_ast
|
package odin_ast
|
||||||
|
|
||||||
import "core:odin/token"
|
import "core:odin/tokenizer"
|
||||||
|
|
||||||
Package_Kind :: enum {
|
Package_Kind :: enum {
|
||||||
Normal,
|
Normal,
|
||||||
@@ -26,7 +26,7 @@ File :: struct {
|
|||||||
src: []byte,
|
src: []byte,
|
||||||
|
|
||||||
pkg_decl: ^Package_Decl,
|
pkg_decl: ^Package_Decl,
|
||||||
pkg_token: token.Token,
|
pkg_token: tokenizer.Token,
|
||||||
pkg_name: string,
|
pkg_name: string,
|
||||||
|
|
||||||
decls: [dynamic]^Stmt,
|
decls: [dynamic]^Stmt,
|
||||||
|
|||||||
+439
-385
File diff suppressed because it is too large.
Load diff
@@ -1,9 +1,9 @@
|
|||||||
package odin_token
|
package odin_tokenizer
|
||||||
|
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
Token :: struct {
|
Token :: struct {
|
||||||
kind: Kind,
|
kind: Token_Kind,
|
||||||
text: string,
|
text: string,
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
|
|||||||
return strings.compare(lhs.file, rhs.file);
|
return strings.compare(lhs.file, rhs.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
using Kind :: enum u32 {
|
Token_Kind :: enum u32 {
|
||||||
Invalid,
|
Invalid,
|
||||||
EOF,
|
EOF,
|
||||||
Comment,
|
Comment,
|
||||||
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
|
|||||||
Package,
|
Package,
|
||||||
Typeid,
|
Typeid,
|
||||||
When,
|
When,
|
||||||
|
Where,
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
For,
|
For,
|
||||||
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
|
|||||||
Offset_Of,
|
Offset_Of,
|
||||||
Type_Of,
|
Type_Of,
|
||||||
Const,
|
Const,
|
||||||
Asm,
|
|
||||||
Yield,
|
|
||||||
Await,
|
|
||||||
B_Keyword_End,
|
B_Keyword_End,
|
||||||
|
|
||||||
COUNT,
|
COUNT,
|
||||||
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
|
|||||||
// ... Custom keywords
|
// ... Custom keywords
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens := [Kind.COUNT]string {
|
tokens := [Token_Kind.COUNT]string {
|
||||||
"Invalid",
|
"Invalid",
|
||||||
"EOF",
|
"EOF",
|
||||||
"Comment",
|
"Comment",
|
||||||
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
|
|||||||
"package",
|
"package",
|
||||||
"typeid",
|
"typeid",
|
||||||
"when",
|
"when",
|
||||||
|
"where",
|
||||||
"if",
|
"if",
|
||||||
"else",
|
"else",
|
||||||
"for",
|
"for",
|
||||||
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
|
|||||||
"offset_of",
|
"offset_of",
|
||||||
"type_of",
|
"type_of",
|
||||||
"const",
|
"const",
|
||||||
"asm",
|
|
||||||
"yield",
|
|
||||||
"await",
|
|
||||||
"",
|
"",
|
||||||
};
|
};
|
||||||
|
|
||||||
custom_keyword_tokens: []string;
|
custom_keyword_tokens: []string;
|
||||||
|
|
||||||
to_string :: proc(kind: Kind) -> string {
|
to_string :: proc(kind: Token_Kind) -> string {
|
||||||
if Invalid <= kind && kind < COUNT {
|
if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
|
||||||
return tokens[kind];
|
return tokens[kind];
|
||||||
}
|
}
|
||||||
if B_Custom_Keyword_Begin < kind {
|
if Token_Kind.B_Custom_Keyword_Begin < kind {
|
||||||
n := int(u16(kind)-u16(B_Custom_Keyword_Begin));
|
n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
|
||||||
if n < len(custom_keyword_tokens) {
|
if n < len(custom_keyword_tokens) {
|
||||||
return custom_keyword_tokens[n];
|
return custom_keyword_tokens[n];
|
||||||
}
|
}
|
||||||
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
|
|||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; }
|
is_literal :: proc(kind: Token_Kind) -> bool {
|
||||||
is_operator :: proc(kind: Kind) -> bool {
|
return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
|
||||||
|
}
|
||||||
|
is_operator :: proc(kind: Token_Kind) -> bool {
|
||||||
switch kind {
|
switch kind {
|
||||||
case B_Operator_Begin..B_Operator_End:
|
case .B_Operator_Begin .. .B_Operator_End:
|
||||||
return true;
|
return true;
|
||||||
case In, Notin:
|
case .In, .Notin:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
is_assignment_operator :: proc(kind: Kind) -> bool {
|
is_assignment_operator :: proc(kind: Token_Kind) -> bool {
|
||||||
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
|
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 {
|
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;
|
return true;
|
||||||
case B_Custom_Keyword_Begin < kind:
|
case Token_Kind.B_Custom_Keyword_Begin < kind:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package odin_tokenizer
|
package odin_tokenizer
|
||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:odin/token"
|
|
||||||
import "core:unicode/utf8"
|
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 {
|
Tokenizer :: struct {
|
||||||
// Immutable data
|
// Immutable data
|
||||||
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
|
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
|
||||||
line := t.line_count;
|
line := t.line_count;
|
||||||
column := offset - t.line_offset + 1;
|
column := offset - t.line_offset + 1;
|
||||||
|
|
||||||
return token.Pos {
|
return Pos {
|
||||||
file = t.path,
|
file = t.path,
|
||||||
offset = offset,
|
offset = offset,
|
||||||
line = line,
|
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) {
|
default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
|
||||||
fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column);
|
fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
|
||||||
fmt.printf_err(msg, ..args);
|
fmt.eprintf(msg, ..args);
|
||||||
fmt.printf_err("\n");
|
fmt.eprintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
|
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
|
||||||
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
|
|||||||
return string(t.src[offset : t.offset]);
|
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) {
|
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
|
||||||
for digit_val(t.ch) < base || t.ch == '_' {
|
for digit_val(t.ch) < base || t.ch == '_' {
|
||||||
advance_rune(t);
|
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' {
|
if t.ch == 'e' || t.ch == 'E' {
|
||||||
kind^ = token.Float;
|
kind^ = .Float;
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
if t.ch == '-' || t.ch == '+' {
|
if t.ch == '-' || t.ch == '+' {
|
||||||
advance_rune(t);
|
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
|
// NOTE(bill): This needs to be here for sanity's sake
|
||||||
if t.ch == 'i' {
|
switch t.ch {
|
||||||
kind^ = token.Imag;
|
case 'i', 'j', 'k':
|
||||||
|
kind^ = .Imag;
|
||||||
advance_rune(t);
|
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) == '.' {
|
if t.ch == '.' && peek_byte(t) == '.' {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if t.ch == '.' {
|
if t.ch == '.' {
|
||||||
kind^ = token.Float;
|
kind^ = .Float;
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
}
|
}
|
||||||
@@ -362,22 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
|||||||
|
|
||||||
|
|
||||||
offset := t.offset;
|
offset := t.offset;
|
||||||
kind := token.Integer;
|
kind := Token_Kind.Integer;
|
||||||
seen_point := seen_decimal_point;
|
seen_point := seen_decimal_point;
|
||||||
|
|
||||||
if seen_point {
|
if seen_point {
|
||||||
offset -= 1;
|
offset -= 1;
|
||||||
kind = token.Float;
|
kind = .Float;
|
||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
scan_exponent(t, &kind);
|
scan_exponent(t, &kind);
|
||||||
} else {
|
} else {
|
||||||
if t.ch == '0' {
|
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;
|
prev := t.offset;
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
scan_mantissa(t, base);
|
scan_mantissa(t, base);
|
||||||
if t.offset - prev <= 1 {
|
if t.offset - prev <= 1 {
|
||||||
kind^ = token.Invalid;
|
kind^ = .Invalid;
|
||||||
error(t, t.offset, msg);
|
error(t, t.offset, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
|||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
scan_mantissa(t, 16);
|
scan_mantissa(t, 16);
|
||||||
if t.offset - prev <= 1 {
|
if t.offset - prev <= 1 {
|
||||||
kind = token.Invalid;
|
kind = .Invalid;
|
||||||
error(t, t.offset, "illegal hexadecimal floating-point number");
|
error(t, t.offset, "illegal hexadecimal floating-point number");
|
||||||
} else {
|
} else {
|
||||||
sub := t.src[prev+1 : t.offset];
|
sub := t.src[prev+1 : t.offset];
|
||||||
@@ -439,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
scan :: proc(t: ^Tokenizer) -> token.Token {
|
scan :: proc(t: ^Tokenizer) -> Token {
|
||||||
switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind {
|
switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind {
|
||||||
if t.ch == '=' {
|
if t.ch == '=' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
return tok1;
|
return tok1;
|
||||||
}
|
}
|
||||||
return tok0;
|
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 == '=' {
|
if t.ch == '=' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
return tok1;
|
return tok1;
|
||||||
@@ -458,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
|||||||
}
|
}
|
||||||
return tok0;
|
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 == '=' {
|
if t.ch == '=' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
return tok1;
|
return tok1;
|
||||||
@@ -479,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
|||||||
|
|
||||||
offset := t.offset;
|
offset := t.offset;
|
||||||
|
|
||||||
kind: token.Kind;
|
kind: Token_Kind;
|
||||||
lit: string;
|
lit: string;
|
||||||
pos := offset_to_pos(t, offset);
|
pos := offset_to_pos(t, offset);
|
||||||
|
|
||||||
switch ch := t.ch; true {
|
switch ch := t.ch; true {
|
||||||
case is_letter(ch):
|
case is_letter(ch):
|
||||||
lit = scan_identifier(t);
|
lit = scan_identifier(t);
|
||||||
kind = token.Ident;
|
kind = .Ident;
|
||||||
check_keyword: if len(lit) > 1 {
|
check_keyword: if len(lit) > 1 {
|
||||||
// TODO(bill): Maybe have a hash table lookup rather than this linear search
|
// TODO(bill): Maybe have a hash table lookup rather than this linear search
|
||||||
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
|
for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End {
|
||||||
if lit == token.tokens[i] {
|
if lit == tokens[i] {
|
||||||
kind = token.Kind(i);
|
kind = Token_Kind(i);
|
||||||
break check_keyword;
|
break check_keyword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for keyword, i in token.custom_keyword_tokens {
|
for keyword, i in custom_keyword_tokens {
|
||||||
if lit == keyword {
|
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;
|
break check_keyword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
|||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
switch ch {
|
switch ch {
|
||||||
case -1:
|
case -1:
|
||||||
kind = token.EOF;
|
kind = .EOF;
|
||||||
case '"':
|
case '"':
|
||||||
kind = token.String;
|
kind = .String;
|
||||||
lit = scan_string(t);
|
lit = scan_string(t);
|
||||||
case '\'':
|
case '\'':
|
||||||
kind = token.Rune;
|
kind = .Rune;
|
||||||
lit = scan_rune(t);
|
lit = scan_rune(t);
|
||||||
case '`':
|
case '`':
|
||||||
kind = token.String;
|
kind = .String;
|
||||||
lit = scan_raw_string(t);
|
lit = scan_raw_string(t);
|
||||||
case '=':
|
case '=':
|
||||||
if t.ch == '>' {
|
if t.ch == '>' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = token.Double_Arrow_Right;
|
kind = .Double_Arrow_Right;
|
||||||
} else {
|
} 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 '#':
|
case '#':
|
||||||
kind = token.Hash;
|
kind = .Hash;
|
||||||
if t.ch == '!' {
|
if t.ch == '!' {
|
||||||
kind = token.Comment;
|
kind = .Comment;
|
||||||
lit = scan_comment(t);
|
lit = scan_comment(t);
|
||||||
}
|
}
|
||||||
case '?': kind = token.Question;
|
case '?': kind = .Question;
|
||||||
case '@': kind = token.At;
|
case '@': kind = .At;
|
||||||
case '$': kind = token.Dollar;
|
case '$': kind = .Dollar;
|
||||||
case '^': kind = token.Pointer;
|
case '^': kind = .Pointer;
|
||||||
case '+': kind = switch2(t, token.Add, token.Add_Eq);
|
case '+': kind = switch2(t, .Add, .Add_Eq);
|
||||||
case '-':
|
case '-':
|
||||||
if t.ch == '>' {
|
if t.ch == '>' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = token.Arrow_Right;
|
kind = .Arrow_Right;
|
||||||
} else if t.ch == '-' && peek_byte(t) == '-' {
|
} else if t.ch == '-' && peek_byte(t) == '-' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = token.Undef;
|
kind = .Undef;
|
||||||
} else {
|
} 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 '/':
|
case '/':
|
||||||
if t.ch == '/' || t.ch == '*' {
|
if t.ch == '/' || t.ch == '*' {
|
||||||
kind = token.Comment;
|
kind = .Comment;
|
||||||
lit = scan_comment(t);
|
lit = scan_comment(t);
|
||||||
} else {
|
} 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 '&':
|
case '&':
|
||||||
if t.ch == '~' {
|
if t.ch == '~' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = switch2(t, token.And_Not, token.And_Not_Eq);
|
kind = switch2(t, .And_Not, .And_Not_Eq);
|
||||||
} else {
|
} 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 = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
|
||||||
case '~': kind = token.Xor;
|
case '~': kind = .Xor;
|
||||||
case '<':
|
case '<':
|
||||||
if t.ch == '-' {
|
if t.ch == '-' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = token.Arrow_Left;
|
kind = .Arrow_Left;
|
||||||
} else {
|
} 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 = .Not_Eq;
|
||||||
case '≤': kind = token.Lt_Eq;
|
case '≤': kind = .Lt_Eq;
|
||||||
case '≥': kind = token.Gt_Eq;
|
case '≥': kind = .Gt_Eq;
|
||||||
case '∈': kind = token.In;
|
case '∈': kind = .In;
|
||||||
case '∉': kind = token.Notin;
|
case '∉': kind = .Notin;
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
if '0' <= t.ch && t.ch <= '9' {
|
if '0' <= t.ch && t.ch <= '9' {
|
||||||
kind, lit = scan_number(t, true);
|
kind, lit = scan_number(t, true);
|
||||||
} else {
|
} else {
|
||||||
kind = token.Period;
|
kind = .Period;
|
||||||
if t.ch == '.' {
|
if t.ch == '.' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = token.Ellipsis;
|
kind = .Ellipsis;
|
||||||
if t.ch == '<' {
|
if t.ch == '<' {
|
||||||
advance_rune(t);
|
advance_rune(t);
|
||||||
kind = token.Range_Half;
|
kind = .Range_Half;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ':': kind = token.Colon;
|
case ':': kind = .Colon;
|
||||||
case ',': kind = token.Comma;
|
case ',': kind = .Comma;
|
||||||
case ';': kind = token.Semicolon;
|
case ';': kind = .Semicolon;
|
||||||
case '(': kind = token.Open_Paren;
|
case '(': kind = .Open_Paren;
|
||||||
case ')': kind = token.Close_Paren;
|
case ')': kind = .Close_Paren;
|
||||||
case '[': kind = token.Open_Bracket;
|
case '[': kind = .Open_Bracket;
|
||||||
case ']': kind = token.Close_Bracket;
|
case ']': kind = .Close_Bracket;
|
||||||
case '{': kind = token.Open_Brace;
|
case '{': kind = .Open_Brace;
|
||||||
case '}': kind = token.Close_Brace;
|
case '}': kind = .Close_Brace;
|
||||||
|
|
||||||
case '\\': kind = token.Back_Slash;
|
case '\\': kind = .Back_Slash;
|
||||||
|
|
||||||
case:
|
case:
|
||||||
if ch != utf8.RUNE_BOM {
|
if ch != utf8.RUNE_BOM {
|
||||||
error(t, t.offset, "illegal character '%r': %d", ch, ch);
|
error(t, t.offset, "illegal character '%r': %d", ch, ch);
|
||||||
}
|
}
|
||||||
kind = token.Invalid;
|
kind = .Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if lit == "" {
|
if lit == "" {
|
||||||
lit = string(t.src[offset : t.offset]);
|
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:runtime"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
OS :: "osx";
|
OS :: "darwin";
|
||||||
|
|
||||||
Handle :: distinct i32;
|
Handle :: distinct i32;
|
||||||
File_Time :: distinct u64;
|
File_Time :: distinct u64;
|
||||||
@@ -319,9 +319,9 @@ dlerror :: proc() -> string {
|
|||||||
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: 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__ {
|
for arg, i in runtime.args__ {
|
||||||
args[i] = string(arg);
|
res[i] = string(arg);
|
||||||
}
|
}
|
||||||
return args;
|
return res;
|
||||||
}
|
}
|
||||||
+2420
-160
File diff suppressed because it is too large.
Load diff
@@ -392,9 +392,9 @@ dlerror :: proc() -> string {
|
|||||||
|
|
||||||
|
|
||||||
_alloc_command_line_arguments :: 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__ {
|
for arg, i in runtime.args__ {
|
||||||
args[i] = string(arg);
|
res[i] = string(arg);
|
||||||
}
|
}
|
||||||
return args;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -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 rt "core:runtime"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||||
if a == b do return true;
|
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 {
|
for _, i in x.types {
|
||||||
xn, yn := x.names[i], y.names[i];
|
xn, yn := x.names[i], y.names[i];
|
||||||
xt, yt := x.types[i], y.types[i];
|
xt, yt := x.types[i], y.types[i];
|
||||||
|
xl, yl := x.tags[i], y.tags[i];
|
||||||
|
|
||||||
if xn != yn do return false;
|
if xn != yn do return false;
|
||||||
if !are_types_identical(xt, yt) do return false;
|
if !are_types_identical(xt, yt) do return false;
|
||||||
|
if xl != yl do return false;
|
||||||
}
|
}
|
||||||
return true;
|
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);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
|
||||||
return ok;
|
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, ')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+83
-60
@@ -6,6 +6,7 @@ package runtime
|
|||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
import "intrinsics"
|
||||||
|
|
||||||
// Naming Conventions:
|
// Naming Conventions:
|
||||||
// In general, Ada_Case for types and snake_case for values
|
// In general, Ada_Case for types and snake_case for values
|
||||||
@@ -40,7 +41,7 @@ Type_Info_Enum_Value :: union {
|
|||||||
u8, u16, u32, u64, uint, uintptr,
|
u8, u16, u32, u64, uint, uintptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type_Info_Endianness :: enum u8 {
|
Platform_Endianness :: enum u8 {
|
||||||
Platform = 0,
|
Platform = 0,
|
||||||
Little = 1,
|
Little = 1,
|
||||||
Big = 2,
|
Big = 2,
|
||||||
@@ -48,10 +49,11 @@ Type_Info_Endianness :: enum u8 {
|
|||||||
|
|
||||||
// Variant Types
|
// Variant Types
|
||||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||||
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
|
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
|
||||||
Type_Info_Rune :: struct {};
|
Type_Info_Rune :: struct {};
|
||||||
Type_Info_Float :: struct {};
|
Type_Info_Float :: struct {};
|
||||||
Type_Info_Complex :: struct {};
|
Type_Info_Complex :: struct {};
|
||||||
|
Type_Info_Quaternion :: struct {};
|
||||||
Type_Info_String :: struct {is_cstring: bool};
|
Type_Info_String :: struct {is_cstring: bool};
|
||||||
Type_Info_Boolean :: struct {};
|
Type_Info_Boolean :: struct {};
|
||||||
Type_Info_Any :: struct {};
|
Type_Info_Any :: struct {};
|
||||||
@@ -79,8 +81,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
|
|||||||
Type_Info_Struct :: struct {
|
Type_Info_Struct :: struct {
|
||||||
types: []^Type_Info,
|
types: []^Type_Info,
|
||||||
names: []string,
|
names: []string,
|
||||||
offsets: []uintptr, // offsets may not be used in tuples
|
offsets: []uintptr,
|
||||||
usings: []bool, // usings may not be used in tuples
|
usings: []bool,
|
||||||
|
tags: []string,
|
||||||
is_packed: bool,
|
is_packed: bool,
|
||||||
is_raw_union: bool,
|
is_raw_union: bool,
|
||||||
custom_align: bool,
|
custom_align: bool,
|
||||||
@@ -134,6 +137,7 @@ Type_Info :: struct {
|
|||||||
Type_Info_Rune,
|
Type_Info_Rune,
|
||||||
Type_Info_Float,
|
Type_Info_Float,
|
||||||
Type_Info_Complex,
|
Type_Info_Complex,
|
||||||
|
Type_Info_Quaternion,
|
||||||
Type_Info_String,
|
Type_Info_String,
|
||||||
Type_Info_Boolean,
|
Type_Info_Boolean,
|
||||||
Type_Info_Any,
|
Type_Info_Any,
|
||||||
@@ -162,6 +166,7 @@ Typeid_Kind :: enum u8 {
|
|||||||
Rune,
|
Rune,
|
||||||
Float,
|
Float,
|
||||||
Complex,
|
Complex,
|
||||||
|
Quaternion,
|
||||||
String,
|
String,
|
||||||
Boolean,
|
Boolean,
|
||||||
Any,
|
Any,
|
||||||
@@ -183,12 +188,13 @@ Typeid_Kind :: enum u8 {
|
|||||||
#assert(len(Typeid_Kind) < 32);
|
#assert(len(Typeid_Kind) < 32);
|
||||||
|
|
||||||
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
||||||
index: 8*size_of(align_of(uintptr)) - 8,
|
index: 8*size_of(uintptr) - 8,
|
||||||
kind: 5, // Typeid_Kind
|
kind: 5, // Typeid_Kind
|
||||||
named: 1,
|
named: 1,
|
||||||
special: 1, // signed, cstring, etc
|
special: 1, // signed, cstring, etc
|
||||||
reserved: 1,
|
reserved: 1,
|
||||||
}
|
}
|
||||||
|
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
|
||||||
|
|
||||||
// NOTE(bill): only the ones that are needed (not all types)
|
// NOTE(bill): only the ones that are needed (not all types)
|
||||||
// This will be set by the compiler
|
// This will be set by the compiler
|
||||||
@@ -231,7 +237,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;
|
INITIAL_MAP_CAP :: 16;
|
||||||
|
|
||||||
@@ -255,7 +276,7 @@ Map_Entry_Header :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map_Header :: struct {
|
Map_Header :: struct {
|
||||||
m: ^mem.Raw_Map,
|
m: ^Raw_Map,
|
||||||
is_key_string: bool,
|
is_key_string: bool,
|
||||||
|
|
||||||
entry_size: int,
|
entry_size: int,
|
||||||
@@ -282,7 +303,7 @@ 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;
|
if info == nil do return nil;
|
||||||
|
|
||||||
base := info;
|
base := info;
|
||||||
@@ -290,11 +311,13 @@ type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_In
|
|||||||
switch i in base.variant {
|
switch i in base.variant {
|
||||||
case Type_Info_Named: base = i.base;
|
case Type_Info_Named: base = i.base;
|
||||||
case Type_Info_Enum: base = i.base;
|
case Type_Info_Enum: base = i.base;
|
||||||
|
case Type_Info_Opaque: base = i.elem;
|
||||||
case: break loop;
|
case: break loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
type_info_base_without_enum :: type_info_core;
|
||||||
|
|
||||||
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
|
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
|
||||||
data := transmute(Typeid_Bit_Field)id;
|
data := transmute(Typeid_Bit_Field)id;
|
||||||
@@ -310,10 +333,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
|||||||
ti = type_info_base(ti);
|
ti = type_info_base(ti);
|
||||||
return ti.id;
|
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));
|
ti := type_info_base_without_enum(type_info_of(id));
|
||||||
return ti.id;
|
return ti.id;
|
||||||
}
|
}
|
||||||
|
typeid_base_without_enum :: typeid_core;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -385,7 +409,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
|
|||||||
@builtin
|
@builtin
|
||||||
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||||
n := max(0, min(len(dst), len(src)));
|
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;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +420,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
|||||||
if array == nil do return E{};
|
if array == nil do return E{};
|
||||||
assert(len(array) > 0);
|
assert(len(array) > 0);
|
||||||
res := array[len(array)-1];
|
res := array[len(array)-1];
|
||||||
(^mem.Raw_Dynamic_Array)(array).len -= 1;
|
(^Raw_Dynamic_Array)(array).len -= 1;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,14 +484,11 @@ make :: proc{
|
|||||||
mem.make_map,
|
mem.make_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
||||||
if m == nil do return;
|
if m == nil do return;
|
||||||
raw_map := (^mem.Raw_Map)(m);
|
raw_map := (^Raw_Map)(m);
|
||||||
entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
|
entries := (^Raw_Dynamic_Array)(&raw_map.entries);
|
||||||
entries.len = 0;
|
entries.len = 0;
|
||||||
for _, i in raw_map.hashes {
|
for _, i in raw_map.hashes {
|
||||||
raw_map.hashes[i] = -1;
|
raw_map.hashes[i] = -1;
|
||||||
@@ -498,11 +519,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
|
|||||||
}
|
}
|
||||||
arg_len = min(cap(array)-len(array), arg_len);
|
arg_len = min(cap(array)-len(array), arg_len);
|
||||||
if arg_len > 0 {
|
if arg_len > 0 {
|
||||||
a := (^mem.Raw_Dynamic_Array)(array);
|
a := (^Raw_Dynamic_Array)(array);
|
||||||
data := (^E)(a.data);
|
data := (^E)(a.data);
|
||||||
assert(data != nil);
|
assert(data != nil);
|
||||||
val := arg;
|
val := arg;
|
||||||
mem.copy(mem.ptr_offset(data, a.len), &val, size_of(E));
|
mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E));
|
||||||
a.len += arg_len;
|
a.len += arg_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,10 +541,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
|
|||||||
}
|
}
|
||||||
arg_len = min(cap(array)-len(array), arg_len);
|
arg_len = min(cap(array)-len(array), arg_len);
|
||||||
if arg_len > 0 {
|
if arg_len > 0 {
|
||||||
a := (^mem.Raw_Dynamic_Array)(array);
|
a := (^Raw_Dynamic_Array)(array);
|
||||||
data := (^E)(a.data);
|
data := (^E)(a.data);
|
||||||
assert(data != nil);
|
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;
|
a.len += arg_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -540,13 +561,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
|
|||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
|
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
|
@builtin
|
||||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||||
if array == nil do return false;
|
if array == nil do return false;
|
||||||
a := (^mem.Raw_Dynamic_Array)(array);
|
a := (^Raw_Dynamic_Array)(array);
|
||||||
|
|
||||||
if capacity <= a.cap do return true;
|
if capacity <= a.cap do return true;
|
||||||
|
|
||||||
@@ -573,7 +594,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
|
|||||||
@builtin
|
@builtin
|
||||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
|
||||||
if array == nil do return false;
|
if array == nil do return false;
|
||||||
a := (^mem.Raw_Dynamic_Array)(array);
|
a := (^Raw_Dynamic_Array)(array);
|
||||||
|
|
||||||
if length <= a.cap {
|
if length <= a.cap {
|
||||||
a.len = max(length, 0);
|
a.len = max(length, 0);
|
||||||
@@ -666,11 +687,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
|
|||||||
@builtin
|
@builtin
|
||||||
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
|
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
|
||||||
if !condition {
|
if !condition {
|
||||||
|
proc(message: string, loc: Source_Code_Location) {
|
||||||
p := context.assertion_failure_proc;
|
p := context.assertion_failure_proc;
|
||||||
if p == nil {
|
if p == nil {
|
||||||
p = default_assertion_failure_proc;
|
p = default_assertion_failure_proc;
|
||||||
}
|
}
|
||||||
p("Runtime assertion", message, loc);
|
p("runtime assertion", message, loc);
|
||||||
|
}(message, loc);
|
||||||
}
|
}
|
||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
@@ -681,7 +704,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
|
|||||||
if p == nil {
|
if p == nil {
|
||||||
p = default_assertion_failure_proc;
|
p = default_assertion_failure_proc;
|
||||||
}
|
}
|
||||||
p("Panic", message, loc);
|
p("panic", message, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
@@ -711,7 +734,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! {
|
|||||||
|
|
||||||
|
|
||||||
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, 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;
|
array.allocator = context.allocator;
|
||||||
assert(array.allocator.procedure != nil);
|
assert(array.allocator.procedure != nil);
|
||||||
|
|
||||||
@@ -722,7 +745,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 {
|
__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;
|
if cap <= array.cap do return true;
|
||||||
|
|
||||||
@@ -744,7 +767,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 {
|
__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);
|
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
|
||||||
if ok do array.len = len;
|
if ok do array.len = len;
|
||||||
@@ -754,7 +777,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
|
|||||||
|
|
||||||
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||||
items: rawptr, item_count: int, loc := #caller_location) -> 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 items == nil do return 0;
|
||||||
if item_count <= 0 do return 0;
|
if item_count <= 0 do return 0;
|
||||||
@@ -771,13 +794,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
|||||||
assert(array.data != nil);
|
assert(array.data != nil);
|
||||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
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;
|
array.len += item_count;
|
||||||
return array.len;
|
return array.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
|
__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;
|
ok := true;
|
||||||
if array.cap <= array.len+1 {
|
if array.cap <= array.len+1 {
|
||||||
@@ -800,15 +823,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
|||||||
// Map
|
// Map
|
||||||
|
|
||||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
__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 {
|
Entry :: struct {
|
||||||
key: Map_Key,
|
key: Map_Key,
|
||||||
next: int,
|
next: int,
|
||||||
value: V,
|
value: V,
|
||||||
}
|
};
|
||||||
|
|
||||||
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
|
header.is_key_string = intrinsics.type_is_string(K);
|
||||||
header.is_key_string = is_string;
|
|
||||||
header.entry_size = int(size_of(Entry));
|
header.entry_size = int(size_of(Entry));
|
||||||
header.entry_align = int(align_of(Entry));
|
header.entry_align = int(align_of(Entry));
|
||||||
header.value_offset = uintptr(offset_of(Entry, value));
|
header.value_offset = uintptr(offset_of(Entry, value));
|
||||||
@@ -819,33 +841,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
|||||||
__get_map_key :: proc "contextless" (k: $K) -> Map_Key {
|
__get_map_key :: proc "contextless" (k: $K) -> Map_Key {
|
||||||
key := k;
|
key := k;
|
||||||
map_key: Map_Key;
|
map_key: Map_Key;
|
||||||
ti := type_info_base_without_enum(type_info_of(K));
|
|
||||||
switch _ in ti.variant {
|
T :: intrinsics.type_core_type(K);
|
||||||
case Type_Info_Integer:
|
|
||||||
switch 8*size_of(key) {
|
when intrinsics.type_is_integer(T) {
|
||||||
case 8: map_key.hash = u64(( ^u8)(&key)^);
|
sz :: 8*size_of(T);
|
||||||
case 16: map_key.hash = u64(( ^u16)(&key)^);
|
when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
|
||||||
case 32: map_key.hash = u64(( ^u32)(&key)^);
|
else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
|
||||||
case 64: map_key.hash = u64(( ^u64)(&key)^);
|
else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
|
||||||
case: panic("Unhandled integer size");
|
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
|
||||||
}
|
else do #assert(false, "Unhandled integer size");
|
||||||
case Type_Info_Rune:
|
} else when intrinsics.type_is_rune(T) {
|
||||||
map_key.hash = u64((^rune)(&key)^);
|
map_key.hash = u64((^rune)(&key)^);
|
||||||
case Type_Info_Pointer:
|
} else when intrinsics.type_is_pointer(T) {
|
||||||
map_key.hash = u64(uintptr((^rawptr)(&key)^));
|
map_key.hash = u64(uintptr((^rawptr)(&key)^));
|
||||||
case Type_Info_Float:
|
} else when intrinsics.type_is_float(T) {
|
||||||
switch 8*size_of(key) {
|
sz :: 8*size_of(T);
|
||||||
case 32: map_key.hash = u64((^u32)(&key)^);
|
when sz == 32 do map_key.hash = u64((^u32)(&key)^);
|
||||||
case 64: map_key.hash = u64((^u64)(&key)^);
|
else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
|
||||||
case: panic("Unhandled float size");
|
else do #assert(false, "Unhandled float size");
|
||||||
}
|
} else when intrinsics.type_is_string(T) {
|
||||||
case Type_Info_String:
|
#assert(T == string);
|
||||||
str := (^string)(&key)^;
|
str := (^string)(&key)^;
|
||||||
map_key.hash = default_hash_string(str);
|
map_key.hash = default_hash_string(str);
|
||||||
map_key.str = str;
|
map_key.str = str;
|
||||||
case:
|
} else {
|
||||||
panic("Unhandled map key type");
|
#assert(false, "Unhandled map key type");
|
||||||
}
|
}
|
||||||
|
|
||||||
return map_key;
|
return map_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,7 +897,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 {
|
__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;
|
if new_count < array.len do return true;
|
||||||
|
|
||||||
@@ -900,7 +923,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 {
|
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
|
||||||
new_header: Map_Header = header;
|
new_header: Map_Header = header;
|
||||||
nm := mem.Raw_Map{};
|
nm := Raw_Map{};
|
||||||
nm.entries.allocator = m.entries.allocator;
|
nm.entries.allocator = m.entries.allocator;
|
||||||
new_header.m = &nm;
|
new_header.m = &nm;
|
||||||
|
|
||||||
@@ -932,7 +955,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c
|
|||||||
e := __dynamic_map_get_entry(new_header, j);
|
e := __dynamic_map_get_entry(new_header, j);
|
||||||
e.next = fr.entry_index;
|
e.next = fr.entry_index;
|
||||||
ndata := uintptr(e);
|
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);
|
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
|
||||||
}
|
}
|
||||||
@@ -975,7 +998,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca
|
|||||||
e := __dynamic_map_get_entry(h, index);
|
e := __dynamic_map_get_entry(h, index);
|
||||||
e.key = key;
|
e.key = key;
|
||||||
val := (^byte)(uintptr(e) + h.value_offset);
|
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) {
|
if __dynamic_map_full(h) {
|
||||||
@@ -1054,7 +1077,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
|
|||||||
} else {
|
} else {
|
||||||
old := __dynamic_map_get_entry(h, fr.entry_index);
|
old := __dynamic_map_get_entry(h, fr.entry_index);
|
||||||
end := __dynamic_map_get_entry(h, m.entries.len-1);
|
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 {
|
if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
|
||||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
|
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
|
||||||
|
|||||||
+242
-12
@@ -1,9 +1,22 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "core:mem"
|
|
||||||
import "core:os"
|
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, x: u64) {
|
print_u64 :: proc(fd: os.Handle, x: u64) {
|
||||||
digits := "0123456789";
|
digits := "0123456789";
|
||||||
@@ -243,6 +256,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 {
|
string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||||
switch {
|
switch {
|
||||||
case len(a) != len(b): return false;
|
case len(a) != len(b): return false;
|
||||||
@@ -253,7 +338,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string_cmp :: proc "contextless" (a, b: string) -> int {
|
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); }
|
string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
|
||||||
@@ -263,18 +348,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; }
|
string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
|
||||||
|
|
||||||
cstring_len :: proc "contextless" (s: cstring) -> int {
|
cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||||
n := 0;
|
p0 := uintptr((^byte)(s));
|
||||||
for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) {
|
p := p0;
|
||||||
n += 1;
|
for p != 0 && (^byte)(p)^ != 0 {
|
||||||
|
p += 1;
|
||||||
}
|
}
|
||||||
return n;
|
return int(p - p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||||
|
Raw_String :: struct {
|
||||||
|
data: ^byte,
|
||||||
|
len: int,
|
||||||
|
};
|
||||||
if s == nil do return "";
|
if s == nil do return "";
|
||||||
ptr := (^byte)(s);
|
ptr := (^byte)(s);
|
||||||
n := cstring_len(s);
|
n := cstring_len(s);
|
||||||
return transmute(string)mem.Raw_String{ptr, n};
|
return transmute(string)Raw_String{ptr, n};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -285,6 +375,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); }
|
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) {
|
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
|
||||||
@@ -358,8 +453,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
|
|||||||
handle_error(file, line, column, from, to);
|
handle_error(file, line, column, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
|
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) {
|
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
|
||||||
@@ -474,9 +645,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
|
|||||||
r, i := real(x), imag(x);
|
r, i := real(x), imag(x);
|
||||||
return _sqrt_f64(r*r + i*i);
|
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 "contextless" (n, m: complex64) -> complex64 {
|
||||||
quo_complex64 :: proc(n, m: complex64) -> complex64 {
|
|
||||||
e, f: f32;
|
e, f: f32;
|
||||||
|
|
||||||
if abs(real(m)) >= abs(imag(m)) {
|
if abs(real(m)) >= abs(imag(m)) {
|
||||||
@@ -494,7 +672,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
|
|||||||
return complex(e, f);
|
return complex(e, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_complex128 :: proc(n, m: complex128) -> complex128 {
|
quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
|
||||||
e, f: f64;
|
e, f: f64;
|
||||||
|
|
||||||
if abs(real(m)) >= abs(imag(m)) {
|
if abs(real(m)) >= abs(imag(m)) {
|
||||||
@@ -511,3 +689,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
|
|||||||
|
|
||||||
return complex(e, f);
|
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);
|
||||||
|
}
|
||||||
+4
-3
@@ -1,6 +1,7 @@
|
|||||||
package sort
|
package sort
|
||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "intrinsics"
|
||||||
|
|
||||||
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||||
assert(f != nil);
|
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);
|
count := len(array);
|
||||||
|
|
||||||
init_j, last_j := 0, count-1;
|
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(a[i:n], f);
|
||||||
}
|
}
|
||||||
|
|
||||||
quick_sort :: proc(array: $A/[]$T) {
|
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
|
||||||
a := array;
|
a := array;
|
||||||
n := len(a);
|
n := len(a);
|
||||||
if n < 2 do return;
|
if n < 2 do return;
|
||||||
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
|||||||
if M & 1 == 0 do copy(arr2, arr1);
|
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) {
|
merge_slices :: proc(arr1, arr2, out: A) {
|
||||||
N1, N2 := len(arr1), len(arr2);
|
N1, N2 := len(arr1), len(arr2);
|
||||||
i, j := 0, 0;
|
i, j := 0, 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Multiple precision decimal numbers
|
// Multiple precision decimal numbers
|
||||||
// NOTE: This is only for floating point printing and nothing else
|
// NOTE: This is only for floating point printing and nothing else
|
||||||
package decimal
|
package strconv_decimal
|
||||||
|
|
||||||
Decimal :: struct {
|
Decimal :: struct {
|
||||||
digits: [384]byte, // big-endian digits
|
digits: [384]byte, // big-endian digits
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package strconv
|
package strconv
|
||||||
|
|
||||||
using import "core:decimal"
|
using import "decimal"
|
||||||
|
|
||||||
Int_Flag :: enum {
|
Int_Flag :: enum {
|
||||||
Prefix,
|
Prefix,
|
||||||
@@ -105,7 +105,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
|
|||||||
Buffer :: struct {
|
Buffer :: struct {
|
||||||
b: []byte,
|
b: []byte,
|
||||||
n: int,
|
n: int,
|
||||||
}
|
};
|
||||||
|
|
||||||
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
|
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
|
||||||
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
|
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
|
||||||
|
|||||||
@@ -205,7 +205,11 @@ itoa :: proc(buf: []byte, i: int) -> string {
|
|||||||
atoi :: proc(s: string) -> int {
|
atoi :: proc(s: string) -> int {
|
||||||
return parse_int(s);
|
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 {
|
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) {
|
|||||||
reserve(&b.buf, cap);
|
reserve(&b.buf, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset_builder :: proc(b: ^Builder) {
|
||||||
|
clear(&b.buf);
|
||||||
|
}
|
||||||
|
|
||||||
builder_from_slice :: proc(backing: []byte) -> Builder {
|
builder_from_slice :: proc(backing: []byte) -> Builder {
|
||||||
s := transmute(mem.Raw_Slice)backing;
|
s := transmute(mem.Raw_Slice)backing;
|
||||||
d := mem.Raw_Dynamic_Array{
|
d := mem.Raw_Dynamic_Array{
|
||||||
|
|||||||
+147
-3
@@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
|
|||||||
return string(b);
|
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 {
|
index_byte :: proc(s: string, c: byte) -> int {
|
||||||
for i := 0; i < len(s); i += 1 {
|
for i := 0; i < len(s); i += 1 {
|
||||||
if s[i] == c do return i;
|
if s[i] == c do return i;
|
||||||
@@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@private PRIME_RABIN_KARP :: 16777619;
|
||||||
|
|
||||||
index :: proc(s, substr: string) -> int {
|
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);
|
n := len(substr);
|
||||||
switch {
|
switch {
|
||||||
case n == 0:
|
case n == 0:
|
||||||
@@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(s)-n+1; i += 1 {
|
hash, pow := hash_str_rabin_karp(substr);
|
||||||
x := s[i:i+n];
|
h: u32;
|
||||||
if x == substr {
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,7 @@ foreign kernel32 {
|
|||||||
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
|
@(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="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="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||||
@(link_name="QueryPerformanceCounter") query_performance_counter :: 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) ---;
|
@(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="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
|
||||||
|
|
||||||
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
|
@(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="GetCursor") get_cursor :: proc() -> Hcursor ---;
|
||||||
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
|
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
|
||||||
|
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1,2 @@
|
|||||||
|
package time
|
||||||
|
IS_SUPPORTED :: false;
|
||||||
@@ -20,5 +20,5 @@ now :: proc() -> Time {
|
|||||||
|
|
||||||
|
|
||||||
sleep :: proc(d: Duration) {
|
sleep :: proc(d: Duration) {
|
||||||
win32.sleep(i32(d/Millisecond));
|
win32.sleep(u32(d/Millisecond));
|
||||||
}
|
}
|
||||||
+60
-17
@@ -41,23 +41,17 @@ accept_ranges := [5]Accept_Range{
|
|||||||
};
|
};
|
||||||
|
|
||||||
accept_sizes := [256]u8{
|
accept_sizes := [256]u8{
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
0x00..0x7f = 0xf0,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
0x80..0xc1 = 0xf1,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
0xc2..0xdf = 0x02,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
|
0xe0 = 0x13,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
|
0xe1..0xec = 0x03,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
|
0xed = 0x23,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
|
0xee..0xef = 0x03,
|
||||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
|
0xf0 = 0x34,
|
||||||
|
0xf1..0xf3 = 0x04,
|
||||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
|
0xf4 = 0x44,
|
||||||
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
|
0xf5..0xff = 0xf1,
|
||||||
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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
encode_rune :: proc(c: rune) -> ([4]u8, int) {
|
encode_rune :: proc(c: rune) -> ([4]u8, int) {
|
||||||
@@ -167,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
|||||||
return r, size;
|
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 {
|
valid_rune :: proc(r: rune) -> bool {
|
||||||
if r < 0 {
|
if r < 0 {
|
||||||
|
|||||||
+334
-40
@@ -3,14 +3,34 @@ package main
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
import "core:reflect"
|
||||||
|
import "intrinsics"
|
||||||
|
|
||||||
when os.OS == "windows" {
|
when os.OS == "windows" {
|
||||||
import "core:thread"
|
import "core:thread"
|
||||||
}
|
}
|
||||||
|
|
||||||
@(link_name="general_stuff")
|
/*
|
||||||
general_stuff :: proc() {
|
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:
|
||||||
fmt.println("# general_stuff");
|
* 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
|
{ // `do` for inline statements rather than block
|
||||||
foo :: proc() do fmt.println("Foo!");
|
foo :: proc() do fmt.println("Foo!");
|
||||||
if false do foo();
|
if false do foo();
|
||||||
@@ -30,14 +50,12 @@ general_stuff :: proc() {
|
|||||||
i := i32(137);
|
i := i32(137);
|
||||||
ptr := &i;
|
ptr := &i;
|
||||||
|
|
||||||
_ = (^f32)(ptr);
|
_ = (^f32)(ptr); // Call-based syntax
|
||||||
// ^f32(ptr) == ^(f32(ptr))
|
// ^f32(ptr) == ^(f32(ptr))
|
||||||
_ = cast(^f32)ptr;
|
_ = cast(^f32)ptr; // Operator-based syntax
|
||||||
|
|
||||||
_ = (^f32)(ptr)^;
|
_ = (^f32)(ptr)^;
|
||||||
_ = (cast(^f32)ptr)^;
|
_ = (cast(^f32)ptr)^;
|
||||||
|
|
||||||
// Questions: Should there be two ways to do it?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -50,7 +68,7 @@ general_stuff :: proc() {
|
|||||||
Foo :: struct {
|
Foo :: struct {
|
||||||
x: int,
|
x: int,
|
||||||
b: bool,
|
b: bool,
|
||||||
}
|
};
|
||||||
f := Foo{137, true};
|
f := Foo{137, true};
|
||||||
x, b := expand_to_tuple(f);
|
x, b := expand_to_tuple(f);
|
||||||
fmt.println(f);
|
fmt.println(f);
|
||||||
@@ -191,8 +209,8 @@ union_type :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 :: struct {x, y, z: f32};
|
Vector3 :: distinct [3]f32;
|
||||||
Quaternion :: struct {x, y, z, w: f32};
|
Quaternion :: distinct quaternion128;
|
||||||
|
|
||||||
// More realistic examples
|
// More realistic examples
|
||||||
{
|
{
|
||||||
@@ -209,18 +227,18 @@ union_type :: proc() {
|
|||||||
orientation: Quaternion,
|
orientation: Quaternion,
|
||||||
|
|
||||||
derived: any,
|
derived: any,
|
||||||
}
|
};
|
||||||
|
|
||||||
Frog :: struct {
|
Frog :: struct {
|
||||||
using entity: Entity,
|
using entity: Entity,
|
||||||
jump_height: f32,
|
jump_height: f32,
|
||||||
}
|
};
|
||||||
|
|
||||||
Monster :: struct {
|
Monster :: struct {
|
||||||
using entity: Entity,
|
using entity: Entity,
|
||||||
is_robot: bool,
|
is_robot: bool,
|
||||||
is_zombie: bool,
|
is_zombie: bool,
|
||||||
}
|
};
|
||||||
|
|
||||||
// See `parametric_polymorphism` procedure for details
|
// See `parametric_polymorphism` procedure for details
|
||||||
new_entity :: proc($T: typeid) -> ^Entity {
|
new_entity :: proc($T: typeid) -> ^Entity {
|
||||||
@@ -254,18 +272,18 @@ union_type :: proc() {
|
|||||||
orientation: Quaternion,
|
orientation: Quaternion,
|
||||||
|
|
||||||
derived: union {Frog, Monster},
|
derived: union {Frog, Monster},
|
||||||
}
|
};
|
||||||
|
|
||||||
Frog :: struct {
|
Frog :: struct {
|
||||||
using entity: ^Entity,
|
using entity: ^Entity,
|
||||||
jump_height: f32,
|
jump_height: f32,
|
||||||
}
|
};
|
||||||
|
|
||||||
Monster :: struct {
|
Monster :: struct {
|
||||||
using entity: ^Entity,
|
using entity: ^Entity,
|
||||||
is_robot: bool,
|
is_robot: bool,
|
||||||
is_zombie: bool,
|
is_zombie: bool,
|
||||||
}
|
};
|
||||||
|
|
||||||
// See `parametric_polymorphism` procedure for details
|
// See `parametric_polymorphism` procedure for details
|
||||||
new_entity :: proc($T: typeid) -> ^Entity {
|
new_entity :: proc($T: typeid) -> ^Entity {
|
||||||
@@ -302,17 +320,17 @@ union_type :: proc() {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Entity :: struct {
|
Entity :: struct {
|
||||||
..
|
...
|
||||||
derived: union{^Frog, ^Monster},
|
derived: union{^Frog, ^Monster},
|
||||||
}
|
}
|
||||||
|
|
||||||
Frog :: struct {
|
Frog :: struct {
|
||||||
using entity: Entity,
|
using entity: Entity,
|
||||||
..
|
...
|
||||||
}
|
}
|
||||||
Monster :: struct {
|
Monster :: struct {
|
||||||
using entity: Entity,
|
using entity: Entity,
|
||||||
..
|
...
|
||||||
|
|
||||||
}
|
}
|
||||||
new_entity :: proc(T: type) -> ^Entity {
|
new_entity :: proc(T: type) -> ^Entity {
|
||||||
@@ -325,7 +343,7 @@ union_type :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parametric_polymorphism :: proc() {
|
parametric_polymorphism :: proc() {
|
||||||
fmt.println("# parametric_polymorphism");
|
fmt.println("\n# parametric_polymorphism");
|
||||||
|
|
||||||
print_value :: proc(value: $T) {
|
print_value :: proc(value: $T) {
|
||||||
fmt.printf("print_value: %T %v\n", value, value);
|
fmt.printf("print_value: %T %v\n", value, value);
|
||||||
@@ -383,13 +401,13 @@ parametric_polymorphism :: proc() {
|
|||||||
hash: u32,
|
hash: u32,
|
||||||
key: Key,
|
key: Key,
|
||||||
value: Value,
|
value: Value,
|
||||||
}
|
};
|
||||||
TABLE_SIZE_MIN :: 32;
|
TABLE_SIZE_MIN :: 32;
|
||||||
Table :: struct(Key, Value: typeid) {
|
Table :: struct(Key, Value: typeid) {
|
||||||
count: int,
|
count: int,
|
||||||
allocator: mem.Allocator,
|
allocator: mem.Allocator,
|
||||||
slots: []Table_Slot(Key, Value),
|
slots: []Table_Slot(Key, Value),
|
||||||
}
|
};
|
||||||
|
|
||||||
// Only allow types that are specializations of a (polymorphic) slice
|
// Only allow types that are specializations of a (polymorphic) slice
|
||||||
make_slice :: proc($T: typeid/[]$E, len: int) -> T {
|
make_slice :: proc($T: typeid/[]$E, len: int) -> T {
|
||||||
@@ -513,7 +531,7 @@ parametric_polymorphism :: proc() {
|
|||||||
Foo1,
|
Foo1,
|
||||||
Foo2,
|
Foo2,
|
||||||
Foo3,
|
Foo3,
|
||||||
}
|
};
|
||||||
Para_Union :: union(T: typeid) {T, Error};
|
Para_Union :: union(T: typeid) {T, Error};
|
||||||
r: Para_Union(int);
|
r: Para_Union(int);
|
||||||
fmt.println(typeid_of(type_of(r)));
|
fmt.println(typeid_of(type_of(r)));
|
||||||
@@ -521,7 +539,7 @@ parametric_polymorphism :: proc() {
|
|||||||
fmt.println(r);
|
fmt.println(r);
|
||||||
r = 123;
|
r = 123;
|
||||||
fmt.println(r);
|
fmt.println(r);
|
||||||
r = Error.Foo0;
|
r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
|
||||||
fmt.println(r);
|
fmt.println(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,6 +561,30 @@ parametric_polymorphism :: proc() {
|
|||||||
for v, i in array {
|
for v, i in array {
|
||||||
assert(v == T(i*i));
|
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() {
|
threading_example :: proc() {
|
||||||
when os.OS == "windows" {
|
when os.OS == "windows" {
|
||||||
fmt.println("# threading_example");
|
fmt.println("\n# threading_example");
|
||||||
|
|
||||||
worker_proc :: proc(t: ^thread.Thread) -> int {
|
worker_proc :: proc(t: ^thread.Thread) -> int {
|
||||||
for iteration in 1..5 {
|
for iteration in 1..5 {
|
||||||
@@ -600,7 +642,7 @@ threading_example :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
array_programming :: proc() {
|
array_programming :: proc() {
|
||||||
fmt.println("# array_programming");
|
fmt.println("\n# array_programming");
|
||||||
{
|
{
|
||||||
a := [3]f32{1, 2, 3};
|
a := [3]f32{1, 2, 3};
|
||||||
b := [3]f32{5, 6, 7};
|
b := [3]f32{5, 6, 7};
|
||||||
@@ -645,7 +687,7 @@ array_programming :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
named_proc_return_parameters :: proc() {
|
named_proc_return_parameters :: proc() {
|
||||||
fmt.println("# named proc return parameters");
|
fmt.println("\n# named proc return parameters");
|
||||||
|
|
||||||
foo0 :: proc() -> int {
|
foo0 :: proc() -> int {
|
||||||
return 123;
|
return 123;
|
||||||
@@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() {
|
|||||||
|
|
||||||
|
|
||||||
using_enum :: proc() {
|
using_enum :: proc() {
|
||||||
fmt.println("# using enum");
|
fmt.println("\n# using enum");
|
||||||
|
|
||||||
using Foo :: enum {A, B, C};
|
using Foo :: enum {A, B, C};
|
||||||
|
|
||||||
@@ -679,25 +721,25 @@ using_enum :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
map_type :: proc() {
|
map_type :: proc() {
|
||||||
fmt.println("# map type");
|
fmt.println("\n# map type");
|
||||||
|
|
||||||
// enums of type u16, u32, i16 & i32 also work
|
// enums of type u16, u32, i16 & i32 also work
|
||||||
Enum_u8 :: enum u8 {
|
Enum_u8 :: enum u8 {
|
||||||
A = 0,
|
A = 0,
|
||||||
B = 1 << 8 - 1,
|
B = 1 << 8 - 1,
|
||||||
}
|
};
|
||||||
Enum_u64 :: enum u64 {
|
Enum_u64 :: enum u64 {
|
||||||
A = 0,
|
A = 0,
|
||||||
B = 1 << 64 - 1,
|
B = 1 << 64 - 1,
|
||||||
}
|
};
|
||||||
Enum_i8 :: enum i8 {
|
Enum_i8 :: enum i8 {
|
||||||
A = 0,
|
A = 0,
|
||||||
B = -(1 << 7),
|
B = -(1 << 7),
|
||||||
}
|
};
|
||||||
Enum_i64 :: enum i64 {
|
Enum_i64 :: enum i64 {
|
||||||
A = 0,
|
A = 0,
|
||||||
B = -(1 << 63),
|
B = -(1 << 63),
|
||||||
}
|
};
|
||||||
|
|
||||||
map_u8: map[Enum_u8]u8;
|
map_u8: map[Enum_u8]u8;
|
||||||
map_u8[Enum_u8.A] = u8(Enum_u8.B);
|
map_u8[Enum_u8.A] = u8(Enum_u8.B);
|
||||||
@@ -721,7 +763,7 @@ map_type :: proc() {
|
|||||||
|
|
||||||
demo_struct :: struct {
|
demo_struct :: struct {
|
||||||
member: Enum_i64,
|
member: Enum_i64,
|
||||||
}
|
};
|
||||||
|
|
||||||
map_string: map[string]demo_struct;
|
map_string: map[string]demo_struct;
|
||||||
map_string["Hellope!"] = demo_struct{Enum_i64.B};
|
map_string["Hellope!"] = demo_struct{Enum_i64.B};
|
||||||
@@ -734,7 +776,7 @@ map_type :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
implicit_selector_expression :: proc() {
|
implicit_selector_expression :: proc() {
|
||||||
fmt.println("# implicit selector expression");
|
fmt.println("\n# implicit selector expression");
|
||||||
|
|
||||||
Foo :: enum {A, B, C};
|
Foo :: enum {A, B, C};
|
||||||
|
|
||||||
@@ -762,7 +804,7 @@ implicit_selector_expression :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
explicit_procedure_overloading :: proc() {
|
explicit_procedure_overloading :: proc() {
|
||||||
fmt.println("# explicit procedure overloading");
|
fmt.println("\n# explicit procedure overloading");
|
||||||
|
|
||||||
add_ints :: proc(a, b: int) -> int {
|
add_ints :: proc(a, b: int) -> int {
|
||||||
x := a + b;
|
x := a + b;
|
||||||
@@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
complete_switch :: proc() {
|
complete_switch :: proc() {
|
||||||
fmt.println("# complete_switch");
|
fmt.println("\n# complete_switch");
|
||||||
{ // enum
|
{ // enum
|
||||||
using Foo :: enum {
|
using Foo :: enum {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
C,
|
C,
|
||||||
D,
|
D,
|
||||||
}
|
};
|
||||||
|
|
||||||
b := Foo.B;
|
b := Foo.B;
|
||||||
f := Foo.A;
|
f := Foo.A;
|
||||||
@@ -829,6 +871,8 @@ complete_switch :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cstring_example :: proc() {
|
cstring_example :: proc() {
|
||||||
|
fmt.println("\n# cstring_example");
|
||||||
|
|
||||||
W :: "Hellope";
|
W :: "Hellope";
|
||||||
X :: cstring(W);
|
X :: cstring(W);
|
||||||
Y :: string(X);
|
Y :: string(X);
|
||||||
@@ -860,6 +904,8 @@ deprecated_attribute :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bit_set_type :: proc() {
|
bit_set_type :: proc() {
|
||||||
|
fmt.println("\n# bit_set_type");
|
||||||
|
|
||||||
{
|
{
|
||||||
using Day :: enum {
|
using Day :: enum {
|
||||||
Sunday,
|
Sunday,
|
||||||
@@ -869,7 +915,7 @@ bit_set_type :: proc() {
|
|||||||
Thursday,
|
Thursday,
|
||||||
Friday,
|
Friday,
|
||||||
Saturday,
|
Saturday,
|
||||||
}
|
};
|
||||||
|
|
||||||
Days :: distinct bit_set[Day];
|
Days :: distinct bit_set[Day];
|
||||||
WEEKEND :: Days{Sunday, Saturday};
|
WEEKEND :: Days{Sunday, Saturday};
|
||||||
@@ -921,6 +967,8 @@ bit_set_type :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
diverging_procedures :: proc() {
|
diverging_procedures :: proc() {
|
||||||
|
fmt.println("\n# diverging_procedures");
|
||||||
|
|
||||||
// Diverging procedures may never return
|
// Diverging procedures may never return
|
||||||
foo :: proc() -> ! {
|
foo :: proc() -> ! {
|
||||||
fmt.println("I'm a diverging procedure");
|
fmt.println("I'm a diverging procedure");
|
||||||
@@ -930,6 +978,8 @@ diverging_procedures :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deferred_procedure_associations :: proc() {
|
deferred_procedure_associations :: proc() {
|
||||||
|
fmt.println("\n# deferred_procedure_associations");
|
||||||
|
|
||||||
@(deferred_out=closure)
|
@(deferred_out=closure)
|
||||||
open :: proc(s: string) -> bool {
|
open :: proc(s: string) -> bool {
|
||||||
fmt.println(s);
|
fmt.println(s);
|
||||||
@@ -945,9 +995,247 @@ 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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
general_stuff();
|
extra_general_stuff();
|
||||||
union_type();
|
union_type();
|
||||||
parametric_polymorphism();
|
parametric_polymorphism();
|
||||||
threading_example();
|
threading_example();
|
||||||
@@ -963,5 +1251,11 @@ main :: proc() {
|
|||||||
bit_set_type();
|
bit_set_type();
|
||||||
diverging_procedures();
|
diverging_procedures();
|
||||||
deferred_procedure_associations();
|
deferred_procedure_associations();
|
||||||
|
reflection();
|
||||||
|
quaternions();
|
||||||
|
inline_for_statement();
|
||||||
|
where_clauses();
|
||||||
|
ranged_fields_for_array_compound_literals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 75 KiB |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
|
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" 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 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
|
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" x86 1> NUL
|
||||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 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
|
set _NO_DEBUG_HEAP=1
|
||||||
|
|||||||
+42
-14
@@ -2,7 +2,7 @@ enum TargetOsKind {
|
|||||||
TargetOs_Invalid,
|
TargetOs_Invalid,
|
||||||
|
|
||||||
TargetOs_windows,
|
TargetOs_windows,
|
||||||
TargetOs_osx,
|
TargetOs_darwin,
|
||||||
TargetOs_linux,
|
TargetOs_linux,
|
||||||
TargetOs_essence,
|
TargetOs_essence,
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ enum TargetEndianKind {
|
|||||||
String target_os_names[TargetOs_COUNT] = {
|
String target_os_names[TargetOs_COUNT] = {
|
||||||
str_lit(""),
|
str_lit(""),
|
||||||
str_lit("windows"),
|
str_lit("windows"),
|
||||||
str_lit("osx"),
|
str_lit("darwin"),
|
||||||
str_lit("linux"),
|
str_lit("linux"),
|
||||||
str_lit("essence"),
|
str_lit("essence"),
|
||||||
};
|
};
|
||||||
@@ -55,9 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
String const ODIN_VERSION = str_lit("0.10.1");
|
String const ODIN_VERSION = str_lit("0.10.2");
|
||||||
String cross_compile_target = str_lit("");
|
|
||||||
String cross_compile_lib_dir = str_lit("");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -66,6 +64,7 @@ struct TargetMetrics {
|
|||||||
TargetArchKind arch;
|
TargetArchKind arch;
|
||||||
isize word_size;
|
isize word_size;
|
||||||
isize max_align;
|
isize max_align;
|
||||||
|
String target_triplet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -109,6 +108,7 @@ struct BuildContext {
|
|||||||
bool has_resource;
|
bool has_resource;
|
||||||
String opt_flags;
|
String opt_flags;
|
||||||
String llc_flags;
|
String llc_flags;
|
||||||
|
String target_triplet;
|
||||||
String link_flags;
|
String link_flags;
|
||||||
bool is_dll;
|
bool is_dll;
|
||||||
bool generate_docs;
|
bool generate_docs;
|
||||||
@@ -121,6 +121,7 @@ struct BuildContext {
|
|||||||
bool no_crt;
|
bool no_crt;
|
||||||
bool use_lld;
|
bool use_lld;
|
||||||
bool vet;
|
bool vet;
|
||||||
|
bool cross_compiling;
|
||||||
|
|
||||||
QueryDataSetSettings query_data_set_settings;
|
QueryDataSetSettings query_data_set_settings;
|
||||||
|
|
||||||
@@ -135,18 +136,19 @@ struct BuildContext {
|
|||||||
gb_global BuildContext build_context = {0};
|
gb_global BuildContext build_context = {0};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gb_global TargetMetrics target_windows_386 = {
|
gb_global TargetMetrics target_windows_386 = {
|
||||||
TargetOs_windows,
|
TargetOs_windows,
|
||||||
TargetArch_386,
|
TargetArch_386,
|
||||||
4,
|
4,
|
||||||
8,
|
8,
|
||||||
|
str_lit("i686-pc-windows"),
|
||||||
};
|
};
|
||||||
gb_global TargetMetrics target_windows_amd64 = {
|
gb_global TargetMetrics target_windows_amd64 = {
|
||||||
TargetOs_windows,
|
TargetOs_windows,
|
||||||
TargetArch_amd64,
|
TargetArch_amd64,
|
||||||
8,
|
8,
|
||||||
16,
|
16,
|
||||||
|
str_lit("x86_64-pc-windows-gnu"),
|
||||||
};
|
};
|
||||||
|
|
||||||
gb_global TargetMetrics target_linux_386 = {
|
gb_global TargetMetrics target_linux_386 = {
|
||||||
@@ -154,23 +156,47 @@ gb_global TargetMetrics target_linux_386 = {
|
|||||||
TargetArch_386,
|
TargetArch_386,
|
||||||
4,
|
4,
|
||||||
8,
|
8,
|
||||||
|
str_lit("i686-pc-linux-gnu"),
|
||||||
};
|
};
|
||||||
gb_global TargetMetrics target_linux_amd64 = {
|
gb_global TargetMetrics target_linux_amd64 = {
|
||||||
TargetOs_linux,
|
TargetOs_linux,
|
||||||
TargetArch_amd64,
|
TargetArch_amd64,
|
||||||
8,
|
8,
|
||||||
16,
|
16,
|
||||||
|
str_lit("x86_64-pc-linux-gnu"),
|
||||||
};
|
};
|
||||||
|
|
||||||
gb_global TargetMetrics target_osx_amd64 = {
|
gb_global TargetMetrics target_darwin_amd64 = {
|
||||||
TargetOs_osx,
|
TargetOs_darwin,
|
||||||
TargetArch_amd64,
|
TargetArch_amd64,
|
||||||
8,
|
8,
|
||||||
16,
|
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) {
|
TargetOsKind get_target_os_from_string(String str) {
|
||||||
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
||||||
@@ -522,7 +548,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;
|
BuildContext *bc = &build_context;
|
||||||
|
|
||||||
gb_affinity_init(&bc->affinity);
|
gb_affinity_init(&bc->affinity);
|
||||||
@@ -540,7 +566,7 @@ void init_build_context(void) {
|
|||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
metrics = target_windows_amd64;
|
metrics = target_windows_amd64;
|
||||||
#elif defined(GB_SYSTEM_OSX)
|
#elif defined(GB_SYSTEM_OSX)
|
||||||
metrics = target_osx_amd64;
|
metrics = target_darwin_amd64;
|
||||||
#else
|
#else
|
||||||
metrics = target_linux_amd64;
|
metrics = target_linux_amd64;
|
||||||
#endif
|
#endif
|
||||||
@@ -554,8 +580,9 @@ void init_build_context(void) {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (cross_compile_target.len) {
|
if (cross_target) {
|
||||||
bc->ODIN_OS = cross_compile_target;
|
metrics = *cross_target;
|
||||||
|
bc->cross_compiling = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_ASSERT(metrics.os != TargetOs_Invalid);
|
GB_ASSERT(metrics.os != TargetOs_Invalid);
|
||||||
@@ -573,6 +600,7 @@ void init_build_context(void) {
|
|||||||
bc->max_align = metrics.max_align;
|
bc->max_align = metrics.max_align;
|
||||||
bc->link_flags = str_lit(" ");
|
bc->link_flags = str_lit(" ");
|
||||||
bc->opt_flags = str_lit(" ");
|
bc->opt_flags = str_lit(" ");
|
||||||
|
bc->target_triplet = metrics.target_triplet;
|
||||||
|
|
||||||
|
|
||||||
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
|
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
|
||||||
@@ -590,7 +618,7 @@ void init_build_context(void) {
|
|||||||
case TargetOs_windows:
|
case TargetOs_windows:
|
||||||
bc->link_flags = str_lit("/machine:x64 ");
|
bc->link_flags = str_lit("/machine:x64 ");
|
||||||
break;
|
break;
|
||||||
case TargetOs_osx:
|
case TargetOs_darwin:
|
||||||
break;
|
break;
|
||||||
case TargetOs_linux:
|
case TargetOs_linux:
|
||||||
bc->link_flags = str_lit("-arch x86-64 ");
|
bc->link_flags = str_lit("-arch x86-64 ");
|
||||||
@@ -603,7 +631,7 @@ void init_build_context(void) {
|
|||||||
case TargetOs_windows:
|
case TargetOs_windows:
|
||||||
bc->link_flags = str_lit("/machine:x86 ");
|
bc->link_flags = str_lit("/machine:x86 ");
|
||||||
break;
|
break;
|
||||||
case TargetOs_osx:
|
case TargetOs_darwin:
|
||||||
gb_printf_err("Unsupported architecture\n");
|
gb_printf_err("Unsupported architecture\n");
|
||||||
gb_exit(1);
|
gb_exit(1);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+115
-36
@@ -41,12 +41,21 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (operand->mode == Addressing_Type) {
|
if (operand->mode == Addressing_Type) {
|
||||||
|
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);
|
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));
|
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||||
gb_string_free(t);
|
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;
|
e->type = operand->type;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
|
|||||||
isize rhs_count = operands.count;
|
isize rhs_count = operands.count;
|
||||||
for_array(i, operands) {
|
for_array(i, operands) {
|
||||||
if (operands[i].mode == Addressing_Invalid) {
|
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);
|
GB_ASSERT(e->type == nullptr);
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(e);
|
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);
|
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_distinct = is_type_distinct(init_expr);
|
||||||
bool is_distinct = is_type_distinct(type_expr);
|
Ast *te = remove_type_alias_clutter(init_expr);
|
||||||
Ast *te = remove_type_alias_clutter(type_expr);
|
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *named = alloc_type_named(name, nullptr, e);
|
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);
|
named->Named.base = base_type(bt);
|
||||||
|
|
||||||
if (is_distinct && is_type_typeid(e->type)) {
|
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;
|
is_distinct = false;
|
||||||
}
|
}
|
||||||
if (!is_distinct) {
|
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;
|
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
|
// using decl
|
||||||
if (decl->is_using) {
|
if (decl->is_using) {
|
||||||
// NOTE(bill): Must be an enum declaration
|
// NOTE(bill): Must be an enum declaration
|
||||||
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
|||||||
|
|
||||||
switch (operand.mode) {
|
switch (operand.mode) {
|
||||||
case Addressing_Type: {
|
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->kind = Entity_TypeName;
|
||||||
e->type = nullptr;
|
e->type = nullptr;
|
||||||
|
|
||||||
DeclInfo *d = ctx->decl;
|
check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
|||||||
|
|
||||||
bool is_foreign = e->Procedure.is_foreign;
|
bool is_foreign = e->Procedure.is_foreign;
|
||||||
bool is_export = e->Procedure.is_export;
|
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 (e->pkg != nullptr && e->token.string == "main") {
|
||||||
if (pt->param_count != 0 ||
|
if (pt->param_count != 0 ||
|
||||||
@@ -714,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pt->result_count == 0 && is_require_results) {
|
if (pt->result_count == 0 && ac.require_results) {
|
||||||
error(pl->type, "'#require_results' is not needed on a procedure with no results");
|
error(pl->type, "'require_results' is not needed on a procedure with no results");
|
||||||
} else {
|
} else {
|
||||||
pt->require_results = is_require_results;
|
pt->require_results = ac.require_results;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ac.link_name.len > 0) {
|
if (ac.link_name.len > 0) {
|
||||||
@@ -791,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->type == nullptr);
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
@@ -805,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;
|
ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(e);
|
DeclInfo *decl = decl_info_of_entity(e);
|
||||||
|
GB_ASSERT(decl == ctx->decl);
|
||||||
if (decl != nullptr) {
|
if (decl != nullptr) {
|
||||||
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
|
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
|
||||||
}
|
}
|
||||||
@@ -936,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
|||||||
|
|
||||||
ptr_set_destroy(&entity_set);
|
ptr_set_destroy(&entity_set);
|
||||||
|
|
||||||
|
|
||||||
for_array(j, pge->entities) {
|
for_array(j, pge->entities) {
|
||||||
Entity *p = pge->entities[j];
|
Entity *p = pge->entities[j];
|
||||||
if (p->type == t_invalid) {
|
if (p->type == t_invalid) {
|
||||||
@@ -962,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
|||||||
defer (end_error_block());
|
defer (end_error_block());
|
||||||
|
|
||||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
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:
|
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;
|
is_invalid = true;
|
||||||
break;
|
break;
|
||||||
// case ProcOverload_CallingConvention:
|
// 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;
|
// is_invalid = true;
|
||||||
// break;
|
// break;
|
||||||
case ProcOverload_ParamVariadic:
|
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;
|
is_invalid = true;
|
||||||
break;
|
break;
|
||||||
case ProcOverload_ResultCount:
|
case ProcOverload_ResultCount:
|
||||||
case ProcOverload_ResultTypes:
|
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;
|
is_invalid = true;
|
||||||
break;
|
break;
|
||||||
case ProcOverload_Polymorphic:
|
case ProcOverload_Polymorphic:
|
||||||
#if 0
|
#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;
|
is_invalid = true;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@@ -1051,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
|
|||||||
|
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_Variable:
|
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;
|
break;
|
||||||
case Entity_Constant:
|
case Entity_Constant:
|
||||||
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
|
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
|
||||||
break;
|
break;
|
||||||
case Entity_TypeName: {
|
case Entity_TypeName: {
|
||||||
check_type_decl(&c, e, d->type_expr, named_type);
|
check_type_decl(&c, e, d->init_expr, named_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Entity_Procedure:
|
case Entity_Procedure:
|
||||||
@@ -1074,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) {
|
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
|
||||||
if (body == nullptr) {
|
if (body == nullptr) {
|
||||||
@@ -1098,6 +1136,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
ctx->curr_proc_decl = decl;
|
ctx->curr_proc_decl = decl;
|
||||||
ctx->curr_proc_sig = type;
|
ctx->curr_proc_sig = type;
|
||||||
|
|
||||||
|
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);
|
GB_ASSERT(type->kind == Type_Proc);
|
||||||
if (type->Proc.param_count > 0) {
|
if (type->Proc.param_count > 0) {
|
||||||
TypeTuple *params = &type->Proc.params->Tuple;
|
TypeTuple *params = &type->Proc.params->Tuple;
|
||||||
@@ -1122,15 +1167,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
for_array(i, scope->elements.entries) {
|
for_array(i, scope->elements.entries) {
|
||||||
Entity *f = scope->elements.entries[i].value;
|
Entity *f = scope->elements.entries[i].value;
|
||||||
if (f->kind == Entity_Variable) {
|
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;
|
uvar->Variable.is_immutable = is_immutable;
|
||||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||||
|
|
||||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
ProcUsingVar puv = {e, uvar};
|
||||||
if (prev != nullptr) {
|
array_add(&using_entities, puv);
|
||||||
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1139,10 +1182,37 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
ast_node(bs, BlockStmt, body);
|
|
||||||
// check_open_scope(ctx, body);
|
|
||||||
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
||||||
|
|
||||||
if (type->Proc.result_count > 0) {
|
if (type->Proc.result_count > 0) {
|
||||||
if (!check_is_terminating(body)) {
|
if (!check_is_terminating(body)) {
|
||||||
if (token.kind == Token_Ident) {
|
if (token.kind == Token_Ident) {
|
||||||
@@ -1153,12 +1223,19 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check_close_scope(ctx);
|
}
|
||||||
|
check_close_scope(ctx);
|
||||||
|
|
||||||
check_scope_usage(ctx->checker, ctx->scope);
|
check_scope_usage(ctx->checker, ctx->scope);
|
||||||
|
|
||||||
|
#if 1
|
||||||
if (decl->parent != nullptr) {
|
if (decl->parent != nullptr) {
|
||||||
|
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)
|
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||||
|
// But only at the procedure level
|
||||||
for_array(i, decl->deps.entries) {
|
for_array(i, decl->deps.entries) {
|
||||||
Entity *e = decl->deps.entries[i].ptr;
|
Entity *e = decl->deps.entries[i].ptr;
|
||||||
ptr_set_add(&decl->parent->deps, e);
|
ptr_set_add(&decl->parent->deps, e);
|
||||||
@@ -1169,6 +1246,8 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+995
-110
File diff suppressed because it is too large.
Load diff
+192
-29
@@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) {
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(rs, InlineRangeStmt, node);
|
||||||
|
return false;
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(rs, RangeStmt, node);
|
case_ast_node(rs, RangeStmt, node);
|
||||||
return false;
|
return false;
|
||||||
case_end;
|
case_end;
|
||||||
@@ -492,8 +496,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
|
|||||||
for_array(i, found->elements.entries) {
|
for_array(i, found->elements.entries) {
|
||||||
Entity *f = found->elements.entries[i].value;
|
Entity *f = found->elements.entries[i].value;
|
||||||
if (f->kind == Entity_Variable) {
|
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, expr);
|
||||||
uvar->using_expr = expr;
|
|
||||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||||
if (prev != nullptr) {
|
if (prev != nullptr) {
|
||||||
gbString expr_str = expr_to_string(expr);
|
gbString expr_str = expr_to_string(expr);
|
||||||
@@ -587,6 +590,162 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
|
|||||||
multi_map_insert(seen, key, tap);
|
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) {
|
void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||||
ast_node(ss, SwitchStmt, node);
|
ast_node(ss, SwitchStmt, node);
|
||||||
|
|
||||||
@@ -971,7 +1130,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
GB_PANIC("Unknown type to type switch statement");
|
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;
|
TokenPos pos = cc->token.pos;
|
||||||
gbString expr_str = expr_to_string(y.expr);
|
gbString expr_str = expr_to_string(y.expr);
|
||||||
error(y.expr,
|
error(y.expr,
|
||||||
@@ -1023,7 +1182,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
|
|
||||||
for_array(i, variants) {
|
for_array(i, variants) {
|
||||||
Type *t = variants[i];
|
Type *t = variants[i];
|
||||||
if (!ptr_set_exists(&seen, t)) {
|
if (!type_ptr_set_exists(&seen, t)) {
|
||||||
array_add(&unhandled, t);
|
array_add(&unhandled, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1132,7 +1291,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
isize rhs_count = rhs_operands.count;
|
isize rhs_count = rhs_operands.count;
|
||||||
for_array(i, rhs_operands) {
|
for_array(i, rhs_operands) {
|
||||||
if (rhs_operands[i].mode == Addressing_Invalid) {
|
if (rhs_operands[i].mode == Addressing_Invalid) {
|
||||||
rhs_count--;
|
// TODO(bill): Should I ignore invalid parameters?
|
||||||
|
// rhs_count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,7 +1328,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
be->right = as->rhs[0];
|
be->right = as->rhs[0];
|
||||||
|
|
||||||
check_expr(ctx, &lhs, as->lhs[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) {
|
if (rhs.mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1298,6 +1458,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
check_close_scope(ctx);
|
check_close_scope(ctx);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
case_ast_node(rs, RangeStmt, node);
|
case_ast_node(rs, RangeStmt, node);
|
||||||
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
|
||||||
|
|
||||||
@@ -1320,29 +1481,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
|
|
||||||
check_expr(ctx, &x, ie->left);
|
check_expr(ctx, &x, ie->left);
|
||||||
if (x.mode == Addressing_Invalid) {
|
if (x.mode == Addressing_Invalid) {
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
check_expr(ctx, &y, ie->right);
|
check_expr(ctx, &y, ie->right);
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (y.mode == Addressing_Invalid) {
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_typed(ctx, &x, y.type);
|
convert_to_typed(ctx, &x, y.type);
|
||||||
if (x.mode == Addressing_Invalid) {
|
if (x.mode == Addressing_Invalid) {
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
convert_to_typed(ctx, &y, x.type);
|
convert_to_typed(ctx, &y, x.type);
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (y.mode == Addressing_Invalid) {
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_typed(ctx, &x, default_type(y.type));
|
convert_to_typed(ctx, &x, default_type(y.type));
|
||||||
if (x.mode == Addressing_Invalid) {
|
if (x.mode == Addressing_Invalid) {
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
convert_to_typed(ctx, &y, default_type(x.type));
|
convert_to_typed(ctx, &y, default_type(x.type));
|
||||||
if (y.mode == Addressing_Invalid) {
|
if (y.mode == Addressing_Invalid) {
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!are_types_identical(x.type, y.type)) {
|
if (!are_types_identical(x.type, y.type)) {
|
||||||
@@ -1356,13 +1517,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
gb_string_free(yt);
|
gb_string_free(yt);
|
||||||
gb_string_free(xt);
|
gb_string_free(xt);
|
||||||
}
|
}
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *type = x.type;
|
Type *type = x.type;
|
||||||
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(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");
|
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x.mode == Addressing_Constant &&
|
if (x.mode == Addressing_Constant &&
|
||||||
@@ -1382,18 +1543,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
if (!ok) {
|
if (!ok) {
|
||||||
// TODO(bill): Better error message
|
// TODO(bill): Better error message
|
||||||
error(ie->op, "Invalid interval range");
|
error(ie->op, "Invalid interval range");
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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->left, x.mode, x.type, x.value);
|
||||||
add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
|
add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
|
||||||
val0 = type;
|
val0 = type;
|
||||||
@@ -1407,12 +1560,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
gbString t = type_to_string(operand.type);
|
gbString t = type_to_string(operand.type);
|
||||||
error(operand.expr, "Cannot iterate over the type '%s'", t);
|
error(operand.expr, "Cannot iterate over the type '%s'", t);
|
||||||
gb_string_free(t);
|
gb_string_free(t);
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
} else {
|
} else {
|
||||||
val0 = operand.type;
|
val0 = operand.type;
|
||||||
val1 = t_int;
|
val1 = t_int;
|
||||||
add_type_info_type(ctx, operand.type);
|
add_type_info_type(ctx, operand.type);
|
||||||
goto skip_expr;
|
goto skip_expr_range_stmt;
|
||||||
}
|
}
|
||||||
} else if (operand.mode != Addressing_Invalid) {
|
} else if (operand.mode != Addressing_Invalid) {
|
||||||
bool is_ptr = is_type_pointer(operand.type);
|
bool is_ptr = is_type_pointer(operand.type);
|
||||||
@@ -1457,7 +1610,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};
|
Ast * lhs[2] = {rs->val0, rs->val1};
|
||||||
Type *rhs[2] = {val0, val1};
|
Type *rhs[2] = {val0, val1};
|
||||||
|
|
||||||
@@ -1507,7 +1661,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
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);
|
check_stmt(ctx, rs->body, new_flags);
|
||||||
@@ -1515,6 +1674,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
check_close_scope(ctx);
|
check_close_scope(ctx);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(irs, InlineRangeStmt, node);
|
||||||
|
check_inline_range_stmt(ctx, node, mod_flags);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ss, SwitchStmt, node);
|
case_ast_node(ss, SwitchStmt, node);
|
||||||
check_switch_stmt(ctx, node, mod_flags);
|
check_switch_stmt(ctx, node, mod_flags);
|
||||||
case_end;
|
case_end;
|
||||||
@@ -1814,7 +1977,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
// TODO(bill): Should a 'continue' happen here?
|
// 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];
|
Entity *e = entities[entity_index];
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1833,7 +1996,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
for_array(i, scope->elements.entries) {
|
for_array(i, scope->elements.entries) {
|
||||||
Entity *f = scope->elements.entries[i].value;
|
Entity *f = scope->elements.entries[i].value;
|
||||||
if (f->kind == Entity_Variable) {
|
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;
|
uvar->Variable.is_immutable = is_immutable;
|
||||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||||
if (prev != nullptr) {
|
if (prev != nullptr) {
|
||||||
|
|||||||
+359
-39
@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
|
|||||||
return false;
|
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) {
|
isize init_field_capacity, Type *struct_type, String context) {
|
||||||
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
*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(node->kind == Ast_StructType);
|
||||||
GB_ASSERT(struct_type->kind == Type_Struct);
|
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);
|
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
|
||||||
add_entity(ctx->checker, ctx->scope, name, field);
|
add_entity(ctx->checker, ctx->scope, name, field);
|
||||||
array_add(fields, field);
|
array_add(fields, field);
|
||||||
|
array_add(tags, p->tag.string);
|
||||||
|
|
||||||
field_src_index += 1;
|
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));
|
auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
|
||||||
if (found_gen_types != nullptr) {
|
if (found_gen_types != nullptr) {
|
||||||
for_array(i, *found_gen_types) {
|
for_array(i, *found_gen_types) {
|
||||||
Entity *e = (*found_gen_types)[i];
|
Entity *e = (*found_gen_types)[i];
|
||||||
Type *t = base_type(e->type);
|
Type *t = base_type(e->type);
|
||||||
TypeTuple *tuple = get_record_polymorphic_params(t);
|
TypeTuple *tuple = get_record_polymorphic_params(t);
|
||||||
bool ok = true;
|
|
||||||
GB_ASSERT(param_count == tuple->variables.count);
|
GB_ASSERT(param_count == tuple->variables.count);
|
||||||
|
|
||||||
|
bool skip = false;
|
||||||
|
|
||||||
for (isize j = 0; j < param_count; j++) {
|
for (isize j = 0; j < param_count; j++) {
|
||||||
Entity *p = tuple->variables[j];
|
Entity *p = tuple->variables[j];
|
||||||
Operand o = ordered_operands[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 (p->kind == Entity_TypeName) {
|
||||||
if (is_type_polymorphic(o.type)) {
|
if (is_type_polymorphic(o.type)) {
|
||||||
// NOTE(bill): Do not add polymorphic version to the gen_types
|
// NOTE(bill): Do not add polymorphic version to the gen_types
|
||||||
ok = false;
|
skip = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!are_types_identical(o.type, p->type)) {
|
if (!are_types_identical(o.type, p->type)) {
|
||||||
ok = false;
|
skip = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (p->kind == Entity_Constant) {
|
} 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)) {
|
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 {
|
} else {
|
||||||
GB_PANIC("Unknown entity kind");
|
GB_PANIC("Unknown entity kind");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (!skip) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -439,8 +454,6 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
if (poly_operands != nullptr) {
|
if (poly_operands != nullptr) {
|
||||||
Operand operand = (*poly_operands)[entities.count];
|
Operand operand = (*poly_operands)[entities.count];
|
||||||
if (is_type_param) {
|
if (is_type_param) {
|
||||||
GB_ASSERT(operand.mode == Addressing_Type ||
|
|
||||||
operand.mode == Addressing_Invalid);
|
|
||||||
if (is_type_polymorphic(base_type(operand.type))) {
|
if (is_type_polymorphic(base_type(operand.type))) {
|
||||||
is_polymorphic = true;
|
is_polymorphic = true;
|
||||||
can_check_fields = false;
|
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 = alloc_entity_type_name(scope, token, operand.type);
|
||||||
e->TypeName.is_type_alias = true;
|
e->TypeName.is_type_alias = true;
|
||||||
} else {
|
} 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);
|
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||||
}
|
}
|
||||||
} else {
|
} 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.polymorphic_params = polymorphic_params;
|
||||||
struct_type->Struct.is_poly_specialized = is_poly_specialized;
|
struct_type->Struct.is_poly_specialized = is_poly_specialized;
|
||||||
|
|
||||||
|
|
||||||
if (!is_polymorphic) {
|
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) {
|
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_polymorphic = is_polymorphic;
|
||||||
union_type->Union.is_poly_specialized = is_poly_specialized;
|
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) {
|
for_array(i, ut->variants) {
|
||||||
Ast *node = ut->variants[i];
|
Ast *node = ut->variants[i];
|
||||||
Type *t = check_type_expr(ctx, node, nullptr);
|
Type *t = check_type_expr(ctx, node, nullptr);
|
||||||
@@ -1252,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) {
|
Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) {
|
||||||
bool modify_type = !ctx->no_polymorphic_errors;
|
bool modify_type = !ctx->no_polymorphic_errors;
|
||||||
|
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
|
||||||
if (!is_operand_value(operand)) {
|
if (!is_operand_value(operand)) {
|
||||||
if (modify_type) {
|
if (show_error) {
|
||||||
error(operand.expr, "Cannot determine polymorphic type from parameter");
|
error(operand.expr, "Cannot determine polymorphic type from parameter");
|
||||||
}
|
}
|
||||||
return t_invalid;
|
return t_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
|
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
|
||||||
if (modify_type) {
|
if (show_error) {
|
||||||
set_procedure_abi_types(ctx, poly_type);
|
set_procedure_abi_types(ctx->allocator, poly_type);
|
||||||
}
|
}
|
||||||
return poly_type;
|
return poly_type;
|
||||||
}
|
}
|
||||||
if (modify_type) {
|
if (show_error) {
|
||||||
gbString pts = type_to_string(poly_type);
|
gbString pts = type_to_string(poly_type);
|
||||||
gbString ots = type_to_string(operand.type);
|
gbString ots = type_to_string(operand.type);
|
||||||
defer (gb_string_free(pts));
|
defer (gb_string_free(pts));
|
||||||
@@ -1538,7 +1567,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_poly_name) {
|
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;
|
is_type_param = true;
|
||||||
} else {
|
} else {
|
||||||
if (param_value.kind != ParameterValue_Invalid) {
|
if (param_value.kind != ParameterValue_Invalid) {
|
||||||
@@ -1622,6 +1651,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
if (op.mode == Addressing_Constant) {
|
if (op.mode == Addressing_Constant) {
|
||||||
poly_const = op.value;
|
poly_const = op.value;
|
||||||
} else {
|
} else {
|
||||||
|
error(op.expr, "Expected a constant value for this polymorphic name parameter");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1825,6 +1855,282 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
|||||||
return tuple;
|
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 *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
|
||||||
Type *new_type = original_type;
|
Type *new_type = original_type;
|
||||||
|
|
||||||
@@ -1889,6 +2195,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
|||||||
{
|
{
|
||||||
i64 align = type_align_of(original_type);
|
i64 align = type_align_of(original_type);
|
||||||
i64 size = type_size_of(original_type);
|
i64 size = type_size_of(original_type);
|
||||||
|
|
||||||
switch (8*size) {
|
switch (8*size) {
|
||||||
case 8: new_type = t_u8; break;
|
case 8: new_type = t_u8; break;
|
||||||
case 16: new_type = t_u16; break;
|
case 16: new_type = t_u16; break;
|
||||||
@@ -1903,7 +2210,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (build_context.ODIN_OS == "linux" ||
|
} else if (build_context.ODIN_OS == "linux" ||
|
||||||
build_context.ODIN_OS == "osx") {
|
build_context.ODIN_OS == "darwin") {
|
||||||
Type *bt = core_type(original_type);
|
Type *bt = core_type(original_type);
|
||||||
switch (bt->kind) {
|
switch (bt->kind) {
|
||||||
// Okay to pass by value (usually)
|
// Okay to pass by value (usually)
|
||||||
@@ -1920,18 +2227,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
|||||||
case Type_Pointer: break;
|
case Type_Pointer: break;
|
||||||
case Type_Proc: break; // NOTE(bill): Just a pointer
|
case Type_Proc: break; // NOTE(bill): Just a pointer
|
||||||
|
|
||||||
// Odin specific
|
default: {
|
||||||
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);
|
i64 size = type_size_of(original_type);
|
||||||
if (8*size > 16) {
|
if (size > 16) {
|
||||||
new_type = alloc_type_pointer(original_type);
|
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;
|
break;
|
||||||
@@ -2004,8 +2310,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
|
|||||||
break;
|
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 {
|
} else {
|
||||||
// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
|
// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
|
||||||
// their architectures
|
// their architectures
|
||||||
@@ -2071,25 +2379,39 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_procedure_abi_types(CheckerContext *c, Type *type) {
|
void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||||
type = base_type(type);
|
type = base_type(type);
|
||||||
if (type->kind != Type_Proc) {
|
if (type->kind != Type_Proc) {
|
||||||
return;
|
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++) {
|
for (i32 i = 0; i < type->Proc.param_count; i++) {
|
||||||
Entity *e = type->Proc.params->Tuple.variables[i];
|
Entity *e = type->Proc.params->Tuple.variables[i];
|
||||||
if (e->kind == Entity_Variable) {
|
if (e->kind == Entity_Variable) {
|
||||||
Type *original_type = e->type;
|
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;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): The types are the same
|
// 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.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(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
|
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
|
// NOTE(bill): 'operands' is for generating non generic procedure type
|
||||||
@@ -2187,8 +2509,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
|||||||
}
|
}
|
||||||
type->Proc.is_polymorphic = is_polymorphic;
|
type->Proc.is_polymorphic = is_polymorphic;
|
||||||
|
|
||||||
set_procedure_abi_types(c, type);
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2537,7 +2857,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
|||||||
generic_type = o.type;
|
generic_type = o.type;
|
||||||
}
|
}
|
||||||
if (count < 0) {
|
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;
|
count = 0;
|
||||||
}
|
}
|
||||||
Type *elem = check_type_expr(ctx, at->elem, nullptr);
|
Type *elem = check_type_expr(ctx, at->elem, nullptr);
|
||||||
|
|||||||
+103
-31
@@ -85,10 +85,14 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) {
|
|||||||
EntityGraphNode *y = data[j];
|
EntityGraphNode *y = data[j];
|
||||||
isize a = x->entity->order_in_src;
|
isize a = x->entity->order_in_src;
|
||||||
isize b = y->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) {
|
||||||
if (x->dep_count > y->dep_count) return +1;
|
return -1;
|
||||||
|
}
|
||||||
|
if (x->dep_count == y->dep_count) {
|
||||||
return a < b ? -1 : b > a;
|
return a < b ? -1 : b > a;
|
||||||
}
|
}
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
|
void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
|
||||||
EntityGraphNode *x = data[i];
|
EntityGraphNode *x = data[i];
|
||||||
@@ -400,6 +404,15 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
|
|||||||
if (found) {
|
if (found) {
|
||||||
return *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);
|
map_set(&s->elements, key, entity);
|
||||||
if (entity->scope == nullptr) {
|
if (entity->scope == nullptr) {
|
||||||
entity->scope = s;
|
entity->scope = s;
|
||||||
@@ -1044,22 +1057,38 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) {
|
|||||||
// NOTE(bill): Error should have been handled already
|
// NOTE(bill): Error should have been handled already
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
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,
|
error(prev->token,
|
||||||
"Redeclaration of '%.*s' in this scope through 'using'\n"
|
"Redeclaration of '%.*s' in this scope through 'using'\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name),
|
LIT(name),
|
||||||
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
|
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pos == prev->token.pos) {
|
if (pos == prev->token.pos) {
|
||||||
// NOTE(bill): Error should have been handled already
|
// NOTE(bill): Error should have been handled already
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
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,
|
error(prev->token,
|
||||||
"Redeclaration of '%.*s' in this scope\n"
|
"Redeclaration of '%.*s' in this scope\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name),
|
LIT(name),
|
||||||
LIT(pos.file), pos.line, pos.column);
|
LIT(pos.file), pos.line, pos.column);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1139,6 +1168,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec
|
|||||||
add_entity_definition(&c->checker->info, identifier, e);
|
add_entity_definition(&c->checker->info, identifier, e);
|
||||||
GB_ASSERT(e->decl_info == nullptr);
|
GB_ASSERT(e->decl_info == nullptr);
|
||||||
e->decl_info = d;
|
e->decl_info = d;
|
||||||
|
d->entity = e;
|
||||||
array_add(&c->checker->info.entities, e);
|
array_add(&c->checker->info.entities, e);
|
||||||
e->order_in_src = c->checker->info.entities.count;
|
e->order_in_src = c->checker->info.entities.count;
|
||||||
e->pkg = c->pkg;
|
e->pkg = c->pkg;
|
||||||
@@ -1415,6 +1445,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_type_info_float);
|
||||||
add_min_dep_type_info(c, t_f64);
|
add_min_dep_type_info(c, t_f64);
|
||||||
break;
|
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;
|
break;
|
||||||
|
|
||||||
@@ -1577,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
|||||||
|
|
||||||
str_lit("args__"),
|
str_lit("args__"),
|
||||||
str_lit("type_table"),
|
str_lit("type_table"),
|
||||||
|
str_lit("__type_info_of"),
|
||||||
str_lit("global_scratch_allocator"),
|
str_lit("global_scratch_allocator"),
|
||||||
|
|
||||||
str_lit("Type_Info"),
|
str_lit("Type_Info"),
|
||||||
@@ -1585,9 +1624,17 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
|||||||
|
|
||||||
str_lit("quo_complex64"),
|
str_lit("quo_complex64"),
|
||||||
str_lit("quo_complex128"),
|
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("umodti3"),
|
||||||
str_lit("udivti3"),
|
str_lit("udivti3"),
|
||||||
|
|
||||||
|
str_lit("memory_compare"),
|
||||||
|
str_lit("memory_compare_zero"),
|
||||||
};
|
};
|
||||||
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
|
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]));
|
add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
|
||||||
@@ -1656,9 +1703,10 @@ bool is_entity_a_dependency(Entity *e) {
|
|||||||
if (e == nullptr) return false;
|
if (e == nullptr) return false;
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_Procedure:
|
case Entity_Procedure:
|
||||||
case Entity_Variable:
|
|
||||||
case Entity_Constant:
|
|
||||||
return true;
|
return true;
|
||||||
|
case Entity_Constant:
|
||||||
|
case Entity_Variable:
|
||||||
|
return e->pkg != nullptr;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1685,21 +1733,20 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
|||||||
EntityGraphNode *n = M.entries[i].value;
|
EntityGraphNode *n = M.entries[i].value;
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(e);
|
DeclInfo *decl = decl_info_of_entity(e);
|
||||||
if (decl != nullptr) {
|
GB_ASSERT(decl != nullptr);
|
||||||
|
|
||||||
for_array(j, decl->deps.entries) {
|
for_array(j, decl->deps.entries) {
|
||||||
auto entry = decl->deps.entries[j];
|
Entity *dep = decl->deps.entries[j].ptr;
|
||||||
Entity *dep = entry.ptr;
|
GB_ASSERT(dep != nullptr);
|
||||||
if (dep && is_entity_a_dependency(dep)) {
|
if (is_entity_a_dependency(dep)) {
|
||||||
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
|
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
|
||||||
if (m_ != nullptr) {
|
GB_ASSERT(m_ != nullptr);
|
||||||
EntityGraphNode *m = *m_;
|
EntityGraphNode *m = *m_;
|
||||||
entity_graph_node_set_add(&n->succ, m);
|
entity_graph_node_set_add(&n->succ, m);
|
||||||
entity_graph_node_set_add(&m->pred, n);
|
entity_graph_node_set_add(&m->pred, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count);
|
auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count);
|
||||||
|
|
||||||
@@ -1741,6 +1788,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
|||||||
EntityGraphNode *n = G[i];
|
EntityGraphNode *n = G[i];
|
||||||
n->index = i;
|
n->index = i;
|
||||||
n->dep_count = n->succ.entries.count;
|
n->dep_count = n->succ.entries.count;
|
||||||
|
|
||||||
GB_ASSERT(n->dep_count >= 0);
|
GB_ASSERT(n->dep_count >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1863,6 +1911,7 @@ void init_core_type_info(Checker *c) {
|
|||||||
t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer"));
|
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_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_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_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_string = find_core_type(c, str_lit("Type_Info_String"));
|
||||||
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
|
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
|
||||||
@@ -1887,6 +1936,7 @@ void init_core_type_info(Checker *c) {
|
|||||||
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
|
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_rune_ptr = alloc_type_pointer(t_type_info_rune);
|
||||||
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
|
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_complex_ptr = alloc_type_pointer(t_type_info_complex);
|
||||||
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
|
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
|
||||||
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
|
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
|
||||||
@@ -2138,6 +2188,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
|||||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2528,6 +2584,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
|
|
||||||
Ast *init_expr = value;
|
Ast *init_expr = value;
|
||||||
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
|
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
|
||||||
|
d->entity = e;
|
||||||
d->type_expr = vd->type;
|
d->type_expr = vd->type;
|
||||||
d->init_expr = init_expr;
|
d->init_expr = init_expr;
|
||||||
d->attributes = vd->attributes;
|
d->attributes = vd->attributes;
|
||||||
@@ -2557,14 +2614,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
Entity *e = nullptr;
|
Entity *e = nullptr;
|
||||||
|
|
||||||
d->attributes = vd->attributes;
|
d->attributes = vd->attributes;
|
||||||
|
d->type_expr = vd->type;
|
||||||
|
d->init_expr = init;
|
||||||
|
|
||||||
if (is_ast_type(init)) {
|
if (is_ast_type(init)) {
|
||||||
e = alloc_entity_type_name(d->scope, token, nullptr);
|
e = alloc_entity_type_name(d->scope, token, nullptr);
|
||||||
if (vd->type != nullptr) {
|
// if (vd->type != nullptr) {
|
||||||
error(name, "A type declaration cannot have an type parameter");
|
// error(name, "A type declaration cannot have an type parameter");
|
||||||
}
|
// }
|
||||||
d->type_expr = init;
|
|
||||||
d->init_expr = init;
|
|
||||||
} else if (init->kind == Ast_ProcLit) {
|
} else if (init->kind == Ast_ProcLit) {
|
||||||
if (c->scope->flags&ScopeFlag_Type) {
|
if (c->scope->flags&ScopeFlag_Type) {
|
||||||
error(name, "Procedure declarations are not allowed within a struct");
|
error(name, "Procedure declarations are not allowed within a struct");
|
||||||
@@ -2591,19 +2648,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
pl->type->ProcType.calling_convention = cc;
|
pl->type->ProcType.calling_convention = cc;
|
||||||
}
|
}
|
||||||
d->proc_lit = init;
|
d->proc_lit = init;
|
||||||
d->type_expr = vd->type;
|
d->init_expr = init;
|
||||||
} else if (init->kind == Ast_ProcGroup) {
|
} else if (init->kind == Ast_ProcGroup) {
|
||||||
ast_node(pg, ProcGroup, init);
|
ast_node(pg, ProcGroup, init);
|
||||||
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
||||||
if (fl != nullptr) {
|
if (fl != nullptr) {
|
||||||
error(name, "Procedure groups are not allowed within a foreign block");
|
error(name, "Procedure groups are not allowed within a foreign block");
|
||||||
}
|
}
|
||||||
d->init_expr = init;
|
|
||||||
d->type_expr = vd->type;
|
|
||||||
} else {
|
} else {
|
||||||
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
||||||
d->type_expr = vd->type;
|
|
||||||
d->init_expr = init;
|
|
||||||
}
|
}
|
||||||
e->identifier = name;
|
e->identifier = name;
|
||||||
|
|
||||||
@@ -3101,7 +3154,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
|||||||
Entity *e = scope->elements.entries[elem_index].value;
|
Entity *e = scope->elements.entries[elem_index].value;
|
||||||
if (e->scope == parent_scope) continue;
|
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);
|
Entity *found = scope_lookup_current(parent_scope, name);
|
||||||
if (found != nullptr) {
|
if (found != nullptr) {
|
||||||
// NOTE(bill):
|
// NOTE(bill):
|
||||||
@@ -3315,8 +3368,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
|
|||||||
if (es->expr->kind == Ast_CallExpr) {
|
if (es->expr->kind == Ast_CallExpr) {
|
||||||
ast_node(ce, CallExpr, es->expr);
|
ast_node(ce, CallExpr, es->expr);
|
||||||
if (ce->proc->kind == Ast_BasicDirective) {
|
if (ce->proc->kind == Ast_BasicDirective) {
|
||||||
Operand o = {};
|
if (ctx->collect_delayed_decls) {
|
||||||
check_expr(ctx, &o, es->expr);
|
array_add(&ctx->scope->delayed_directives, es->expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
@@ -3473,12 +3527,18 @@ void check_import_entities(Checker *c) {
|
|||||||
for_array(i, pkg->files) {
|
for_array(i, pkg->files) {
|
||||||
AstFile *f = pkg->files[i];
|
AstFile *f = pkg->files[i];
|
||||||
CheckerContext ctx = c->init_ctx;
|
CheckerContext ctx = c->init_ctx;
|
||||||
|
|
||||||
add_curr_ast_file(&ctx, f);
|
add_curr_ast_file(&ctx, f);
|
||||||
|
|
||||||
for_array(j, f->scope->delayed_imports) {
|
for_array(j, f->scope->delayed_imports) {
|
||||||
Ast *decl = f->scope->delayed_imports[j];
|
Ast *decl = f->scope->delayed_imports[j];
|
||||||
check_add_import_decl(&ctx, decl);
|
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) {
|
for_array(j, f->scope->delayed_directives) {
|
||||||
Ast *expr = f->scope->delayed_directives[j];
|
Ast *expr = f->scope->delayed_directives[j];
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
@@ -3542,7 +3602,6 @@ void calculate_global_init_order(Checker *c) {
|
|||||||
#define TIME_SECTION(str)
|
#define TIME_SECTION(str)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
CheckerInfo *info = &c->info;
|
CheckerInfo *info = &c->info;
|
||||||
|
|
||||||
TIME_SECTION("generate entity dependency graph");
|
TIME_SECTION("generate entity dependency graph");
|
||||||
@@ -3584,21 +3643,26 @@ void calculate_global_init_order(Checker *c) {
|
|||||||
|
|
||||||
for_array(i, n->pred.entries) {
|
for_array(i, n->pred.entries) {
|
||||||
EntityGraphNode *p = n->pred.entries[i].ptr;
|
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);
|
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;
|
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)) {
|
if (ptr_set_exists(&emitted, d)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ptr_set_add(&emitted, d);
|
ptr_set_add(&emitted, d);
|
||||||
|
|
||||||
d->entity = e;
|
|
||||||
array_add(&info->variable_init_order, d);
|
array_add(&info->variable_init_order, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3637,6 +3701,14 @@ void check_proc_info(Checker *c, ProcInfo pi) {
|
|||||||
return;
|
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 bounds_check = (pi.tags & ProcTag_bounds_check) != 0;
|
||||||
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
|
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
|
||||||
|
|
||||||
|
|||||||
+7
-211
@@ -59,218 +59,8 @@ struct BuiltinProc {
|
|||||||
BuiltinProcPkg pkg;
|
BuiltinProcPkg pkg;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BuiltinProcId {
|
|
||||||
BuiltinProc_Invalid,
|
|
||||||
|
|
||||||
BuiltinProc_len,
|
#include "checker_builtin_procs.hpp"
|
||||||
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},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Operand is used as an intermediate value whilst checking
|
// Operand is used as an intermediate value whilst checking
|
||||||
@@ -307,6 +97,7 @@ struct DeferredProcedure {
|
|||||||
struct AttributeContext {
|
struct AttributeContext {
|
||||||
bool is_export;
|
bool is_export;
|
||||||
bool is_static;
|
bool is_static;
|
||||||
|
bool require_results;
|
||||||
String link_name;
|
String link_name;
|
||||||
String link_prefix;
|
String link_prefix;
|
||||||
isize init_expr_list_count;
|
isize init_expr_list_count;
|
||||||
@@ -431,6 +222,7 @@ struct ForeignContext {
|
|||||||
typedef Array<Entity *> CheckerTypePath;
|
typedef Array<Entity *> CheckerTypePath;
|
||||||
typedef Array<Type *> CheckerPolyPath;
|
typedef Array<Type *> CheckerPolyPath;
|
||||||
|
|
||||||
|
|
||||||
// CheckerInfo stores all the symbol information for a type-checked program
|
// CheckerInfo stores all the symbol information for a type-checked program
|
||||||
struct CheckerInfo {
|
struct CheckerInfo {
|
||||||
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
|
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
|
||||||
@@ -486,10 +278,14 @@ struct CheckerContext {
|
|||||||
CheckerPolyPath *poly_path;
|
CheckerPolyPath *poly_path;
|
||||||
isize poly_level; // TODO(bill): Actually handle correctly
|
isize poly_level; // TODO(bill): Actually handle correctly
|
||||||
|
|
||||||
|
#define MAX_INLINE_FOR_DEPTH 1024ll
|
||||||
|
i64 inline_for_depth;
|
||||||
|
|
||||||
bool in_enum_type;
|
bool in_enum_type;
|
||||||
bool collect_delayed_decls;
|
bool collect_delayed_decls;
|
||||||
bool allow_polymorphic_types;
|
bool allow_polymorphic_types;
|
||||||
bool no_polymorphic_errors;
|
bool no_polymorphic_errors;
|
||||||
|
bool hide_polymorphic_errors;
|
||||||
bool in_polymorphic_specialization;
|
bool in_polymorphic_specialization;
|
||||||
Scope * polymorphic_scope;
|
Scope * polymorphic_scope;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,320 @@
|
|||||||
|
// 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_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_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("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_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
|
#define GB_IMPLEMENTATION
|
||||||
#include "gb/gb.h"
|
#include "gb/gb.h"
|
||||||
|
|
||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
template <typename U, typename V>
|
template <typename U, typename V>
|
||||||
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(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_++)
|
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||||
|
|
||||||
|
#include "range_cache.cpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
u64 fnv64a(void const *data, isize len) {
|
u64 fnv64a(void const *data, isize len) {
|
||||||
u8 const *bytes = cast(u8 const *)data;
|
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 "ptr_set.cpp"
|
||||||
#include "string_set.cpp"
|
#include "string_set.cpp"
|
||||||
#include "priority_queue.cpp"
|
#include "priority_queue.cpp"
|
||||||
|
#include "thread_pool.cpp"
|
||||||
|
|
||||||
|
|
||||||
gb_global String global_module_path = {0};
|
gb_global String global_module_path = {0};
|
||||||
@@ -873,7 +874,6 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
|||||||
info.size = size;
|
info.size = size;
|
||||||
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||||
array_add(fi, info);
|
array_add(fi, info);
|
||||||
|
|
||||||
} while (FindNextFileW(find_file, &file_data));
|
} while (FindNextFileW(find_file, &file_data));
|
||||||
|
|
||||||
if (fi->count == 0) {
|
if (fi->count == 0) {
|
||||||
|
|||||||
+8
-5
@@ -48,7 +48,8 @@ enum EntityFlag {
|
|||||||
EntityFlag_NotExported = 1<<14,
|
EntityFlag_NotExported = 1<<14,
|
||||||
|
|
||||||
EntityFlag_Static = 1<<16,
|
EntityFlag_Static = 1<<16,
|
||||||
// EntityFlag_Reference = 1<<17,
|
|
||||||
|
EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++
|
||||||
|
|
||||||
EntityFlag_CVarArg = 1<<20,
|
EntityFlag_CVarArg = 1<<20,
|
||||||
EntityFlag_AutoCast = 1<<21,
|
EntityFlag_AutoCast = 1<<21,
|
||||||
@@ -183,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
if (name.len == 0) {
|
switch (name.len) {
|
||||||
return false;
|
case 0: return false;
|
||||||
|
case 1: return name[0] != '_';
|
||||||
}
|
}
|
||||||
return name[0] != '_';
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool entity_has_deferred_procedure(Entity *e) {
|
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;
|
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);
|
GB_ASSERT(parent != nullptr);
|
||||||
token.pos = parent->token.pos;
|
token.pos = parent->token.pos;
|
||||||
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
|
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
|
||||||
entity->using_parent = parent;
|
entity->using_parent = parent;
|
||||||
entity->parent_proc_decl = parent->parent_proc_decl;
|
entity->parent_proc_decl = parent->parent_proc_decl;
|
||||||
|
entity->using_expr = using_expr;
|
||||||
entity->flags |= EntityFlag_Using;
|
entity->flags |= EntityFlag_Using;
|
||||||
entity->flags |= EntityFlag_Used;
|
entity->flags |= EntityFlag_Used;
|
||||||
entity->state = EntityState_Resolved;
|
entity->state = EntityState_Resolved;
|
||||||
|
|||||||
+249
-15
@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
|
|||||||
struct Complex128 {
|
struct Complex128 {
|
||||||
f64 real, imag;
|
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 {
|
enum ExactValueKind {
|
||||||
ExactValue_Invalid,
|
ExactValue_Invalid,
|
||||||
@@ -21,9 +34,11 @@ enum ExactValueKind {
|
|||||||
ExactValue_Integer,
|
ExactValue_Integer,
|
||||||
ExactValue_Float,
|
ExactValue_Float,
|
||||||
ExactValue_Complex,
|
ExactValue_Complex,
|
||||||
|
ExactValue_Quaternion,
|
||||||
ExactValue_Pointer,
|
ExactValue_Pointer,
|
||||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||||
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
||||||
|
ExactValue_Typeid,
|
||||||
|
|
||||||
ExactValue_Count,
|
ExactValue_Count,
|
||||||
};
|
};
|
||||||
@@ -37,8 +52,10 @@ struct ExactValue {
|
|||||||
f64 value_float;
|
f64 value_float;
|
||||||
i64 value_pointer;
|
i64 value_pointer;
|
||||||
Complex128 value_complex;
|
Complex128 value_complex;
|
||||||
|
Quaternion256 value_quaternion;
|
||||||
Ast * value_compound;
|
Ast * value_compound;
|
||||||
Ast * value_procedure;
|
Ast * value_procedure;
|
||||||
|
Type * value_typeid;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,25 +70,22 @@ HashKey hash_exact_value(ExactValue v) {
|
|||||||
return hash_integer(u64(v.value_bool));
|
return hash_integer(u64(v.value_bool));
|
||||||
case ExactValue_String:
|
case ExactValue_String:
|
||||||
return hash_string(v.value_string);
|
return hash_string(v.value_string);
|
||||||
case ExactValue_Integer: {
|
case ExactValue_Integer:
|
||||||
u64 *d = big_int_ptr(&v.value_integer);
|
return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
|
||||||
u64 x = 0;
|
|
||||||
for (i32 i = 0; i < v.value_integer.len; i++) {
|
|
||||||
x |= d[i];
|
|
||||||
}
|
|
||||||
return hash_integer(x);
|
|
||||||
}
|
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
return hash_f64(v.value_float);
|
return hash_f64(v.value_float);
|
||||||
case ExactValue_Pointer:
|
case ExactValue_Pointer:
|
||||||
return hash_integer(v.value_pointer);
|
return hash_integer(v.value_pointer);
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
return hashing_proc(&v.value_complex, gb_size_of(Complex128));
|
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:
|
case ExactValue_Compound:
|
||||||
return hash_pointer(v.value_compound);
|
return hash_pointer(v.value_compound);
|
||||||
case ExactValue_Procedure:
|
case ExactValue_Procedure:
|
||||||
return hash_pointer(v.value_procedure);
|
return hash_pointer(v.value_procedure);
|
||||||
|
case ExactValue_Typeid:
|
||||||
|
return hash_pointer(v.value_typeid);
|
||||||
}
|
}
|
||||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
return hashing_proc(&v, gb_size_of(ExactValue));
|
||||||
|
|
||||||
@@ -122,6 +136,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
|
|||||||
return result;
|
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 exact_value_pointer(i64 ptr) {
|
||||||
ExactValue result = {ExactValue_Pointer};
|
ExactValue result = {ExactValue_Pointer};
|
||||||
result.value_pointer = ptr;
|
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 exact_value_integer_from_string(String const &string) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
big_int_from_string(&result.value_integer, string);
|
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'
|
str.len--; // Ignore the 'i|j|k'
|
||||||
f64 imag = float_from_string(str);
|
f64 imag = float_from_string(str);
|
||||||
|
|
||||||
if (last_rune == 'i') {
|
switch (last_rune) {
|
||||||
return exact_value_complex(0, imag);
|
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: {
|
case Token_Rune: {
|
||||||
Rune r = GB_RUNE_INVALID;
|
Rune r = GB_RUNE_INVALID;
|
||||||
gb_utf8_decode(token.string.text, token.string.len, &r);
|
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);
|
return exact_value_i64(r);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -324,11 +356,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
|
|||||||
return exact_value_complex(v.value_float, 0);
|
return exact_value_complex(v.value_float, 0);
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
return v;
|
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};
|
ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExactValue exact_value_real(ExactValue v) {
|
ExactValue exact_value_real(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
@@ -337,6 +384,8 @@ ExactValue exact_value_real(ExactValue v) {
|
|||||||
return v;
|
return v;
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
return exact_value_float(v.value_complex.real);
|
return exact_value_float(v.value_complex.real);
|
||||||
|
case ExactValue_Quaternion:
|
||||||
|
return exact_value_float(v.value_quaternion.real);
|
||||||
}
|
}
|
||||||
ExactValue r = {ExactValue_Invalid};
|
ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
return r;
|
||||||
@@ -349,6 +398,34 @@ ExactValue exact_value_imag(ExactValue v) {
|
|||||||
return exact_value_i64(0);
|
return exact_value_i64(0);
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
return exact_value_float(v.value_complex.imag);
|
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};
|
ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
return r;
|
||||||
@@ -367,6 +444,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
|
|||||||
return r;
|
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) {
|
i64 exact_value_to_i64(ExactValue v) {
|
||||||
v = exact_value_to_integer(v);
|
v = exact_value_to_integer(v);
|
||||||
if (v.kind == ExactValue_Integer) {
|
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_Integer:
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
|
case ExactValue_Quaternion:
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -419,6 +523,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
|||||||
f64 imag = v.value_complex.imag;
|
f64 imag = v.value_complex.imag;
|
||||||
return exact_value_complex(-real, -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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -469,8 +580,10 @@ i32 exact_value_order(ExactValue const &v) {
|
|||||||
return 3;
|
return 3;
|
||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
return 4;
|
return 4;
|
||||||
case ExactValue_Pointer:
|
case ExactValue_Quaternion:
|
||||||
return 5;
|
return 5;
|
||||||
|
case ExactValue_Pointer:
|
||||||
|
return 6;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("How'd you get here? Invalid Value.kind");
|
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_Bool:
|
||||||
case ExactValue_String:
|
case ExactValue_String:
|
||||||
case ExactValue_Complex:
|
case ExactValue_Quaternion:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
@@ -505,6 +618,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
|||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
|
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
|
||||||
return;
|
return;
|
||||||
|
case ExactValue_Quaternion:
|
||||||
|
*x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -515,6 +631,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
|||||||
case ExactValue_Complex:
|
case ExactValue_Complex:
|
||||||
*x = exact_value_to_complex(*x);
|
*x = exact_value_to_complex(*x);
|
||||||
return;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -612,6 +739,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
|||||||
break;
|
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: {
|
case ExactValue_String: {
|
||||||
if (op != Token_Add) goto error;
|
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);
|
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) {
|
i32 cmp_f64(f64 a, f64 b) {
|
||||||
return (a > b) - (a < b);
|
return (a > b) - (a < b);
|
||||||
@@ -719,8 +900,61 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
}
|
}
|
||||||
break;
|
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");
|
GB_PANIC("Invalid comparison");
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
+15
-7
@@ -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_init (gbSemaphore *s);
|
||||||
GB_DEF void gb_semaphore_destroy(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_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);
|
GB_DEF void gb_semaphore_wait (gbSemaphore *s);
|
||||||
|
|
||||||
|
|
||||||
@@ -978,7 +978,7 @@ typedef struct gbThread {
|
|||||||
gbThreadProc * proc;
|
gbThreadProc * proc;
|
||||||
void * user_data;
|
void * user_data;
|
||||||
isize user_index;
|
isize user_index;
|
||||||
isize return_value;
|
isize volatile return_value;
|
||||||
|
|
||||||
gbSemaphore semaphore;
|
gbSemaphore semaphore;
|
||||||
isize stack_size;
|
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); }
|
gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#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_init(gbSemaphore *s) {
|
||||||
gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); }
|
s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
|
||||||
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_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)
|
#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); }
|
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) {
|
gb_inline void gb_yield(void) {
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
Sleep(0);
|
YieldProcessor();
|
||||||
#else
|
#else
|
||||||
sched_yield();
|
sched_yield();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+796
-99
File diff suppressed because it is too large.
Load diff
+201
-25
@@ -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) {
|
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;
|
i64 word_bits = 8*build_context.word_size;
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
GB_ASSERT(is_type_proc(t));
|
GB_ASSERT(is_type_proc(t));
|
||||||
|
|
||||||
isize param_count = t->Proc.param_count;
|
isize param_count = t->Proc.param_count;
|
||||||
isize result_count = t->Proc.result_count;
|
isize result_count = t->Proc.result_count;
|
||||||
|
|
||||||
ir_print_proc_results(f, m, t);
|
ir_print_proc_results(f, m, t);
|
||||||
ir_write_string(f, str_lit(" ("));
|
ir_write_string(f, str_lit(" ("));
|
||||||
if (t->Proc.return_by_pointer) {
|
if (t->Proc.return_by_pointer) {
|
||||||
@@ -426,6 +429,9 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
|||||||
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
|
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
|
||||||
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
|
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
|
||||||
|
|
||||||
|
case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return;
|
||||||
|
case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return;
|
||||||
|
|
||||||
case Basic_any: ir_write_str_lit(f, "%..any"); return;
|
case Basic_any: ir_write_str_lit(f, "%..any"); return;
|
||||||
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
|
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
|
||||||
case Basic_string: ir_write_str_lit(f, "%..string"); return;
|
case Basic_string: ir_write_str_lit(f, "%..string"); return;
|
||||||
@@ -767,15 +773,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
case ExactValue_Float: {
|
case ExactValue_Float: {
|
||||||
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
|
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
|
||||||
type = core_type(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) {
|
switch (type->Basic.kind) {
|
||||||
case Basic_f32:
|
case Basic_f32:
|
||||||
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
|
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
|
||||||
// a 64 bit number if bits_of(float type) <= 64.
|
// a 64 bit number if bits_of(float type) <= 64.
|
||||||
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
|
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
|
||||||
// 64 bit mantissa: 52 bits
|
// 64 bit mantissa: 52 bits ==> 52-52 == 0
|
||||||
// 32 bit mantissa: 23 bits
|
// 32 bit mantissa: 23 bits ==> 52-23 == 29
|
||||||
// 16 bit mantissa: 10 bits
|
// 16 bit mantissa: 10 bits ==> 52=10 == 42
|
||||||
// 29 == 52-23
|
// 29 == 52-23
|
||||||
u >>= 29;
|
u >>= 29;
|
||||||
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);
|
ir_fprintf(f, "0x%016llx", u);
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ExactValue_Complex: {
|
case ExactValue_Complex: {
|
||||||
|
// xy/ri format
|
||||||
type = core_type(type);
|
type = core_type(type);
|
||||||
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
|
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
|
||||||
Type *ft = base_complex_elem_type(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, '}');
|
ir_write_byte(f, '}');
|
||||||
break;
|
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:
|
case ExactValue_Pointer:
|
||||||
if (value.value_pointer == 0) {
|
if (value.value_pointer == 0) {
|
||||||
if (is_type_typeid(type)) {
|
if (is_type_typeid(type)) {
|
||||||
@@ -836,6 +879,69 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
ir_write_str_lit(f, "zeroinitializer");
|
ir_write_str_lit(f, "zeroinitializer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
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, ", ");
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
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);
|
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
|
||||||
|
|
||||||
ir_write_byte(f, '[');
|
ir_write_byte(f, '[');
|
||||||
@@ -852,6 +958,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
}
|
}
|
||||||
|
|
||||||
ir_write_byte(f, ']');
|
ir_write_byte(f, ']');
|
||||||
|
}
|
||||||
} else if (is_type_simd_vector(type)) {
|
} else if (is_type_simd_vector(type)) {
|
||||||
ast_node(cl, CompoundLit, value.value_compound);
|
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, '<');
|
if (type->Struct.is_packed) ir_write_byte(f, '<');
|
||||||
ir_write_byte(f, '{');
|
ir_write_byte(f, '{');
|
||||||
if (type->Struct.custom_align > 0) {
|
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) {
|
if (value_count > 0) {
|
||||||
ir_write_string(f, str_lit(", "));
|
ir_write_string(f, str_lit(", "));
|
||||||
}
|
}
|
||||||
@@ -1089,7 +1197,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case irValue_Param:
|
case irValue_Param:
|
||||||
|
if (value->Param.index >= 0) {
|
||||||
|
ir_fprintf(f, "%%_.%d", value->Param.index);
|
||||||
|
} else {
|
||||||
ir_print_encoded_local(f, value->Param.entity->token.string);
|
ir_print_encoded_local(f, value->Param.entity->token.string);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case irValue_SourceCodeLocation: {
|
case irValue_SourceCodeLocation: {
|
||||||
irValue *file = value->SourceCodeLocation.file;
|
irValue *file = value->SourceCodeLocation.file;
|
||||||
@@ -1124,7 +1236,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
|
|||||||
switch (cc) {
|
switch (cc) {
|
||||||
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
|
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
|
||||||
case ProcCC_Contextless: 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_StdCall: ir_write_str_lit(f, "cc 64 "); break;
|
||||||
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
|
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
|
||||||
case ProcCC_None: ir_write_str_lit(f, ""); 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) {
|
void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
|
||||||
ir_print_type(f, m, t_context_ptr);
|
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 inreg ");
|
||||||
// ir_write_str_lit(f, " noalias nonnull nocapture ");
|
ir_write_str_lit(f, " noalias nonnull nocapture ");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
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_write_str_lit(f, ", ");
|
||||||
ir_print_type(f, m, type);
|
ir_print_type(f, m, type);
|
||||||
ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
|
ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
|
||||||
|
// ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1888,11 +2002,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
if (e->flags&EntityFlag_NoAlias) {
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
ir_write_str_lit(f, " noalias");
|
ir_write_str_lit(f, " noalias");
|
||||||
}
|
}
|
||||||
|
if (e->flags&EntityFlag_ImplicitReference) {
|
||||||
|
ir_write_str_lit(f, " nonnull dereferenceable");
|
||||||
|
}
|
||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
irValue *arg = call->args[i];
|
irValue *arg = call->args[i];
|
||||||
if (is_type_boolean(t)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
ir_print_value(f, m, arg, t);
|
ir_print_value(f, m, arg, t);
|
||||||
param_index++;
|
param_index++;
|
||||||
}
|
}
|
||||||
@@ -1907,17 +2021,35 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
param_index++;
|
param_index++;
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
for_array(i, params->variables) {
|
||||||
Entity *e = params->variables[i];
|
Entity *e = params->variables[i];
|
||||||
GB_ASSERT(e != nullptr);
|
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, ", ");
|
if (param_index > 0) ir_write_str_lit(f, ", ");
|
||||||
|
|
||||||
irValue *arg = call->args[i];
|
|
||||||
Type *t = proc_type->Proc.abi_compat_params[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, ", ");
|
||||||
|
|
||||||
|
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);
|
ir_print_type(f, m, t);
|
||||||
if (e->flags&EntityFlag_NoAlias) {
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
ir_write_str_lit(f, " noalias");
|
ir_write_str_lit(f, " noalias");
|
||||||
@@ -1928,6 +2060,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (proc_type->Proc.calling_convention == ProcCC_Odin) {
|
if (proc_type->Proc.calling_convention == ProcCC_Odin) {
|
||||||
if (param_index > 0) ir_write_str_lit(f, ", ");
|
if (param_index > 0) ir_write_str_lit(f, ", ");
|
||||||
|
|
||||||
@@ -1995,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
|
|
||||||
|
|
||||||
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||||
|
set_procedure_abi_types(heap_allocator(), proc->type);
|
||||||
|
|
||||||
if (proc->body == nullptr) {
|
if (proc->body == nullptr) {
|
||||||
ir_write_str_lit(f, "declare ");
|
ir_write_str_lit(f, "declare ");
|
||||||
// if (proc->tags & ProcTag_dll_import) {
|
// if (proc->tags & ProcTag_dll_import) {
|
||||||
@@ -2043,7 +2178,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
|
|
||||||
if (param_count > 0) {
|
if (param_count > 0) {
|
||||||
TypeTuple *params = &proc_type->params->Tuple;
|
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];
|
Entity *e = params->variables[i];
|
||||||
Type *original_type = e->type;
|
Type *original_type = e->type;
|
||||||
Type *abi_type = proc_type->abi_compat_params[i];
|
Type *abi_type = proc_type->abi_compat_params[i];
|
||||||
@@ -2052,17 +2188,30 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
|
|
||||||
if (i+1 == params->variables.count && proc_type->c_vararg) {
|
if (i+1 == params->variables.count && proc_type->c_vararg) {
|
||||||
ir_write_str_lit(f, " ...");
|
ir_write_str_lit(f, " ...");
|
||||||
|
} else {
|
||||||
|
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 {
|
} else {
|
||||||
ir_print_type(f, m, abi_type);
|
ir_print_type(f, m, abi_type);
|
||||||
if (e->flags&EntityFlag_NoAlias) {
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
ir_write_str_lit(f, " noalias");
|
ir_write_str_lit(f, " noalias");
|
||||||
}
|
}
|
||||||
if (proc->body != nullptr) {
|
if (proc->body != nullptr) {
|
||||||
if (e->token.string != "" && !is_blank_ident(e->token)) {
|
ir_fprintf(f, " %%_.%td", parameter_index);
|
||||||
ir_write_byte(f, ' ');
|
|
||||||
ir_print_encoded_local(f, e->token.string);
|
|
||||||
} else {
|
|
||||||
ir_fprintf(f, " %%_.param_%td", i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2176,6 +2325,22 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
|
|||||||
ir_write_byte(f, '\n');
|
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) {
|
void print_llvm_ir(irGen *ir) {
|
||||||
irModule *m = &ir->module;
|
irModule *m = &ir->module;
|
||||||
|
|
||||||
@@ -2184,9 +2349,11 @@ void print_llvm_ir(irGen *ir) {
|
|||||||
defer (ir_file_buffer_destroy(f));
|
defer (ir_file_buffer_destroy(f));
|
||||||
|
|
||||||
i32 word_bits = cast(i32)(8*build_context.word_size);
|
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);
|
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") {
|
} else if (build_context.ODIN_OS == "windows") {
|
||||||
ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
|
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) {
|
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_print_encoded_local(f, str_lit("..complex128"));
|
||||||
ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
|
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_print_encoded_local(f, str_lit("..typeid"));
|
||||||
ir_write_str_lit(f, " = type ");
|
ir_write_str_lit(f, " = type ");
|
||||||
ir_print_type(f, m, t_uintptr);
|
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_print_type(f, m, g->entity->type);
|
||||||
ir_write_byte(f, ' ');
|
ir_write_byte(f, ' ');
|
||||||
if (!g->is_foreign) {
|
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);
|
ir_print_value(f, m, g->value, g->entity->type);
|
||||||
} else {
|
} else {
|
||||||
ir_write_string(f, str_lit("zeroinitializer"));
|
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) {
|
for_array(di_index, m->debug_info.entries) {
|
||||||
irDebugInfo *di = m->debug_info.entries[di_index].value;
|
irDebugInfo *di = m->debug_info.entries[di_index].value;
|
||||||
|
GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
|
||||||
ir_fprintf(f, "!%d = ", di->id);
|
ir_fprintf(f, "!%d = ", di->id);
|
||||||
|
|
||||||
switch (di->kind) {
|
switch (di->kind) {
|
||||||
case irDebugInfo_CompileUnit: {
|
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,
|
ir_fprintf(f,
|
||||||
"distinct !DICompileUnit("
|
"distinct !DICompileUnit("
|
||||||
"language: DW_LANG_C_plus_plus" // Is this good enough?
|
"language: DW_LANG_C_plus_plus" // Is this good enough?
|
||||||
|
|||||||
+53
-58
@@ -160,8 +160,9 @@ void usage(String argv0) {
|
|||||||
print_usage_line(0, "Usage:");
|
print_usage_line(0, "Usage:");
|
||||||
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
||||||
print_usage_line(0, "Commands:");
|
print_usage_line(0, "Commands:");
|
||||||
print_usage_line(1, "build compile .odin file as executable");
|
print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
|
||||||
print_usage_line(1, "run compile and run .odin file");
|
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, "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, "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");
|
print_usage_line(1, "docs generate documentation for a .odin file");
|
||||||
@@ -210,9 +211,8 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_Collection,
|
BuildFlag_Collection,
|
||||||
BuildFlag_Define,
|
BuildFlag_Define,
|
||||||
BuildFlag_BuildMode,
|
BuildFlag_BuildMode,
|
||||||
|
BuildFlag_Target,
|
||||||
BuildFlag_Debug,
|
BuildFlag_Debug,
|
||||||
BuildFlag_CrossCompile,
|
|
||||||
BuildFlag_CrossLibDir,
|
|
||||||
BuildFlag_NoBoundsCheck,
|
BuildFlag_NoBoundsCheck,
|
||||||
BuildFlag_NoCRT,
|
BuildFlag_NoCRT,
|
||||||
BuildFlag_UseLLD,
|
BuildFlag_UseLLD,
|
||||||
@@ -298,9 +298,8 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
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_Define, str_lit("define"), BuildFlagParam_String);
|
||||||
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), 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_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_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_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
|
||||||
@@ -447,7 +446,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
path = substring(path, 0, string_extension_position(path));
|
path = substring(path, 0, string_extension_position(path));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
build_context.out_filepath = path;
|
build_context.out_filepath = path_to_full_path(heap_allocator(), path);
|
||||||
} else {
|
} else {
|
||||||
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
|
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
|
||||||
bad_flags = true;
|
bad_flags = true;
|
||||||
@@ -478,33 +477,6 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
build_context.keep_temp_files = true;
|
build_context.keep_temp_files = true;
|
||||||
break;
|
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: {
|
case BuildFlag_Collection: {
|
||||||
GB_ASSERT(value.kind == ExactValue_String);
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
String str = value.value_string;
|
String str = value.value_string;
|
||||||
@@ -623,7 +595,25 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
break;
|
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: {
|
case BuildFlag_BuildMode: {
|
||||||
GB_ASSERT(value.kind == ExactValue_String);
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
@@ -635,7 +625,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str == "dll") {
|
if (str == "dll" || str == "shared") {
|
||||||
build_context.is_dll = true;
|
build_context.is_dll = true;
|
||||||
} else if (str == "exe") {
|
} else if (str == "exe") {
|
||||||
build_context.is_dll = false;
|
build_context.is_dll = false;
|
||||||
@@ -889,8 +879,8 @@ i32 exec_llvm_opt(String output_base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i32 exec_llvm_llc(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
|
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
return system_exec_command_line_app("llvm-llc",
|
return system_exec_command_line_app("llvm-llc",
|
||||||
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
|
||||||
"-o \"%.*s.obj\" "
|
"-o \"%.*s.obj\" "
|
||||||
@@ -903,21 +893,19 @@ i32 exec_llvm_llc(String output_base) {
|
|||||||
LIT(build_context.llc_flags));
|
LIT(build_context.llc_flags));
|
||||||
#else
|
#else
|
||||||
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
|
// 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",
|
return system_exec_command_line_app("llc",
|
||||||
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
|
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
|
||||||
"%.*s "
|
"%.*s "
|
||||||
"%s"
|
"%s%.*s",
|
||||||
"",
|
|
||||||
LIT(output_base),
|
LIT(output_base),
|
||||||
build_context.optimization_level,
|
build_context.optimization_level,
|
||||||
LIT(build_context.llc_flags),
|
LIT(build_context.llc_flags),
|
||||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
|
build_context.cross_compiling ? "-mtriple=" : "",
|
||||||
|
(int) (build_context.cross_compiling ? build_context.target_triplet.len : 0),
|
||||||
|
build_context.target_triplet.text);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int arg_count, char **arg_ptr) {
|
int main(int arg_count, char **arg_ptr) {
|
||||||
if (arg_count < 2) {
|
if (arg_count < 2) {
|
||||||
usage(make_string_c(arg_ptr[0]));
|
usage(make_string_c(arg_ptr[0]));
|
||||||
@@ -1026,7 +1014,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) {
|
if (build_context.word_size == 4) {
|
||||||
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
|
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1121,6 +1109,17 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
return exit_code;
|
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)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
timings_start_section(&timings, str_lit("msvc-link"));
|
timings_start_section(&timings, str_lit("msvc-link"));
|
||||||
|
|
||||||
@@ -1219,7 +1218,7 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
remove_temp_files(output_base);
|
remove_temp_files(output_base);
|
||||||
|
|
||||||
if (run_output) {
|
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
|
#else
|
||||||
timings_start_section(&timings, str_lit("ld-link"));
|
timings_start_section(&timings, str_lit("ld-link"));
|
||||||
@@ -1241,15 +1240,17 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
// This allows you to specify '-f' in a #foreign_system_library,
|
// This allows you to specify '-f' in a #foreign_system_library,
|
||||||
// without having to implement any new syntax specifically for MacOS.
|
// without having to implement any new syntax specifically for MacOS.
|
||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
|
if (string_ends_with(lib, str_lit(".framework"))) {
|
||||||
// framework thingie
|
// 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"))) {
|
} 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
|
// 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));
|
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
|
||||||
} else if (string_ends_with(lib, str_lit(".dylib"))) {
|
} else if (string_ends_with(lib, str_lit(".dylib"))) {
|
||||||
// dynamic lib, relative path to executable
|
// dynamic lib
|
||||||
lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
|
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||||
} else {
|
} else {
|
||||||
// dynamic or static system lib, just link regularly searching system library paths
|
// dynamic or static system lib, just link regularly searching system library paths
|
||||||
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
|
||||||
@@ -1309,11 +1310,7 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
// It probably has to do with including the entire CRT, but
|
// It probably has to do with including the entire CRT, but
|
||||||
// that's quite a complicated issue to solve while remaining distro-agnostic.
|
// 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_.
|
// 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
|
#endif
|
||||||
|
|
||||||
exit_code = system_exec_command_line_app("ld-link",
|
exit_code = system_exec_command_line_app("ld-link",
|
||||||
@@ -1321,7 +1318,6 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
" %s "
|
" %s "
|
||||||
" %.*s "
|
" %.*s "
|
||||||
" %s "
|
" %s "
|
||||||
" %.*s "
|
|
||||||
#if defined(GB_SYSTEM_OSX)
|
#if defined(GB_SYSTEM_OSX)
|
||||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
// 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)
|
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
|
||||||
@@ -1332,11 +1328,9 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
#endif
|
#endif
|
||||||
, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
|
, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
|
||||||
lib_str,
|
lib_str,
|
||||||
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm",
|
"-lc -lm",
|
||||||
LIT(build_context.link_flags),
|
LIT(build_context.link_flags),
|
||||||
link_settings,
|
link_settings);
|
||||||
LIT(cross_compile_lib_dir)
|
|
||||||
);
|
|
||||||
if (exit_code != 0) {
|
if (exit_code != 0) {
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
@@ -1366,9 +1360,10 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
//NOTE(thebirk): This whole thing is a little leaky
|
//NOTE(thebirk): This whole thing is a little leaky
|
||||||
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
|
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
|
||||||
complete_path = path_to_full_path(heap_allocator(), complete_path);
|
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
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
+286
-208
@@ -51,6 +51,7 @@ Token ast_token(Ast *node) {
|
|||||||
case Ast_ReturnStmt: return node->ReturnStmt.token;
|
case Ast_ReturnStmt: return node->ReturnStmt.token;
|
||||||
case Ast_ForStmt: return node->ForStmt.token;
|
case Ast_ForStmt: return node->ForStmt.token;
|
||||||
case Ast_RangeStmt: return node->RangeStmt.token;
|
case Ast_RangeStmt: return node->RangeStmt.token;
|
||||||
|
case Ast_InlineRangeStmt: return node->InlineRangeStmt.inline_token;
|
||||||
case Ast_CaseClause: return node->CaseClause.token;
|
case Ast_CaseClause: return node->CaseClause.token;
|
||||||
case Ast_SwitchStmt: return node->SwitchStmt.token;
|
case Ast_SwitchStmt: return node->SwitchStmt.token;
|
||||||
case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
|
case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
|
||||||
@@ -143,6 +144,7 @@ Ast *clone_ast(Ast *node) {
|
|||||||
case Ast_ProcLit:
|
case Ast_ProcLit:
|
||||||
n->ProcLit.type = clone_ast(n->ProcLit.type);
|
n->ProcLit.type = clone_ast(n->ProcLit.type);
|
||||||
n->ProcLit.body = clone_ast(n->ProcLit.body);
|
n->ProcLit.body = clone_ast(n->ProcLit.body);
|
||||||
|
n->ProcLit.where_clauses = clone_ast_array(n->ProcLit.where_clauses);
|
||||||
break;
|
break;
|
||||||
case Ast_CompoundLit:
|
case Ast_CompoundLit:
|
||||||
n->CompoundLit.type = clone_ast(n->CompoundLit.type);
|
n->CompoundLit.type = clone_ast(n->CompoundLit.type);
|
||||||
@@ -257,6 +259,12 @@ Ast *clone_ast(Ast *node) {
|
|||||||
n->RangeStmt.expr = clone_ast(n->RangeStmt.expr);
|
n->RangeStmt.expr = clone_ast(n->RangeStmt.expr);
|
||||||
n->RangeStmt.body = clone_ast(n->RangeStmt.body);
|
n->RangeStmt.body = clone_ast(n->RangeStmt.body);
|
||||||
break;
|
break;
|
||||||
|
case Ast_InlineRangeStmt:
|
||||||
|
n->InlineRangeStmt.val0 = clone_ast(n->InlineRangeStmt.val0);
|
||||||
|
n->InlineRangeStmt.val1 = clone_ast(n->InlineRangeStmt.val1);
|
||||||
|
n->InlineRangeStmt.expr = clone_ast(n->InlineRangeStmt.expr);
|
||||||
|
n->InlineRangeStmt.body = clone_ast(n->InlineRangeStmt.body);
|
||||||
|
break;
|
||||||
case Ast_CaseClause:
|
case Ast_CaseClause:
|
||||||
n->CaseClause.list = clone_ast_array(n->CaseClause.list);
|
n->CaseClause.list = clone_ast_array(n->CaseClause.list);
|
||||||
n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts);
|
n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts);
|
||||||
@@ -341,10 +349,12 @@ Ast *clone_ast(Ast *node) {
|
|||||||
n->StructType.fields = clone_ast_array(n->StructType.fields);
|
n->StructType.fields = clone_ast_array(n->StructType.fields);
|
||||||
n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params);
|
n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params);
|
||||||
n->StructType.align = clone_ast(n->StructType.align);
|
n->StructType.align = clone_ast(n->StructType.align);
|
||||||
|
n->StructType.where_clauses = clone_ast_array(n->StructType.where_clauses);
|
||||||
break;
|
break;
|
||||||
case Ast_UnionType:
|
case Ast_UnionType:
|
||||||
n->UnionType.variants = clone_ast_array(n->UnionType.variants);
|
n->UnionType.variants = clone_ast_array(n->UnionType.variants);
|
||||||
n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params);
|
n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params);
|
||||||
|
n->UnionType.where_clauses = clone_ast_array(n->UnionType.where_clauses);
|
||||||
break;
|
break;
|
||||||
case Ast_EnumType:
|
case Ast_EnumType:
|
||||||
n->EnumType.base_type = clone_ast(n->EnumType.base_type);
|
n->EnumType.base_type = clone_ast(n->EnumType.base_type);
|
||||||
@@ -417,7 +427,7 @@ void syntax_error(Ast *node, char *fmt, ...) {
|
|||||||
|
|
||||||
bool ast_node_expect(Ast *node, AstKind kind) {
|
bool ast_node_expect(Ast *node, AstKind kind) {
|
||||||
if (node->kind != kind) {
|
if (node->kind != kind) {
|
||||||
error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind]));
|
syntax_error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind]));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -578,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) {
|
|||||||
Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
|
Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_BasicLit);
|
Ast *result = alloc_ast_node(f, Ast_BasicLit);
|
||||||
result->BasicLit.token = basic_lit;
|
result->BasicLit.token = basic_lit;
|
||||||
|
result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -605,11 +616,13 @@ Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<Ast
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags) {
|
Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags, Token where_token, Array<Ast *> const &where_clauses) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_ProcLit);
|
Ast *result = alloc_ast_node(f, Ast_ProcLit);
|
||||||
result->ProcLit.type = type;
|
result->ProcLit.type = type;
|
||||||
result->ProcLit.body = body;
|
result->ProcLit.body = body;
|
||||||
result->ProcLit.tags = tags;
|
result->ProcLit.tags = tags;
|
||||||
|
result->ProcLit.where_token = where_token;
|
||||||
|
result->ProcLit.where_clauses = where_clauses;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,6 +761,18 @@ Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_toke
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast *ast_inline_range_stmt(AstFile *f, Token inline_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) {
|
||||||
|
Ast *result = alloc_ast_node(f, Ast_InlineRangeStmt);
|
||||||
|
result->InlineRangeStmt.inline_token = inline_token;
|
||||||
|
result->InlineRangeStmt.for_token = for_token;
|
||||||
|
result->InlineRangeStmt.val0 = val0;
|
||||||
|
result->InlineRangeStmt.val1 = val1;
|
||||||
|
result->InlineRangeStmt.in_token = in_token;
|
||||||
|
result->InlineRangeStmt.expr = expr;
|
||||||
|
result->InlineRangeStmt.body = body;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) {
|
Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_SwitchStmt);
|
Ast *result = alloc_ast_node(f, Ast_SwitchStmt);
|
||||||
result->SwitchStmt.token = token;
|
result->SwitchStmt.token = token;
|
||||||
@@ -805,13 +830,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags,
|
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Token tag,
|
||||||
CommentGroup *docs, CommentGroup *comment) {
|
CommentGroup *docs, CommentGroup *comment) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_Field);
|
Ast *result = alloc_ast_node(f, Ast_Field);
|
||||||
result->Field.names = names;
|
result->Field.names = names;
|
||||||
result->Field.type = type;
|
result->Field.type = type;
|
||||||
result->Field.default_value = default_value;
|
result->Field.default_value = default_value;
|
||||||
result->Field.flags = flags;
|
result->Field.flags = flags;
|
||||||
|
result->Field.tag = tag;
|
||||||
result->Field.docs = docs;
|
result->Field.docs = docs;
|
||||||
result->Field.comment = comment;
|
result->Field.comment = comment;
|
||||||
return result;
|
return result;
|
||||||
@@ -898,7 +924,8 @@ Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
|
|||||||
|
|
||||||
Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count,
|
Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count,
|
||||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union,
|
Ast *polymorphic_params, bool is_packed, bool is_raw_union,
|
||||||
Ast *align) {
|
Ast *align,
|
||||||
|
Token where_token, Array<Ast *> const &where_clauses) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_StructType);
|
Ast *result = alloc_ast_node(f, Ast_StructType);
|
||||||
result->StructType.token = token;
|
result->StructType.token = token;
|
||||||
result->StructType.fields = fields;
|
result->StructType.fields = fields;
|
||||||
@@ -907,17 +934,22 @@ Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_c
|
|||||||
result->StructType.is_packed = is_packed;
|
result->StructType.is_packed = is_packed;
|
||||||
result->StructType.is_raw_union = is_raw_union;
|
result->StructType.is_raw_union = is_raw_union;
|
||||||
result->StructType.align = align;
|
result->StructType.align = align;
|
||||||
|
result->StructType.where_token = where_token;
|
||||||
|
result->StructType.where_clauses = where_clauses;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil) {
|
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil,
|
||||||
|
Token where_token, Array<Ast *> const &where_clauses) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_UnionType);
|
Ast *result = alloc_ast_node(f, Ast_UnionType);
|
||||||
result->UnionType.token = token;
|
result->UnionType.token = token;
|
||||||
result->UnionType.variants = variants;
|
result->UnionType.variants = variants;
|
||||||
result->UnionType.polymorphic_params = polymorphic_params;
|
result->UnionType.polymorphic_params = polymorphic_params;
|
||||||
result->UnionType.align = align;
|
result->UnionType.align = align;
|
||||||
result->UnionType.no_nil = no_nil;
|
result->UnionType.no_nil = no_nil;
|
||||||
|
result->UnionType.where_token = where_token;
|
||||||
|
result->UnionType.where_clauses = where_clauses;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1118,6 +1150,17 @@ Token advance_token(AstFile *f) {
|
|||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool peek_token_kind(AstFile *f, TokenKind kind) {
|
||||||
|
for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) {
|
||||||
|
Token tok = f->tokens[i];
|
||||||
|
if (kind != Token_Comment && tok.kind == Token_Comment) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return tok.kind == kind;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Token expect_token(AstFile *f, TokenKind kind) {
|
Token expect_token(AstFile *f, TokenKind kind) {
|
||||||
Token prev = f->curr_token;
|
Token prev = f->curr_token;
|
||||||
if (prev.kind != kind) {
|
if (prev.kind != kind) {
|
||||||
@@ -1302,7 +1345,8 @@ bool is_semicolon_optional_for_node(AstFile *f, Ast *s) {
|
|||||||
case Ast_UnionType:
|
case Ast_UnionType:
|
||||||
case Ast_EnumType:
|
case Ast_EnumType:
|
||||||
case Ast_BitFieldType:
|
case Ast_BitFieldType:
|
||||||
return true;
|
// Require semicolon within a procedure body
|
||||||
|
return f->curr_proc == nullptr;
|
||||||
case Ast_ProcLit:
|
case Ast_ProcLit:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -1336,10 +1380,6 @@ void expect_semicolon(AstFile *f, Ast *s) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (f->curr_token.kind) {
|
|
||||||
case Token_EOF:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s != nullptr) {
|
if (s != nullptr) {
|
||||||
if (prev_token.pos.line != f->curr_token.pos.line) {
|
if (prev_token.pos.line != f->curr_token.pos.line) {
|
||||||
@@ -1352,12 +1392,21 @@ void expect_semicolon(AstFile *f, Ast *s) {
|
|||||||
case Token_CloseParen:
|
case Token_CloseParen:
|
||||||
case Token_else:
|
case Token_else:
|
||||||
return;
|
return;
|
||||||
|
case Token_EOF:
|
||||||
|
if (is_semicolon_optional_for_node(f, s)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String node_string = ast_strings[s->kind];
|
String node_string = ast_strings[s->kind];
|
||||||
syntax_error(prev_token, "Expected ';' after %.*s, got %.*s",
|
syntax_error(prev_token, "Expected ';' after %.*s, got %.*s",
|
||||||
LIT(node_string), LIT(token_strings[prev_token.kind]));
|
LIT(node_string), LIT(token_strings[f->curr_token.kind]));
|
||||||
} else {
|
} else {
|
||||||
|
switch (f->curr_token.kind) {
|
||||||
|
case Token_EOF:
|
||||||
|
return;
|
||||||
|
}
|
||||||
syntax_error(prev_token, "Expected ';'");
|
syntax_error(prev_token, "Expected ';'");
|
||||||
}
|
}
|
||||||
fix_advance_to_next_stmt(f);
|
fix_advance_to_next_stmt(f);
|
||||||
@@ -1461,8 +1510,11 @@ Ast *parse_value(AstFile *f) {
|
|||||||
if (f->curr_token.kind == Token_OpenBrace) {
|
if (f->curr_token.kind == Token_OpenBrace) {
|
||||||
return parse_literal_value(f, nullptr);
|
return parse_literal_value(f, nullptr);
|
||||||
}
|
}
|
||||||
|
Ast *value;
|
||||||
Ast *value = parse_expr(f, false);
|
bool prev_allow_range = f->allow_range;
|
||||||
|
f->allow_range = true;
|
||||||
|
value = parse_expr(f, false);
|
||||||
|
f->allow_range = prev_allow_range;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1614,7 +1666,7 @@ void check_polymorphic_params_for_type(AstFile *f, Ast *polymorphic_params, Toke
|
|||||||
for_array(i, field->Field.names) {
|
for_array(i, field->Field.names) {
|
||||||
Ast *name = field->Field.names[i];
|
Ast *name = field->Field.names[i];
|
||||||
if (name->kind == Ast_PolyType) {
|
if (name->kind == Ast_PolyType) {
|
||||||
error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string));
|
syntax_error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string));
|
||||||
return; // TODO(bill): Err multiple times or just the once?
|
return; // TODO(bill): Err multiple times or just the once?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1687,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
operand = ast_bad_expr(f, token, f->curr_token);
|
operand = ast_bad_expr(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
operand->stmt_state_flags |= StmtStateFlag_no_deferred;
|
operand->stmt_state_flags |= StmtStateFlag_no_deferred;
|
||||||
} */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string);
|
} */ else if (name.string == "file") {
|
||||||
|
return ast_basic_directive(f, token, name.string);
|
||||||
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
|
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
|
||||||
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
|
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
|
||||||
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
|
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
|
||||||
@@ -1796,15 +1849,41 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ast *type = parse_proc_type(f, token);
|
Ast *type = parse_proc_type(f, token);
|
||||||
|
Token where_token = {};
|
||||||
|
Array<Ast *> where_clauses = {};
|
||||||
|
u64 tags = 0;
|
||||||
|
|
||||||
|
if (f->curr_token.kind == Token_where) {
|
||||||
|
where_token = expect_token(f, Token_where);
|
||||||
|
isize prev_level = f->expr_level;
|
||||||
|
f->expr_level = -1;
|
||||||
|
where_clauses = parse_rhs_expr_list(f);
|
||||||
|
f->expr_level = prev_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_proc_tags(f, &tags);
|
||||||
|
if ((tags & ProcTag_require_results) != 0) {
|
||||||
|
syntax_error(f->curr_token, "#require_results has now been replaced as an attribute @(require_results) on the declaration");
|
||||||
|
tags &= ~ProcTag_require_results;
|
||||||
|
}
|
||||||
|
GB_ASSERT(type->kind == Ast_ProcType);
|
||||||
|
type->ProcType.tags = tags;
|
||||||
|
|
||||||
if (f->allow_type && f->expr_level < 0) {
|
if (f->allow_type && f->expr_level < 0) {
|
||||||
|
if (tags != 0) {
|
||||||
|
syntax_error(token, "A procedure type cannot have suffix tags");
|
||||||
|
}
|
||||||
|
if (where_token.kind != Token_Invalid) {
|
||||||
|
syntax_error(where_token, "'where' clauses are not allowed on procedure types");
|
||||||
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 tags = type->ProcType.tags;
|
|
||||||
|
|
||||||
if (allow_token(f, Token_Undef)) {
|
if (allow_token(f, Token_Undef)) {
|
||||||
return ast_proc_lit(f, type, nullptr, tags);
|
if (where_token.kind != Token_Invalid) {
|
||||||
|
syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)");
|
||||||
|
}
|
||||||
|
return ast_proc_lit(f, type, nullptr, tags, where_token, where_clauses);
|
||||||
} else if (f->curr_token.kind == Token_OpenBrace) {
|
} else if (f->curr_token.kind == Token_OpenBrace) {
|
||||||
Ast *curr_proc = f->curr_proc;
|
Ast *curr_proc = f->curr_proc;
|
||||||
Ast *body = nullptr;
|
Ast *body = nullptr;
|
||||||
@@ -1812,7 +1891,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
body = parse_body(f);
|
body = parse_body(f);
|
||||||
f->curr_proc = curr_proc;
|
f->curr_proc = curr_proc;
|
||||||
|
|
||||||
return ast_proc_lit(f, type, body, tags);
|
return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
|
||||||
} else if (allow_token(f, Token_do)) {
|
} else if (allow_token(f, Token_do)) {
|
||||||
Ast *curr_proc = f->curr_proc;
|
Ast *curr_proc = f->curr_proc;
|
||||||
Ast *body = nullptr;
|
Ast *body = nullptr;
|
||||||
@@ -1820,11 +1899,14 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
body = convert_stmt_to_body(f, parse_stmt(f));
|
body = convert_stmt_to_body(f, parse_stmt(f));
|
||||||
f->curr_proc = curr_proc;
|
f->curr_proc = curr_proc;
|
||||||
|
|
||||||
return ast_proc_lit(f, type, body, tags);
|
return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags != 0) {
|
if (tags != 0) {
|
||||||
syntax_error(token, "A procedure type cannot have tags");
|
syntax_error(token, "A procedure type cannot have suffix tags");
|
||||||
|
}
|
||||||
|
if (where_token.kind != Token_Invalid) {
|
||||||
|
syntax_error(where_token, "'where' clauses are not allowed on procedure types");
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
@@ -1847,10 +1929,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
case Token_typeid: {
|
case Token_typeid: {
|
||||||
Token token = expect_token(f, Token_typeid);
|
Token token = expect_token(f, Token_typeid);
|
||||||
// Ast *specialization = nullptr;
|
|
||||||
// if (allow_token(f, Token_Quo)) {
|
|
||||||
// specialization = parse_type(f);
|
|
||||||
// }
|
|
||||||
return ast_typeid_type(f, token, nullptr);
|
return ast_typeid_type(f, token, nullptr);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -1952,6 +2030,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
syntax_error(token, "'#raw_union' cannot also be '#packed'");
|
syntax_error(token, "'#raw_union' cannot also be '#packed'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token where_token = {};
|
||||||
|
Array<Ast *> where_clauses = {};
|
||||||
|
|
||||||
|
if (f->curr_token.kind == Token_where) {
|
||||||
|
where_token = expect_token(f, Token_where);
|
||||||
|
isize prev_level = f->expr_level;
|
||||||
|
f->expr_level = -1;
|
||||||
|
where_clauses = parse_rhs_expr_list(f);
|
||||||
|
f->expr_level = prev_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
Token open = expect_token_after(f, Token_OpenBrace, "struct");
|
||||||
|
|
||||||
isize name_count = 0;
|
isize name_count = 0;
|
||||||
@@ -1964,7 +2054,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
decls = fields->FieldList.list;
|
decls = fields->FieldList.list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align);
|
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align, where_token, where_clauses);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Token_union: {
|
case Token_union: {
|
||||||
@@ -2005,6 +2095,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token where_token = {};
|
||||||
|
Array<Ast *> where_clauses = {};
|
||||||
|
|
||||||
|
if (f->curr_token.kind == Token_where) {
|
||||||
|
where_token = expect_token(f, Token_where);
|
||||||
|
isize prev_level = f->expr_level;
|
||||||
|
f->expr_level = -1;
|
||||||
|
where_clauses = parse_rhs_expr_list(f);
|
||||||
|
f->expr_level = prev_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Token open = expect_token_after(f, Token_OpenBrace, "union");
|
Token open = expect_token_after(f, Token_OpenBrace, "union");
|
||||||
|
|
||||||
while (f->curr_token.kind != Token_CloseBrace &&
|
while (f->curr_token.kind != Token_CloseBrace &&
|
||||||
@@ -2020,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
Token close = expect_token(f, Token_CloseBrace);
|
Token close = expect_token(f, Token_CloseBrace);
|
||||||
|
|
||||||
return ast_union_type(f, token, variants, polymorphic_params, align, no_nil);
|
return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, where_token, where_clauses);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Token_enum: {
|
case Token_enum: {
|
||||||
@@ -2091,7 +2193,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
bool prev_allow_range = f->allow_range;
|
bool prev_allow_range = f->allow_range;
|
||||||
f->allow_range = true;
|
f->allow_range = true;
|
||||||
elem = parse_expr(f, false);
|
elem = parse_expr(f, true);
|
||||||
f->allow_range = prev_allow_range;
|
f->allow_range = prev_allow_range;
|
||||||
if (allow_token(f, Token_Semicolon)) {
|
if (allow_token(f, Token_Semicolon)) {
|
||||||
underlying = parse_type(f);
|
underlying = parse_type(f);
|
||||||
@@ -2383,17 +2485,18 @@ i32 token_precedence(AstFile *f, TokenKind t) {
|
|||||||
case Token_LtEq:
|
case Token_LtEq:
|
||||||
case Token_GtEq:
|
case Token_GtEq:
|
||||||
return 5;
|
return 5;
|
||||||
|
|
||||||
case Token_in:
|
case Token_in:
|
||||||
case Token_notin:
|
case Token_notin:
|
||||||
if (f->expr_level >= 0 || f->allow_in_expr) {
|
if (f->expr_level < 0 && !f->allow_in_expr) {
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
/*fallthrough*/
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
case Token_Sub:
|
case Token_Sub:
|
||||||
case Token_Or:
|
case Token_Or:
|
||||||
case Token_Xor:
|
case Token_Xor:
|
||||||
return 7;
|
return 6;
|
||||||
case Token_Mul:
|
case Token_Mul:
|
||||||
case Token_Quo:
|
case Token_Quo:
|
||||||
case Token_Mod:
|
case Token_Mod:
|
||||||
@@ -2402,7 +2505,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
|
|||||||
case Token_AndNot:
|
case Token_AndNot:
|
||||||
case Token_Shl:
|
case Token_Shl:
|
||||||
case Token_Shr:
|
case Token_Shr:
|
||||||
return 8;
|
return 7;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2649,7 +2752,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) {
|
|||||||
allow_token(f, Token_in);
|
allow_token(f, Token_in);
|
||||||
bool prev_allow_range = f->allow_range;
|
bool prev_allow_range = f->allow_range;
|
||||||
f->allow_range = true;
|
f->allow_range = true;
|
||||||
Ast *expr = parse_expr(f, false);
|
Ast *expr = parse_expr(f, true);
|
||||||
f->allow_range = prev_allow_range;
|
f->allow_range = prev_allow_range;
|
||||||
|
|
||||||
auto rhs = array_make<Ast *>(heap_allocator(), 0, 1);
|
auto rhs = array_make<Ast *>(heap_allocator(), 0, 1);
|
||||||
@@ -2740,7 +2843,8 @@ Ast *parse_results(AstFile *f, bool *diverging) {
|
|||||||
Array<Ast *> empty_names = {};
|
Array<Ast *> empty_names = {};
|
||||||
auto list = array_make<Ast *>(heap_allocator(), 0, 1);
|
auto list = array_make<Ast *>(heap_allocator(), 0, 1);
|
||||||
Ast *type = parse_type(f);
|
Ast *type = parse_type(f);
|
||||||
array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr));
|
Token tag = {};
|
||||||
|
array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr));
|
||||||
return ast_field_list(f, begin_token, list);
|
return ast_field_list(f, begin_token, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2795,8 +2899,6 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) {
|
|||||||
results = parse_results(f, &diverging);
|
results = parse_results(f, &diverging);
|
||||||
|
|
||||||
u64 tags = 0;
|
u64 tags = 0;
|
||||||
parse_proc_tags(f, &tags);
|
|
||||||
|
|
||||||
bool is_generic = false;
|
bool is_generic = false;
|
||||||
|
|
||||||
for_array(i, params->FieldList.list) {
|
for_array(i, params->FieldList.list) {
|
||||||
@@ -3095,6 +3197,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
|
|
||||||
Ast *type = nullptr;
|
Ast *type = nullptr;
|
||||||
Ast *default_value = nullptr;
|
Ast *default_value = nullptr;
|
||||||
|
Token tag = {};
|
||||||
|
|
||||||
expect_token_after(f, Token_Colon, "field list");
|
expect_token_after(f, Token_Colon, "field list");
|
||||||
if (f->curr_token.kind != Token_Eq) {
|
if (f->curr_token.kind != Token_Eq) {
|
||||||
@@ -3132,16 +3235,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type != nullptr && default_value == nullptr) {
|
||||||
|
if (f->curr_token.kind == Token_String) {
|
||||||
|
tag = expect_token(f, Token_String);
|
||||||
|
if ((allowed_flags & FieldFlag_Tags) == 0) {
|
||||||
|
syntax_error(tag, "Field tags are only allowed within structures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parse_expect_field_separator(f, type);
|
parse_expect_field_separator(f, type);
|
||||||
Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
|
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
|
|
||||||
|
|
||||||
while (f->curr_token.kind != follow &&
|
while (f->curr_token.kind != follow &&
|
||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
|
|
||||||
u32 set_flags = parse_field_prefixes(f);
|
u32 set_flags = parse_field_prefixes(f);
|
||||||
|
Token tag = {};
|
||||||
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
|
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
|
||||||
if (names.count == 0) {
|
if (names.count == 0) {
|
||||||
syntax_error(f->curr_token, "Empty field declaration");
|
syntax_error(f->curr_token, "Empty field declaration");
|
||||||
@@ -3184,9 +3296,18 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type != nullptr && default_value == nullptr) {
|
||||||
|
if (f->curr_token.kind == Token_String) {
|
||||||
|
tag = expect_token(f, Token_String);
|
||||||
|
if ((allowed_flags & FieldFlag_Tags) == 0) {
|
||||||
|
syntax_error(tag, "Field tags are only allowed within structures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ok = parse_expect_field_separator(f, param);
|
bool ok = parse_expect_field_separator(f, param);
|
||||||
Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
|
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -3210,8 +3331,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
token.pos = ast_token(type).pos;
|
token.pos = ast_token(type).pos;
|
||||||
names[0] = ast_ident(f, token);
|
names[0] = ast_ident(f, token);
|
||||||
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
|
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
|
||||||
|
Token tag = {};
|
||||||
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
|
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3758,9 +3879,55 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
switch (token.kind) {
|
switch (token.kind) {
|
||||||
// Operands
|
// Operands
|
||||||
case Token_context: // Also allows for `context =`
|
|
||||||
case Token_inline:
|
case Token_inline:
|
||||||
|
if (peek_token_kind(f, Token_for)) {
|
||||||
|
Token inline_token = expect_token(f, Token_inline);
|
||||||
|
Token for_token = expect_token(f, Token_for);
|
||||||
|
Ast *val0 = nullptr;
|
||||||
|
Ast *val1 = nullptr;
|
||||||
|
Token in_token = {};
|
||||||
|
Ast *expr = nullptr;
|
||||||
|
Ast *body = nullptr;
|
||||||
|
|
||||||
|
bool bad_stmt = false;
|
||||||
|
|
||||||
|
if (f->curr_token.kind != Token_in) {
|
||||||
|
Array<Ast *> idents = parse_ident_list(f, false);
|
||||||
|
switch (idents.count) {
|
||||||
|
case 1:
|
||||||
|
val0 = idents[0];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
val0 = idents[0];
|
||||||
|
val1 = idents[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
syntax_error(for_token, "Expected either 1 or 2 identifiers");
|
||||||
|
bad_stmt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in_token = expect_token(f, Token_in);
|
||||||
|
|
||||||
|
bool prev_allow_range = f->allow_range;
|
||||||
|
f->allow_range = true;
|
||||||
|
expr = parse_expr(f, true);
|
||||||
|
f->allow_range = prev_allow_range;
|
||||||
|
|
||||||
|
if (allow_token(f, Token_do)) {
|
||||||
|
body = convert_stmt_to_body(f, parse_stmt(f));
|
||||||
|
} else {
|
||||||
|
body = parse_block_stmt(f, false);
|
||||||
|
}
|
||||||
|
if (bad_stmt) {
|
||||||
|
return ast_bad_stmt(f, inline_token, f->curr_token);
|
||||||
|
}
|
||||||
|
return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body);
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
case Token_no_inline:
|
case Token_no_inline:
|
||||||
|
case Token_context: // Also allows for `context =`
|
||||||
|
case Token_proc:
|
||||||
case Token_Ident:
|
case Token_Ident:
|
||||||
case Token_Integer:
|
case Token_Integer:
|
||||||
case Token_Float:
|
case Token_Float:
|
||||||
@@ -3808,34 +3975,6 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case Token_static: {
|
|
||||||
// CommentGroup *docs = f->lead_comment;
|
|
||||||
// Token token = expect_token(f, Token_static);
|
|
||||||
|
|
||||||
// Ast *decl = nullptr;
|
|
||||||
// Array<Ast *> list = parse_lhs_expr_list(f);
|
|
||||||
// if (list.count == 0) {
|
|
||||||
// syntax_error(token, "Illegal use of 'static' statement");
|
|
||||||
// expect_semicolon(f, nullptr);
|
|
||||||
// return ast_bad_stmt(f, token, f->curr_token);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// expect_token_after(f, Token_Colon, "identifier list");
|
|
||||||
// decl = parse_value_decl(f, list, docs);
|
|
||||||
|
|
||||||
// if (decl != nullptr && decl->kind == Ast_ValueDecl) {
|
|
||||||
// if (decl->ValueDecl.is_mutable) {
|
|
||||||
// decl->ValueDecl.is_static = true;
|
|
||||||
// } else {
|
|
||||||
// error(token, "'static' may only be currently used with variable declaration");
|
|
||||||
// }
|
|
||||||
// return decl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// syntax_error(token, "Illegal use of 'static' statement");
|
|
||||||
// return ast_bad_stmt(f, token, f->curr_token);
|
|
||||||
// } break;
|
|
||||||
|
|
||||||
case Token_using: {
|
case Token_using: {
|
||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
Token token = expect_token(f, Token_using);
|
Token token = expect_token(f, Token_using);
|
||||||
@@ -3909,12 +4048,10 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
} else if (tag == "assert") {
|
} else if (tag == "assert") {
|
||||||
Ast *t = ast_basic_directive(f, hash_token, tag);
|
Ast *t = ast_basic_directive(f, hash_token, tag);
|
||||||
return ast_expr_stmt(f, parse_call_expr(f, t));
|
return ast_expr_stmt(f, parse_call_expr(f, t));
|
||||||
} /* else if (name.string == "no_deferred") {
|
} else if (tag == "panic") {
|
||||||
s = parse_stmt(f);
|
Ast *t = ast_basic_directive(f, hash_token, tag);
|
||||||
s->stmt_state_flags |= StmtStateFlag_no_deferred;
|
return ast_expr_stmt(f, parse_call_expr(f, t));
|
||||||
} */
|
} else if (tag == "include") {
|
||||||
|
|
||||||
if (tag == "include") {
|
|
||||||
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
|
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
|
||||||
s = ast_bad_stmt(f, token, f->curr_token);
|
s = ast_bad_stmt(f, token, f->curr_token);
|
||||||
} else {
|
} else {
|
||||||
@@ -4037,7 +4174,6 @@ bool init_parser(Parser *p) {
|
|||||||
map_init(&p->package_map, heap_allocator());
|
map_init(&p->package_map, heap_allocator());
|
||||||
array_init(&p->packages, heap_allocator());
|
array_init(&p->packages, heap_allocator());
|
||||||
array_init(&p->package_imports, heap_allocator());
|
array_init(&p->package_imports, heap_allocator());
|
||||||
array_init(&p->files_to_process, heap_allocator());
|
|
||||||
gb_mutex_init(&p->file_add_mutex);
|
gb_mutex_init(&p->file_add_mutex);
|
||||||
gb_mutex_init(&p->file_decl_mutex);
|
gb_mutex_init(&p->file_decl_mutex);
|
||||||
return true;
|
return true;
|
||||||
@@ -4060,7 +4196,6 @@ void destroy_parser(Parser *p) {
|
|||||||
#endif
|
#endif
|
||||||
array_free(&p->packages);
|
array_free(&p->packages);
|
||||||
array_free(&p->package_imports);
|
array_free(&p->package_imports);
|
||||||
array_free(&p->files_to_process);
|
|
||||||
string_set_destroy(&p->imported_files);
|
string_set_destroy(&p->imported_files);
|
||||||
map_destroy(&p->package_map);
|
map_destroy(&p->package_map);
|
||||||
gb_mutex_destroy(&p->file_add_mutex);
|
gb_mutex_destroy(&p->file_add_mutex);
|
||||||
@@ -4077,19 +4212,32 @@ void parser_add_package(Parser *p, AstPackage *pkg) {
|
|||||||
if (found) {
|
if (found) {
|
||||||
GB_ASSERT(pkg->files.count > 0);
|
GB_ASSERT(pkg->files.count > 0);
|
||||||
AstFile *f = pkg->files[0];
|
AstFile *f = pkg->files[0];
|
||||||
error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name));
|
syntax_error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name));
|
||||||
GB_ASSERT((*found)->files.count > 0);
|
GB_ASSERT((*found)->files.count > 0);
|
||||||
TokenPos pos = (*found)->files[0]->package_token.pos;
|
TokenPos pos = (*found)->files[0]->package_token.pos;
|
||||||
gb_printf_err("\tpreviously declared at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column);
|
error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
|
||||||
} else {
|
} else {
|
||||||
map_set(&p->package_map, key, pkg);
|
map_set(&p->package_map, key, pkg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file);
|
||||||
|
|
||||||
|
WORKER_TASK_PROC(parser_worker_proc) {
|
||||||
|
ParserWorkerData *wd = cast(ParserWorkerData *)data;
|
||||||
|
ParseFileError err = process_imported_file(wd->parser, wd->imported_file);
|
||||||
|
return cast(isize)err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
|
void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
|
||||||
ImportedFile f = {pkg, fi, pos, p->files_to_process.count};
|
// TODO(bill): Use a better allocator
|
||||||
array_add(&p->files_to_process, f);
|
ImportedFile f = {pkg, fi, pos, p->file_to_process_count++};
|
||||||
|
auto wd = gb_alloc_item(heap_allocator(), ParserWorkerData);
|
||||||
|
wd->parser = p;
|
||||||
|
wd->imported_file = f;
|
||||||
|
thread_pool_add_task(&parser_thread_pool, parser_worker_proc, wd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4140,22 +4288,22 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path,
|
|||||||
|
|
||||||
switch (rd_err) {
|
switch (rd_err) {
|
||||||
case ReadDirectory_InvalidPath:
|
case ReadDirectory_InvalidPath:
|
||||||
error(pos, "Invalid path: %.*s", LIT(rel_path));
|
syntax_error(pos, "Invalid path: %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
case ReadDirectory_NotExists:
|
case ReadDirectory_NotExists:
|
||||||
error(pos, "Path does not exist: %.*s", LIT(rel_path));
|
syntax_error(pos, "Path does not exist: %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
case ReadDirectory_Permission:
|
case ReadDirectory_Permission:
|
||||||
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
case ReadDirectory_NotDir:
|
case ReadDirectory_NotDir:
|
||||||
error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
|
syntax_error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
case ReadDirectory_Empty:
|
case ReadDirectory_Empty:
|
||||||
error(pos, "Empty directory: %.*s", LIT(rel_path));
|
syntax_error(pos, "Empty directory: %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
case ReadDirectory_Unknown:
|
case ReadDirectory_Unknown:
|
||||||
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4257,7 +4405,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
|
|||||||
|
|
||||||
String file_str = {};
|
String file_str = {};
|
||||||
if (colon_pos == 0) {
|
if (colon_pos == 0) {
|
||||||
error(node, "Expected a collection name");
|
syntax_error(node, "Expected a collection name");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4272,32 +4420,19 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
|
|||||||
if (has_windows_drive) {
|
if (has_windows_drive) {
|
||||||
String sub_file_path = substring(file_str, 3, file_str.len);
|
String sub_file_path = substring(file_str, 3, file_str.len);
|
||||||
if (!is_import_path_valid(sub_file_path)) {
|
if (!is_import_path_valid(sub_file_path)) {
|
||||||
error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!is_import_path_valid(file_str)) {
|
} else if (!is_import_path_valid(file_str)) {
|
||||||
error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (is_package_name_reserved(file_str)) {
|
|
||||||
*path = file_str;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_mutex) gb_mutex_lock(file_mutex);
|
|
||||||
defer (if (file_mutex) gb_mutex_unlock(file_mutex));
|
|
||||||
|
|
||||||
|
|
||||||
if (node->kind == Ast_ForeignImportDecl) {
|
|
||||||
node->ForeignImportDecl.collection_name = collection_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collection_name.len > 0) {
|
if (collection_name.len > 0) {
|
||||||
if (collection_name == "system") {
|
if (collection_name == "system") {
|
||||||
if (node->kind != Ast_ForeignImportDecl) {
|
if (node->kind != Ast_ForeignImportDecl) {
|
||||||
error(node, "The library collection 'system' is restrict for 'foreign_library'");
|
syntax_error(node, "The library collection 'system' is restrict for 'foreign_library'");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
*path = file_str;
|
*path = file_str;
|
||||||
@@ -4305,7 +4440,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
|
|||||||
}
|
}
|
||||||
} else if (!find_library_collection_path(collection_name, &base_dir)) {
|
} else if (!find_library_collection_path(collection_name, &base_dir)) {
|
||||||
// NOTE(bill): It's a naughty name
|
// NOTE(bill): It's a naughty name
|
||||||
error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
|
syntax_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -4324,6 +4459,20 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_package_name_reserved(file_str)) {
|
||||||
|
*path = file_str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_mutex) gb_mutex_lock(file_mutex);
|
||||||
|
defer (if (file_mutex) gb_mutex_unlock(file_mutex));
|
||||||
|
|
||||||
|
|
||||||
|
if (node->kind == Ast_ForeignImportDecl) {
|
||||||
|
node->ForeignImportDecl.collection_name = collection_name;
|
||||||
|
}
|
||||||
|
|
||||||
if (has_windows_drive) {
|
if (has_windows_drive) {
|
||||||
*path = file_str;
|
*path = file_str;
|
||||||
} else {
|
} else {
|
||||||
@@ -4412,7 +4561,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *>
|
|||||||
array_add(&fl->fullpaths, fullpath);
|
array_add(&fl->fullpaths, fullpath);
|
||||||
}
|
}
|
||||||
if (fl->fullpaths.count == 0) {
|
if (fl->fullpaths.count == 0) {
|
||||||
error(decls[i], "No foreign paths found");
|
syntax_error(decls[i], "No foreign paths found");
|
||||||
decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
|
decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -4461,7 +4610,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
|
|||||||
is_notted = true;
|
is_notted = true;
|
||||||
p = substring(p, 1, p.len);
|
p = substring(p, 1, p.len);
|
||||||
if (p.len == 0) {
|
if (p.len == 0) {
|
||||||
error(token_for_pos, "Expected a build platform after '!'");
|
syntax_error(token_for_pos, "Expected a build platform after '!'");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4490,7 +4639,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (os == TargetOs_Invalid && arch == TargetArch_Invalid) {
|
if (os == TargetOs_Invalid && arch == TargetArch_Invalid) {
|
||||||
error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p));
|
syntax_error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4536,11 +4685,11 @@ bool parse_file(Parser *p, AstFile *f) {
|
|||||||
Token package_name = expect_token_after(f, Token_Ident, "package");
|
Token package_name = expect_token_after(f, Token_Ident, "package");
|
||||||
if (package_name.kind == Token_Ident) {
|
if (package_name.kind == Token_Ident) {
|
||||||
if (package_name.string == "_") {
|
if (package_name.string == "_") {
|
||||||
error(package_name, "Invalid package name '_'");
|
syntax_error(package_name, "Invalid package name '_'");
|
||||||
} else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") {
|
} else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") {
|
||||||
error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
|
syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
|
||||||
} else if (is_package_name_reserved(package_name.string)) {
|
} else if (is_package_name_reserved(package_name.string)) {
|
||||||
error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
|
syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f->package_name = package_name.string;
|
f->package_name = package_name.string;
|
||||||
@@ -4590,9 +4739,9 @@ bool parse_file(Parser *p, AstFile *f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) {
|
ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file) {
|
||||||
AstPackage *pkg = imported_file.pkg;
|
AstPackage *pkg = imported_file.pkg;
|
||||||
FileInfo *fi = &imported_file.fi;
|
FileInfo const *fi = &imported_file.fi;
|
||||||
TokenPos pos = imported_file.pos;
|
TokenPos pos = imported_file.pos;
|
||||||
|
|
||||||
AstFile *file = gb_alloc_item(heap_allocator(), AstFile);
|
AstFile *file = gb_alloc_item(heap_allocator(), AstFile);
|
||||||
@@ -4607,38 +4756,35 @@ ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) {
|
|||||||
if (err != ParseFile_None) {
|
if (err != ParseFile_None) {
|
||||||
if (err == ParseFile_EmptyFile) {
|
if (err == ParseFile_EmptyFile) {
|
||||||
if (fi->fullpath == p->init_fullpath) {
|
if (fi->fullpath == p->init_fullpath) {
|
||||||
error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath));
|
syntax_error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath));
|
||||||
gb_exit(1);
|
gb_exit(1);
|
||||||
}
|
}
|
||||||
goto skip;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case ParseFile_WrongExtension:
|
case ParseFile_WrongExtension:
|
||||||
error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name));
|
syntax_error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_InvalidFile:
|
case ParseFile_InvalidFile:
|
||||||
error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name));
|
syntax_error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_Permission:
|
case ParseFile_Permission:
|
||||||
error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
|
syntax_error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_NotFound:
|
case ParseFile_NotFound:
|
||||||
error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath));
|
syntax_error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath));
|
||||||
break;
|
break;
|
||||||
case ParseFile_InvalidToken:
|
case ParseFile_InvalidToken:
|
||||||
error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name));
|
syntax_error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
case ParseFile_EmptyFile:
|
case ParseFile_EmptyFile:
|
||||||
error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name));
|
syntax_error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
skip:
|
|
||||||
if (parse_file(p, file)) {
|
if (parse_file(p, file)) {
|
||||||
gb_mutex_lock(&p->file_add_mutex);
|
gb_mutex_lock(&p->file_add_mutex);
|
||||||
defer (gb_mutex_unlock(&p->file_add_mutex));
|
defer (gb_mutex_unlock(&p->file_add_mutex));
|
||||||
@@ -4648,42 +4794,33 @@ skip:
|
|||||||
if (pkg->name.len == 0) {
|
if (pkg->name.len == 0) {
|
||||||
pkg->name = file->package_name;
|
pkg->name = file->package_name;
|
||||||
} else if (file->tokens.count > 0 && pkg->name != file->package_name) {
|
} else if (file->tokens.count > 0 && pkg->name != file->package_name) {
|
||||||
error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name));
|
syntax_error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
p->total_line_count += file->tokenizer.line_count;
|
p->total_line_count += file->tokenizer.line_count;
|
||||||
p->total_token_count += file->tokens.count;
|
p->total_token_count += file->tokens.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseFile_None;
|
return ParseFile_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GB_THREAD_PROC(parse_worker_file_proc) {
|
|
||||||
if (thread == nullptr) return 0;
|
|
||||||
auto *p = cast(Parser *)thread->user_data;
|
|
||||||
isize index = thread->user_index;
|
|
||||||
gb_mutex_lock(&p->file_add_mutex);
|
|
||||||
auto file_to_process = p->files_to_process[index];
|
|
||||||
gb_mutex_unlock(&p->file_add_mutex);
|
|
||||||
ParseFileError err = process_imported_file(p, file_to_process);
|
|
||||||
return cast(isize)err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseFileError parse_packages(Parser *p, String init_filename) {
|
ParseFileError parse_packages(Parser *p, String init_filename) {
|
||||||
GB_ASSERT(init_filename.text[init_filename.len] == 0);
|
GB_ASSERT(init_filename.text[init_filename.len] == 0);
|
||||||
|
|
||||||
// char *fullpath_str = gb_path_get_full_name(heap_allocator(), cast(char const *)&init_filename[0]);
|
isize thread_count = gb_max(build_context.thread_count, 1);
|
||||||
// String init_fullpath = string_trim_whitespace(make_string_c(fullpath_str));
|
isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work
|
||||||
|
thread_pool_init(&parser_thread_pool, heap_allocator(), worker_count, "ParserWork");
|
||||||
|
|
||||||
String init_fullpath = path_to_full_path(heap_allocator(), init_filename);
|
String init_fullpath = path_to_full_path(heap_allocator(), init_filename);
|
||||||
if (!path_is_directory(init_fullpath)) {
|
if (!path_is_directory(init_fullpath)) {
|
||||||
String const ext = str_lit(".odin");
|
String const ext = str_lit(".odin");
|
||||||
if (!string_ends_with(init_fullpath, ext)) {
|
if (!string_ends_with(init_fullpath, ext)) {
|
||||||
gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
|
error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
|
||||||
return ParseFile_WrongExtension;
|
return ParseFile_WrongExtension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TokenPos init_pos = {};
|
TokenPos init_pos = {};
|
||||||
if (!build_context.generate_docs) {
|
if (!build_context.generate_docs) {
|
||||||
String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
|
String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
|
||||||
@@ -4693,76 +4830,17 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
|
|||||||
try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init);
|
try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init);
|
||||||
p->init_fullpath = init_fullpath;
|
p->init_fullpath = init_fullpath;
|
||||||
|
|
||||||
#if 1
|
thread_pool_start(&parser_thread_pool);
|
||||||
isize thread_count = gb_max(build_context.thread_count, 1);
|
thread_pool_wait_to_process(&parser_thread_pool);
|
||||||
if (thread_count > 1) {
|
|
||||||
isize volatile curr_import_index = 0;
|
|
||||||
isize initial_file_count = p->files_to_process.count;
|
|
||||||
// NOTE(bill): Make sure that these are in parsed in this order
|
|
||||||
for (isize i = 0; i < initial_file_count; i++) {
|
|
||||||
ParseFileError err = process_imported_file(p, p->files_to_process[i]);
|
|
||||||
if (err != ParseFile_None) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
curr_import_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto worker_threads = array_make<gbThread>(heap_allocator(), thread_count);
|
// NOTE(bill): Get the last error and use that
|
||||||
defer (array_free(&worker_threads));
|
for (isize i = parser_thread_pool.task_tail-1; i >= 0; i--) {
|
||||||
|
WorkerTask *task = &parser_thread_pool.tasks[i];
|
||||||
for_array(i, worker_threads) {
|
ParseFileError err = cast(ParseFileError)task->result;
|
||||||
gbThread *t = &worker_threads[i];
|
|
||||||
gb_thread_init(t);
|
|
||||||
}
|
|
||||||
defer (for_array(i, worker_threads) {
|
|
||||||
gb_thread_destroy(&worker_threads[i]);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto errors = array_make<ParseFileError>(heap_allocator(), 0, 16);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
bool are_any_alive = false;
|
|
||||||
for_array(i, worker_threads) {
|
|
||||||
gbThread *t = &worker_threads[i];
|
|
||||||
if (gb_thread_is_running(t)) {
|
|
||||||
are_any_alive = true;
|
|
||||||
} else if (curr_import_index < p->files_to_process.count) {
|
|
||||||
auto curr_err = cast(ParseFileError)t->return_value;
|
|
||||||
if (curr_err != ParseFile_None) {
|
|
||||||
array_add(&errors, curr_err);
|
|
||||||
} else {
|
|
||||||
t->user_index = curr_import_index;
|
|
||||||
curr_import_index++;
|
|
||||||
gb_thread_start(t, parse_worker_file_proc, p);
|
|
||||||
are_any_alive = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!are_any_alive && curr_import_index >= p->files_to_process.count) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errors.count > 0) {
|
|
||||||
return errors[errors.count-1];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for_array(i, p->files_to_process) {
|
|
||||||
ParseFileError err = process_imported_file(p, p->files_to_process[i]);
|
|
||||||
if (err != ParseFile_None) {
|
if (err != ParseFile_None) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#else
|
|
||||||
for_array(i, p->files_to_process) {
|
|
||||||
ImportedFile f = p->files_to_process[i];
|
|
||||||
ParseFileError err = process_imported_file(p, f);
|
|
||||||
if (err != ParseFile_None) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ParseFile_None;
|
return ParseFile_None;
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-2
@@ -134,13 +134,26 @@ struct Parser {
|
|||||||
Map<AstPackage *> package_map; // Key: String (package name)
|
Map<AstPackage *> package_map; // Key: String (package name)
|
||||||
Array<AstPackage *> packages;
|
Array<AstPackage *> packages;
|
||||||
Array<ImportedPackage> package_imports;
|
Array<ImportedPackage> package_imports;
|
||||||
Array<ImportedFile> files_to_process;
|
isize file_to_process_count;
|
||||||
isize total_token_count;
|
isize total_token_count;
|
||||||
isize total_line_count;
|
isize total_line_count;
|
||||||
gbMutex file_add_mutex;
|
gbMutex file_add_mutex;
|
||||||
gbMutex file_decl_mutex;
|
gbMutex file_decl_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
gb_global ThreadPool parser_thread_pool = {};
|
||||||
|
|
||||||
|
struct ParserWorkerData {
|
||||||
|
Parser *parser;
|
||||||
|
ImportedFile imported_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum ProcInlining {
|
enum ProcInlining {
|
||||||
ProcInlining_none = 0,
|
ProcInlining_none = 0,
|
||||||
ProcInlining_inline = 1,
|
ProcInlining_inline = 1,
|
||||||
@@ -186,11 +199,12 @@ enum FieldFlag {
|
|||||||
FieldFlag_c_vararg = 1<<3,
|
FieldFlag_c_vararg = 1<<3,
|
||||||
FieldFlag_auto_cast = 1<<4,
|
FieldFlag_auto_cast = 1<<4,
|
||||||
|
|
||||||
|
FieldFlag_Tags = 1<<10,
|
||||||
|
|
||||||
FieldFlag_Results = 1<<16,
|
FieldFlag_Results = 1<<16,
|
||||||
|
|
||||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
|
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 {
|
enum StmtAllowFlag {
|
||||||
@@ -208,6 +222,7 @@ enum StmtAllowFlag {
|
|||||||
AST_KIND(Undef, "undef", Token) \
|
AST_KIND(Undef, "undef", Token) \
|
||||||
AST_KIND(BasicLit, "basic literal", struct { \
|
AST_KIND(BasicLit, "basic literal", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
|
ExactValue value; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(BasicDirective, "basic directive", struct { \
|
AST_KIND(BasicDirective, "basic directive", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
@@ -228,11 +243,14 @@ enum StmtAllowFlag {
|
|||||||
Ast *body; \
|
Ast *body; \
|
||||||
u64 tags; \
|
u64 tags; \
|
||||||
ProcInlining inlining; \
|
ProcInlining inlining; \
|
||||||
|
Token where_token; \
|
||||||
|
Array<Ast *> where_clauses; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(CompoundLit, "compound literal", struct { \
|
AST_KIND(CompoundLit, "compound literal", struct { \
|
||||||
Ast *type; \
|
Ast *type; \
|
||||||
Array<Ast *> elems; \
|
Array<Ast *> elems; \
|
||||||
Token open, close; \
|
Token open, close; \
|
||||||
|
i64 max_count; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(_ExprBegin, "", bool) \
|
AST_KIND(_ExprBegin, "", bool) \
|
||||||
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
|
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
|
||||||
@@ -325,6 +343,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
|||||||
Ast *expr; \
|
Ast *expr; \
|
||||||
Ast *body; \
|
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 { \
|
AST_KIND(CaseClause, "case clause", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
Array<Ast *> list; \
|
Array<Ast *> list; \
|
||||||
@@ -412,6 +439,7 @@ AST_KIND(_DeclEnd, "", bool) \
|
|||||||
Array<Ast *> names; \
|
Array<Ast *> names; \
|
||||||
Ast * type; \
|
Ast * type; \
|
||||||
Ast * default_value; \
|
Ast * default_value; \
|
||||||
|
Token tag; \
|
||||||
u32 flags; \
|
u32 flags; \
|
||||||
CommentGroup * docs; \
|
CommentGroup * docs; \
|
||||||
CommentGroup * comment; \
|
CommentGroup * comment; \
|
||||||
@@ -470,6 +498,8 @@ AST_KIND(_TypeBegin, "", bool) \
|
|||||||
isize field_count; \
|
isize field_count; \
|
||||||
Ast *polymorphic_params; \
|
Ast *polymorphic_params; \
|
||||||
Ast *align; \
|
Ast *align; \
|
||||||
|
Token where_token; \
|
||||||
|
Array<Ast *> where_clauses; \
|
||||||
bool is_packed; \
|
bool is_packed; \
|
||||||
bool is_raw_union; \
|
bool is_raw_union; \
|
||||||
}) \
|
}) \
|
||||||
@@ -479,6 +509,8 @@ AST_KIND(_TypeBegin, "", bool) \
|
|||||||
Ast *polymorphic_params; \
|
Ast *polymorphic_params; \
|
||||||
Ast * align; \
|
Ast * align; \
|
||||||
bool no_nil; \
|
bool no_nil; \
|
||||||
|
Token where_token; \
|
||||||
|
Array<Ast *> where_clauses; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(EnumType, "enum type", struct { \
|
AST_KIND(EnumType, "enum type", struct { \
|
||||||
Token token; \
|
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) {
|
if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
|
||||||
j = j2;
|
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);
|
pq->swap(&pq->queue[0], i, j);
|
||||||
i = j;
|
i = j;
|
||||||
@@ -32,7 +32,7 @@ template <typename T>
|
|||||||
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
||||||
while (0 <= j && j < pq->queue.count) {
|
while (0 <= j && j < pq->queue.count) {
|
||||||
isize i = (j-1)/2;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
pq->swap(&pq->queue[0], i, j);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
+13
-1
@@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
|||||||
TOKEN_KIND(Token_package, "package"), \
|
TOKEN_KIND(Token_package, "package"), \
|
||||||
TOKEN_KIND(Token_typeid, "typeid"), \
|
TOKEN_KIND(Token_typeid, "typeid"), \
|
||||||
TOKEN_KIND(Token_when, "when"), \
|
TOKEN_KIND(Token_when, "when"), \
|
||||||
|
TOKEN_KIND(Token_where, "where"), \
|
||||||
TOKEN_KIND(Token_if, "if"), \
|
TOKEN_KIND(Token_if, "if"), \
|
||||||
TOKEN_KIND(Token_else, "else"), \
|
TOKEN_KIND(Token_else, "else"), \
|
||||||
TOKEN_KIND(Token_for, "for"), \
|
TOKEN_KIND(Token_for, "for"), \
|
||||||
@@ -400,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) {
|
|||||||
va_end(va);
|
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, ...) {
|
void syntax_warning(Token token, char *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
@@ -745,9 +755,11 @@ exponent:
|
|||||||
scan_mantissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->curr_rune == 'i') {
|
switch (t->curr_rune) {
|
||||||
|
case 'i': case 'j': case 'k':
|
||||||
token.kind = Token_Imag;
|
token.kind = Token_Imag;
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
|||||||
+173
-41
@@ -32,6 +32,9 @@ enum BasicKind {
|
|||||||
Basic_complex64,
|
Basic_complex64,
|
||||||
Basic_complex128,
|
Basic_complex128,
|
||||||
|
|
||||||
|
Basic_quaternion128,
|
||||||
|
Basic_quaternion256,
|
||||||
|
|
||||||
Basic_int,
|
Basic_int,
|
||||||
Basic_uint,
|
Basic_uint,
|
||||||
Basic_uintptr,
|
Basic_uintptr,
|
||||||
@@ -66,6 +69,7 @@ enum BasicKind {
|
|||||||
Basic_UntypedInteger,
|
Basic_UntypedInteger,
|
||||||
Basic_UntypedFloat,
|
Basic_UntypedFloat,
|
||||||
Basic_UntypedComplex,
|
Basic_UntypedComplex,
|
||||||
|
Basic_UntypedQuaternion,
|
||||||
Basic_UntypedString,
|
Basic_UntypedString,
|
||||||
Basic_UntypedRune,
|
Basic_UntypedRune,
|
||||||
Basic_UntypedNil,
|
Basic_UntypedNil,
|
||||||
@@ -82,17 +86,18 @@ enum BasicFlag {
|
|||||||
BasicFlag_Unsigned = GB_BIT(2),
|
BasicFlag_Unsigned = GB_BIT(2),
|
||||||
BasicFlag_Float = GB_BIT(3),
|
BasicFlag_Float = GB_BIT(3),
|
||||||
BasicFlag_Complex = GB_BIT(4),
|
BasicFlag_Complex = GB_BIT(4),
|
||||||
BasicFlag_Pointer = GB_BIT(5),
|
BasicFlag_Quaternion = GB_BIT(5),
|
||||||
BasicFlag_String = GB_BIT(6),
|
BasicFlag_Pointer = GB_BIT(6),
|
||||||
BasicFlag_Rune = GB_BIT(7),
|
BasicFlag_String = GB_BIT(7),
|
||||||
BasicFlag_Untyped = GB_BIT(8),
|
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_EndianLittle = GB_BIT(13),
|
||||||
BasicFlag_EndianBig = GB_BIT(14),
|
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_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
||||||
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
|
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
|
||||||
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
|
||||||
@@ -107,21 +112,23 @@ struct BasicType {
|
|||||||
|
|
||||||
struct TypeStruct {
|
struct TypeStruct {
|
||||||
Array<Entity *> fields;
|
Array<Entity *> fields;
|
||||||
|
Array<String> tags;
|
||||||
|
Array<i64> offsets;
|
||||||
Ast * node;
|
Ast * node;
|
||||||
Scope * scope;
|
Scope * scope;
|
||||||
|
|
||||||
Array<i64> offsets;
|
Type * polymorphic_params; // Type_Tuple
|
||||||
|
Type * polymorphic_parent;
|
||||||
|
|
||||||
|
i64 custom_align;
|
||||||
|
Entity * names;
|
||||||
|
|
||||||
bool are_offsets_set;
|
bool are_offsets_set;
|
||||||
bool are_offsets_being_processed;
|
bool are_offsets_being_processed;
|
||||||
bool is_packed;
|
bool is_packed;
|
||||||
bool is_raw_union;
|
bool is_raw_union;
|
||||||
bool is_polymorphic;
|
bool is_polymorphic;
|
||||||
bool is_poly_specialized;
|
bool is_poly_specialized;
|
||||||
Type * polymorphic_params; // Type_Tuple
|
|
||||||
Type * polymorphic_parent;
|
|
||||||
|
|
||||||
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
|
||||||
Entity * names;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeUnion {
|
struct TypeUnion {
|
||||||
@@ -131,12 +138,11 @@ struct TypeUnion {
|
|||||||
i64 variant_block_size;
|
i64 variant_block_size;
|
||||||
i64 custom_align;
|
i64 custom_align;
|
||||||
i64 tag_size;
|
i64 tag_size;
|
||||||
bool no_nil;
|
|
||||||
|
|
||||||
bool is_polymorphic;
|
|
||||||
bool is_poly_specialized;
|
|
||||||
Type * polymorphic_params; // Type_Tuple
|
Type * polymorphic_params; // Type_Tuple
|
||||||
Type * polymorphic_parent;
|
Type * polymorphic_parent;
|
||||||
|
bool no_nil;
|
||||||
|
bool is_polymorphic;
|
||||||
|
bool is_poly_specialized;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TYPE_KINDS \
|
#define TYPE_KINDS \
|
||||||
@@ -184,7 +190,9 @@ struct TypeUnion {
|
|||||||
TYPE_KIND(Tuple, struct { \
|
TYPE_KIND(Tuple, struct { \
|
||||||
Array<Entity *> variables; /* Entity_Variable */ \
|
Array<Entity *> variables; /* Entity_Variable */ \
|
||||||
Array<i64> offsets; \
|
Array<i64> offsets; \
|
||||||
|
bool are_offsets_being_processed; \
|
||||||
bool are_offsets_set; \
|
bool are_offsets_set; \
|
||||||
|
bool is_packed; \
|
||||||
}) \
|
}) \
|
||||||
TYPE_KIND(Proc, struct { \
|
TYPE_KIND(Proc, struct { \
|
||||||
Ast *node; \
|
Ast *node; \
|
||||||
@@ -195,9 +203,9 @@ struct TypeUnion {
|
|||||||
i32 result_count; \
|
i32 result_count; \
|
||||||
Array<Type *> abi_compat_params; \
|
Array<Type *> abi_compat_params; \
|
||||||
Type * abi_compat_result_type; \
|
Type * abi_compat_result_type; \
|
||||||
bool return_by_pointer; \
|
|
||||||
bool variadic; \
|
|
||||||
i32 variadic_index; \
|
i32 variadic_index; \
|
||||||
|
bool variadic; \
|
||||||
|
bool abi_types_set; \
|
||||||
bool require_results; \
|
bool require_results; \
|
||||||
bool c_vararg; \
|
bool c_vararg; \
|
||||||
bool is_polymorphic; \
|
bool is_polymorphic; \
|
||||||
@@ -205,6 +213,7 @@ struct TypeUnion {
|
|||||||
bool has_proc_default_values; \
|
bool has_proc_default_values; \
|
||||||
bool has_named_results; \
|
bool has_named_results; \
|
||||||
bool diverging; /* no return */ \
|
bool diverging; /* no return */ \
|
||||||
|
bool return_by_pointer; \
|
||||||
u64 tags; \
|
u64 tags; \
|
||||||
isize specialization_count; \
|
isize specialization_count; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
@@ -341,6 +350,9 @@ gb_global Type basic_types[] = {
|
|||||||
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
|
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
|
||||||
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
|
{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_int, BasicFlag_Integer, -1, STR_LIT("int")}},
|
||||||
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
|
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
|
||||||
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
|
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
|
||||||
@@ -376,6 +388,7 @@ gb_global Type basic_types[] = {
|
|||||||
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
|
{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_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_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_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_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
|
||||||
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
|
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
|
||||||
@@ -411,6 +424,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64];
|
|||||||
gb_global Type *t_complex64 = &basic_types[Basic_complex64];
|
gb_global Type *t_complex64 = &basic_types[Basic_complex64];
|
||||||
gb_global Type *t_complex128 = &basic_types[Basic_complex128];
|
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_int = &basic_types[Basic_int];
|
||||||
gb_global Type *t_uint = &basic_types[Basic_uint];
|
gb_global Type *t_uint = &basic_types[Basic_uint];
|
||||||
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
|
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
|
||||||
@@ -445,6 +461,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_integer = &basic_types[Basic_UntypedInteger];
|
||||||
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
|
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_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_string = &basic_types[Basic_UntypedString];
|
||||||
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
|
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
|
||||||
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
|
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
|
||||||
@@ -471,6 +488,7 @@ gb_global Type *t_type_info_integer = nullptr;
|
|||||||
gb_global Type *t_type_info_rune = nullptr;
|
gb_global Type *t_type_info_rune = nullptr;
|
||||||
gb_global Type *t_type_info_float = nullptr;
|
gb_global Type *t_type_info_float = nullptr;
|
||||||
gb_global Type *t_type_info_complex = 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_any = nullptr;
|
||||||
gb_global Type *t_type_info_typeid = nullptr;
|
gb_global Type *t_type_info_typeid = nullptr;
|
||||||
gb_global Type *t_type_info_string = nullptr;
|
gb_global Type *t_type_info_string = nullptr;
|
||||||
@@ -495,6 +513,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_rune_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_float_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_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_any_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_typeid_ptr = nullptr;
|
gb_global Type *t_type_info_typeid_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_string_ptr = nullptr;
|
gb_global Type *t_type_info_string_ptr = nullptr;
|
||||||
@@ -535,8 +554,27 @@ i64 type_offset_of (Type *t, i32 index);
|
|||||||
gbString type_to_string (Type *type);
|
gbString type_to_string (Type *type);
|
||||||
void init_map_internal_types(Type *type);
|
void init_map_internal_types(Type *type);
|
||||||
Type * bit_set_to_int(Type *t);
|
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) {
|
Type *base_type(Type *t) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (t == nullptr) {
|
if (t == nullptr) {
|
||||||
@@ -923,6 +961,13 @@ bool is_type_complex(Type *t) {
|
|||||||
}
|
}
|
||||||
return false;
|
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) {
|
bool is_type_f32(Type *t) {
|
||||||
t = core_type(t);
|
t = core_type(t);
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
@@ -1037,14 +1082,40 @@ Type *core_array_type(Type *t) {
|
|||||||
return 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) {
|
Type *base_complex_elem_type(Type *t) {
|
||||||
t = core_type(t);
|
t = core_type(t);
|
||||||
if (is_type_complex(t)) {
|
if (t->kind == Type_Basic) {
|
||||||
switch (t->Basic.kind) {
|
switch (t->Basic.kind) {
|
||||||
// case Basic_complex32: return t_f16;
|
// case Basic_complex32: return t_f16;
|
||||||
case Basic_complex64: return t_f32;
|
case Basic_complex64: return t_f32;
|
||||||
case Basic_complex128: return t_f64;
|
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_UntypedComplex: return t_untyped_float;
|
||||||
|
case Basic_UntypedQuaternion: return t_untyped_float;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GB_PANIC("Invalid complex type");
|
GB_PANIC("Invalid complex type");
|
||||||
@@ -1099,12 +1170,11 @@ bool is_type_integer_endian_big(Type *t) {
|
|||||||
return is_type_integer_endian_big(bit_set_to_int(t));
|
return is_type_integer_endian_big(bit_set_to_int(t));
|
||||||
} else if (t->kind == Type_Pointer) {
|
} else if (t->kind == Type_Pointer) {
|
||||||
return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
|
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;
|
return build_context.endian_kind == TargetEndian_Big;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_type_integer_endian_little(Type *t) {
|
bool is_type_integer_endian_little(Type *t) {
|
||||||
t = core_type(t);
|
t = core_type(t);
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
@@ -1118,11 +1188,24 @@ bool is_type_integer_endian_little(Type *t) {
|
|||||||
return is_type_integer_endian_little(bit_set_to_int(t));
|
return is_type_integer_endian_little(bit_set_to_int(t));
|
||||||
} else if (t->kind == Type_Pointer) {
|
} else if (t->kind == Type_Pointer) {
|
||||||
return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
|
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;
|
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) {
|
bool is_type_different_to_arch_endianness(Type *t) {
|
||||||
switch (build_context.endian_kind) {
|
switch (build_context.endian_kind) {
|
||||||
@@ -1284,6 +1367,19 @@ bool is_type_indexable(Type *t) {
|
|||||||
return false;
|
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) {
|
bool is_type_polymorphic_record(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
@@ -1663,6 +1759,12 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
if (xf_is_using ^ yf_is_using) {
|
if (xf_is_using ^ yf_is_using) {
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1683,7 +1785,8 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
|
|
||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
if (y->kind == 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) {
|
for_array(i, x->Tuple.variables) {
|
||||||
Entity *xe = x->Tuple.variables[i];
|
Entity *xe = x->Tuple.variables[i];
|
||||||
Entity *ye = y->Tuple.variables[i];
|
Entity *ye = y->Tuple.variables[i];
|
||||||
@@ -1763,6 +1866,7 @@ Type *default_type(Type *type) {
|
|||||||
case Basic_UntypedInteger: return t_int;
|
case Basic_UntypedInteger: return t_int;
|
||||||
case Basic_UntypedFloat: return t_f64;
|
case Basic_UntypedFloat: return t_f64;
|
||||||
case Basic_UntypedComplex: return t_complex128;
|
case Basic_UntypedComplex: return t_complex128;
|
||||||
|
case Basic_UntypedQuaternion: return t_quaternion256;
|
||||||
case Basic_UntypedString: return t_string;
|
case Basic_UntypedString: return t_string;
|
||||||
case Basic_UntypedRune: return t_rune;
|
case Basic_UntypedRune: return t_rune;
|
||||||
}
|
}
|
||||||
@@ -2131,19 +2235,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
|||||||
if (type->Array.count <= 4) {
|
if (type->Array.count <= 4) {
|
||||||
// HACK(bill): Memory leak
|
// HACK(bill): Memory leak
|
||||||
switch (type->Array.count) {
|
switch (type->Array.count) {
|
||||||
#define _ARRAY_FIELD_CASE(_length, _name) \
|
#define _ARRAY_FIELD_CASE_IF(_length, _name) \
|
||||||
case (_length): \
|
if (field_name == (_name)) { \
|
||||||
if (field_name == _name) { \
|
|
||||||
selection_add_index(&sel, (_length)-1); \
|
selection_add_index(&sel, (_length)-1); \
|
||||||
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
|
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
|
||||||
return sel; \
|
return sel; \
|
||||||
} \
|
}
|
||||||
|
#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
|
||||||
|
case (_length): \
|
||||||
|
_ARRAY_FIELD_CASE_IF(_length, _name0); \
|
||||||
|
_ARRAY_FIELD_CASE_IF(_length, _name1); \
|
||||||
/*fallthrough*/
|
/*fallthrough*/
|
||||||
|
|
||||||
_ARRAY_FIELD_CASE(4, "w");
|
_ARRAY_FIELD_CASE(4, "w", "a");
|
||||||
_ARRAY_FIELD_CASE(3, "z");
|
_ARRAY_FIELD_CASE(3, "z", "b");
|
||||||
_ARRAY_FIELD_CASE(2, "y");
|
_ARRAY_FIELD_CASE(2, "y", "g");
|
||||||
_ARRAY_FIELD_CASE(1, "x");
|
_ARRAY_FIELD_CASE(1, "x", "r");
|
||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
#undef _ARRAY_FIELD_CASE
|
#undef _ARRAY_FIELD_CASE
|
||||||
@@ -2254,7 +2361,9 @@ i64 type_size_of(Type *t) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// NOTE(bill): Always calculate the size when it is a Type_Basic
|
// 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;
|
return t->cached_size;
|
||||||
}
|
}
|
||||||
TypePath path = {0};
|
TypePath path = {0};
|
||||||
@@ -2269,7 +2378,9 @@ i64 type_align_of(Type *t) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
// NOTE(bill): Always calculate the size when it is a Type_Basic
|
// 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;
|
return t->cached_align;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2303,6 +2414,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
|||||||
|
|
||||||
case Basic_complex64: case Basic_complex128:
|
case Basic_complex64: case Basic_complex128:
|
||||||
return type_size_of_internal(t, path) / 2;
|
return type_size_of_internal(t, path) / 2;
|
||||||
|
case Basic_quaternion128: case Basic_quaternion256:
|
||||||
|
return type_size_of_internal(t, path) / 4;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -2488,9 +2601,9 @@ bool type_set_offsets(Type *t) {
|
|||||||
}
|
}
|
||||||
} else if (is_type_tuple(t)) {
|
} else if (is_type_tuple(t)) {
|
||||||
if (!t->Tuple.are_offsets_set) {
|
if (!t->Tuple.are_offsets_set) {
|
||||||
t->Struct.are_offsets_being_processed = true;
|
t->Tuple.are_offsets_being_processed = true;
|
||||||
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false);
|
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
|
||||||
t->Struct.are_offsets_being_processed = false;
|
t->Tuple.are_offsets_being_processed = false;
|
||||||
t->Tuple.are_offsets_set = true;
|
t->Tuple.are_offsets_set = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2913,9 +3026,22 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
isize comma_index = 0;
|
isize comma_index = 0;
|
||||||
for_array(i, type->Tuple.variables) {
|
for_array(i, type->Tuple.variables) {
|
||||||
Entity *var = type->Tuple.variables[i];
|
Entity *var = type->Tuple.variables[i];
|
||||||
if (var != nullptr) {
|
if (var == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = var->token.string;
|
||||||
if (var->kind == Entity_Constant) {
|
if (var->kind == Entity_Constant) {
|
||||||
// Ignore
|
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 {
|
||||||
|
str = gb_string_appendc(str, "=");
|
||||||
|
str = write_exact_value_to_string(str, var->Constant.value);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2938,10 +3064,16 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
} else {
|
} else {
|
||||||
GB_ASSERT(var->kind == Entity_TypeName);
|
GB_ASSERT(var->kind == Entity_TypeName);
|
||||||
if (var->type->kind == Type_Generic) {
|
if (var->type->kind == Type_Generic) {
|
||||||
str = gb_string_appendc(str, "type/");
|
str = gb_string_appendc(str, "typeid/");
|
||||||
str = write_type_to_string(str, var->type);
|
str = write_type_to_string(str, var->type);
|
||||||
} else {
|
} else {
|
||||||
str = gb_string_appendc(str, "type");
|
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, "typeid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#pragma warning(disable: 4245)
|
#pragma warning(disable: 4245)
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "utf8proc/utf8proc.h"
|
|
||||||
#include "utf8proc/utf8proc.c"
|
#include "utf8proc/utf8proc.c"
|
||||||
}
|
}
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
* Implementation of libutf8proc.
|
* Implementation of libutf8proc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "utf8proc.h"
|
#include "utf8proc.h"
|
||||||
#include "utf8proc_data.c"
|
#include "utf8proc_data.c"
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user