aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Heyes <rumcode@icloud.com>2019-11-01 19:18:33 +0000
committerChris Heyes <rumcode@icloud.com>2019-11-01 19:18:33 +0000
commit153e7525b5d64f12deb318d50aee1d9dbeb1fc8e (patch)
treeb8ac88c0788af31bcb3c5041d78306c2120714f6
parentd85893954dccc7833e3d954db641d9fd2a3c7451 (diff)
parent44a303e5778fb8564964d53523634f34f8589489 (diff)
Merge remote-tracking branch 'upstream/master'
-rw-r--r--.github/workflows/ci.yml57
-rw-r--r--.travis.yml24
-rw-r--r--README.md11
-rw-r--r--appveyor.yml19
-rw-r--r--build.bat1
-rw-r--r--core/builtin/builtin.odin105
-rw-r--r--core/c/c.odin2
-rw-r--r--core/encoding/base64/base64.odin93
-rw-r--r--core/encoding/cel/cel.odin6
-rw-r--r--core/encoding/cel/token.odin6
-rw-r--r--core/encoding/json/marshal.odin11
-rw-r--r--core/fmt/fmt.odin288
-rw-r--r--core/intrinsics/intrinsics.odin126
-rw-r--r--core/log/file_console_logger.odin32
-rw-r--r--core/log/log.odin67
-rw-r--r--core/math/linalg/linalg.odin283
-rw-r--r--core/math/math.odin725
-rw-r--r--core/math/rand/normal.odin4
-rw-r--r--core/mem/allocators.odin2
-rw-r--r--core/mem/raw.odin6
-rw-r--r--core/odin/ast/ast.odin219
-rw-r--r--core/odin/ast/clone.odin4
-rw-r--r--core/odin/ast/file.odin4
-rw-r--r--core/odin/parser/parser.odin842
-rw-r--r--core/odin/tokenizer/token.odin (renamed from core/odin/token/token.odin)44
-rw-r--r--core/odin/tokenizer/tokenizer.odin160
-rw-r--r--core/os/os_darwin.odin (renamed from core/os/os_osx.odin)8
-rw-r--r--core/os/os_essence.odin2544
-rw-r--r--core/os/os_linux.odin6
-rw-r--r--core/os/os_windows.odin2
-rw-r--r--core/reflect/reflect.odin396
-rw-r--r--core/reflect/types.odin (renamed from core/types/types.odin)218
-rw-r--r--core/runtime/core.odin173
-rw-r--r--core/runtime/internal.odin254
-rw-r--r--core/sort/sort.odin7
-rw-r--r--core/strconv/decimal/decimal.odin (renamed from core/decimal/decimal.odin)2
-rw-r--r--core/strconv/generic_float.odin4
-rw-r--r--core/strconv/strconv.odin4
-rw-r--r--core/strings/builder.odin4
-rw-r--r--core/strings/strings.odin150
-rw-r--r--core/sys/essence_linker_userland64.ld24
-rw-r--r--core/sys/win32/kernel32.odin2
-rw-r--r--core/sys/win32/user32.odin2
-rw-r--r--core/time/time_darwin.odin (renamed from core/time/time_osx.odin)0
-rw-r--r--core/time/time_essence.odin2
-rw-r--r--core/time/time_windows.odin2
-rw-r--r--core/unicode/utf8/utf8.odin77
-rw-r--r--examples/demo/demo.odin374
-rw-r--r--misc/logo-slim.pngbin73988 -> 76402 bytes
-rw-r--r--misc/old_demos/demo001.odin (renamed from examples/old_demos/demo001.odin)0
-rw-r--r--misc/old_demos/demo002.odin (renamed from examples/old_demos/demo002.odin)0
-rw-r--r--misc/old_demos/demo004.odin (renamed from examples/old_demos/demo004.odin)0
-rw-r--r--misc/old_demos/demo005.odin (renamed from examples/old_demos/demo005.odin)0
-rw-r--r--misc/old_demos/demo006.odin (renamed from examples/old_demos/demo006.odin)0
-rw-r--r--misc/old_demos/demo007.odin (renamed from examples/old_demos/demo007.odin)0
-rw-r--r--misc/old_demos/demo008.odin (renamed from examples/old_demos/demo008.odin)0
-rw-r--r--misc/old_demos/old_runtime.odin (renamed from examples/old_demos/old_runtime.odin)0
-rw-r--r--misc/old_stuff/demo_backup.odin (renamed from examples/old_stuff/demo_backup.odin)0
-rw-r--r--misc/shell.bat4
-rw-r--r--src/build_settings.cpp56
-rw-r--r--src/check_decl.cpp247
-rw-r--r--src/check_expr.cpp1163
-rw-r--r--src/check_stmt.cpp221
-rw-r--r--src/check_type.cpp400
-rw-r--r--src/checker.cpp166
-rw-r--r--src/checker.hpp220
-rw-r--r--src/checker_builtin_procs.hpp320
-rw-r--r--src/common.cpp8
-rw-r--r--src/entity.cpp13
-rw-r--r--src/exact_value.cpp264
-rw-r--r--src/gb/gb.h30
-rw-r--r--src/ir.cpp963
-rw-r--r--src/ir_print.cpp300
-rw-r--r--src/main.cpp115
-rw-r--r--src/parser.cpp524
-rw-r--r--src/parser.hpp60
-rw-r--r--src/priority_queue.cpp4
-rw-r--r--src/range_cache.cpp70
-rw-r--r--src/string.cpp86
-rw-r--r--src/thread_pool.cpp184
-rw-r--r--src/tokenizer.cpp14
-rw-r--r--src/types.cpp272
-rw-r--r--src/unicode.cpp1
-rw-r--r--src/utf8proc/utf8proc.c1
84 files changed, 10286 insertions, 2816 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 000000000..7c43b01e1
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -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
+
+
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index a0169259d..000000000
--- a/.travis.yml
+++ /dev/null
@@ -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
diff --git a/README.md b/README.md
index 092c33155..d3de6f332 100644
--- a/README.md
+++ b/README.md
@@ -10,15 +10,12 @@
<a href="https://github.com/odin-lang/odin/releases/latest">
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
</a>
- <a href="https://github.com/odin-lang/odin/blob/master/LICENSE">
- <img src="https://img.shields.io/github/license/odin-lang/odin.svg">
- </a>
<br>
- <a href="https://ci.appveyor.com/project/ThisDrunkDane/odin-vf0ap">
- <img src="https://ci.appveyor.com/api/projects/status/qss6l921c0eu85u6/branch/master?svg=true">
+ <a href="https://discord.gg/hnwN2Rj">
+ <img src="https://img.shields.io/discord/568138951836172421?logo=discord">
</a>
- <a href="https://travis-ci.org/odin-lang/Odin">
- <img src="https://travis-ci.org/odin-lang/Odin.svg?branch=master">
+ <a href="https://github.com/odin-lang/odin/actions">
+ <img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg">
</a>
</p>
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 5e5abe979..000000000
--- a/appveyor.yml
+++ /dev/null
@@ -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 \ No newline at end of file
diff --git a/build.bat b/build.bat
index 6e5450c2b..b95e8a2ab 100644
--- a/build.bat
+++ b/build.bat
@@ -39,7 +39,6 @@ set linker_settings=%libs% %linker_flags%
del *.pdb > NUL 2> NUL
del *.ilk > NUL 2> NUL
-
cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
&& odin run examples/demo/demo.odin
diff --git a/core/builtin/builtin.odin b/core/builtin/builtin.odin
new file mode 100644
index 000000000..74ade0260
--- /dev/null
+++ b/core/builtin/builtin.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 ---
diff --git a/core/c/c.odin b/core/c/c.odin
index 47af84165..3ed49c0c2 100644
--- a/core/c/c.odin
+++ b/core/c/c.odin
@@ -31,3 +31,5 @@ ssize_t :: b.int;
ptrdiff_t :: b.int;
uintptr_t :: b.uintptr;
intptr_t :: b.int;
+
+wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32;
diff --git a/core/encoding/base64/base64.odin b/core/encoding/base64/base64.odin
new file mode 100644
index 000000000..0224e93e4
--- /dev/null
+++ b/core/encoding/base64/base64.odin
@@ -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;
+} \ No newline at end of file
diff --git a/core/encoding/cel/cel.odin b/core/encoding/cel/cel.odin
index 793dba231..754d8cbfa 100644
--- a/core/encoding/cel/cel.odin
+++ b/core/encoding/cel/cel.odin
@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
}
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
- fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
- fmt.printf_err(msg, ..args);
- fmt.println_err();
+ fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
+ fmt.eprintf(msg, ..args);
+ fmt.eprintln();
p.error_count += 1;
}
diff --git a/core/encoding/cel/token.odin b/core/encoding/cel/token.odin
index 1ad86b299..a2bcb963a 100644
--- a/core/encoding/cel/token.odin
+++ b/core/encoding/cel/token.odin
@@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
}
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
- fmt.printf_err("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
- fmt.printf_err(msg, ..args);
- fmt.println_err();
+ fmt.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
+ fmt.eprintf(msg, ..args);
+ fmt.eprintln();
t.error_count += 1;
}
diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin
index cd9aae169..60839b21b 100644
--- a/core/encoding/json/marshal.odin
+++ b/core/encoding/json/marshal.odin
@@ -5,7 +5,7 @@ import "core:math/bits"
import "core:runtime"
import "core:strconv"
import "core:strings"
-import "core:types"
+import "core:reflect"
Marshal_Error :: enum {
None,
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^Map_Entry_Header)data;
- if types.is_string(info.key) {
+ if reflect.is_string(info.key) {
marshal_arg(b, header.key.str);
} else {
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
@@ -284,11 +284,10 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
t := runtime.type_info_base(ti);
switch info in t.variant {
case runtime.Type_Info_Integer:
- using runtime.Type_Info_Endianness;
switch info.endianness {
- case Platform: return false;
- case Little: return ODIN_ENDIAN != "little";
- case Big: return ODIN_ENDIAN != "big";
+ case .Platform: return false;
+ case .Little: return ODIN_ENDIAN != "little";
+ case .Big: return ODIN_ENDIAN != "big";
}
}
return false;
diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin
index 60b1fdcc1..e6830e734 100644
--- a/core/fmt/fmt.odin
+++ b/core/fmt/fmt.odin
@@ -5,9 +5,9 @@ import "core:os"
import "core:mem"
import "core:math/bits"
import "core:unicode/utf8"
-import "core:types"
import "core:strconv"
import "core:strings"
+import "core:reflect"
@private
@@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
// print* procedures return the number of bytes written
-print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
-print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
-println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
-println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
-printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
-printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
+print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
+println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
+printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
+
+eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
+eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
+eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
+
+
+@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); }
+@(deprecated="prefer eprintf") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); }
+@(deprecated="prefer eprintln") println_err :: proc(args: ..any) -> int { return eprintln(..args); }
// aprint* procedures return a string that was allocated with the current context
@@ -143,7 +149,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location)
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
data: [DEFAULT_BUFFER_SIZE]byte;
buf := strings.builder_from_slice(data[:]);
- write_type(&buf, info);
+ reflect.write_type(&buf, info);
os.write_string(fd, strings.to_string(buf));
}
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
fi.buf = buf;
for arg, i in args {
- is_string := arg != nil && types.is_string(type_info_of(arg.id));
+ is_string := arg != nil && reflect.is_string(type_info_of(arg.id));
if i > 0 && !is_string && !prev_string {
strings.write_byte(buf, ' ');
}
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
strings.write_rune(buf, verb);
strings.write_byte(buf, '(');
if arg.id != nil {
- write_typeid(buf, arg.id);
+ reflect.write_typeid(buf, arg.id);
strings.write_byte(buf, '=');
fmt_value(fi, arg, 'v');
} else {
@@ -792,7 +798,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) {
case: return "", false;
case runtime.Type_Info_Enum:
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
- if types.is_string(e.base) {
+ if reflect.is_string(e.base) {
for val, idx in e.values {
if v, ok := val.(T); ok && v == i {
return e.names[idx], true;
@@ -947,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
if name != "" {
strings.write_string(fi.buf, name);
} else {
- write_type(fi.buf, type_info);
+ reflect.write_type(fi.buf, type_info);
}
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
@@ -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 {
elem := rt.type_info_base(ot.elem);
if elem == nil do return;
- write_type(fi.buf, type_info);
+ reflect.write_type(fi.buf, type_info);
strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}');
@@ -1053,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
// Okay
}
} else {
- write_type(fi.buf, type_info);
+ reflect.write_type(fi.buf, type_info);
strings.write_byte(fi.buf, '{');
strings.write_byte(fi.buf, '}');
}
@@ -1101,7 +1107,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
strings.write_string(fi.buf, name);
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{}");
} else {
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_Float: fmt_arg(fi, v, verb);
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
+ case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
case runtime.Type_Info_String: fmt_arg(fi, v, verb);
case runtime.Type_Info_Pointer:
if v.id == typeid_of(^runtime.Type_Info) {
- write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
+ reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
} else {
ptr := (^rawptr)(v.data)^;
if verb != 'p' && info.elem != nil {
@@ -1256,7 +1263,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^runtime.Map_Entry_Header)data;
- if types.is_string(info.key) {
+ if reflect.is_string(info.key) {
strings.write_string(fi.buf, header.key.str);
} else {
fi := Info{buf = fi.buf};
@@ -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, " = ");
- if t := info.types[i]; types.is_any(t) {
+ if t := info.types[i]; reflect.is_any(t) {
strings.write_string(fi.buf, "any{}");
} else {
data := uintptr(v.data) + info.offsets[i];
@@ -1349,14 +1356,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
if ptr == nil {
strings.write_string(fi.buf, "nil");
} else {
- write_typeid(fi.buf, v.id);
+ reflect.write_typeid(fi.buf, v.id);
strings.write_string(fi.buf, " @ ");
fmt_pointer(fi, ptr, 'p');
}
case runtime.Type_Info_Type_Id:
id := (^typeid)(v.data)^;
- write_typeid(fi.buf, id);
+ reflect.write_typeid(fi.buf, id);
case runtime.Type_Info_Bit_Field:
fmt_bit_field(fi, v);
@@ -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) {
if arg == nil {
strings.write_string(fi.buf, "<nil>");
@@ -1398,7 +1430,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
switch a in arg {
case ^runtime.Type_Info: ti = a;
}
- write_type(fi.buf, ti);
+ reflect.write_type(fi.buf, ti);
return;
}
@@ -1434,6 +1466,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case complex64: fmt_complex(fi, complex128(a), 64, verb);
case complex128: fmt_complex(fi, a, 128, verb);
+ case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
+ case quaternion256: fmt_quaternion(fi, a, 256, verb);
+
case i8: fmt_int(fi, u64(a), true, 8, verb);
case u8: fmt_int(fi, u64(a), false, 8, verb);
case i16: fmt_int(fi, u64(a), true, 16, verb);
@@ -1449,7 +1484,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case string: fmt_string(fi, a, verb);
case cstring: fmt_cstring(fi, a, verb);
- case typeid: write_typeid(fi.buf, a);
+ case typeid: reflect.write_typeid(fi.buf, a);
case i16le: fmt_int(fi, u64(a), true, 16, verb);
case u16le: fmt_int(fi, u64(a), false, 16, verb);
@@ -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, ')');
- }
- }
-}
diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin
new file mode 100644
index 000000000..8ee12554c
--- /dev/null
+++ b/core/intrinsics/intrinsics.odin
@@ -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) ---
diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin
index 3778d3e53..6bddf7ffb 100644
--- a/core/log/file_console_logger.odin
+++ b/core/log/file_console_logger.odin
@@ -14,18 +14,18 @@ Level_Headers := []string{
};
Default_Console_Logger_Opts :: Options{
- Option.Level,
- Option.Terminal_Color,
- Option.Short_File_Path,
- Option.Line,
- Option.Procedure,
+ .Level,
+ .Terminal_Color,
+ .Short_File_Path,
+ .Line,
+ .Procedure,
} | Full_Timestamp_Opts;
Default_File_Logger_Opts :: Options{
- Option.Level,
- Option.Short_File_Path,
- Option.Line,
- Option.Procedure,
+ .Level,
+ .Short_File_Path,
+ .Line,
+ .Procedure,
} | Full_Timestamp_Opts;
@@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
case Level.Error, Level.Fatal : col = RED;
}
- if Option.Level in opts {
- if Option.Terminal_Color in opts do fmt.sbprint(str, col);
+ if .Level in opts {
+ if .Terminal_Color in opts do fmt.sbprint(str, col);
fmt.sbprint(str, Level_Headers[level]);
- if Option.Terminal_Color in opts do fmt.sbprint(str, RESET);
+ if .Terminal_Color in opts do fmt.sbprint(str, RESET);
}
}
@@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
file := location.file_path;
- if Option.Short_File_Path in opts {
+ if .Short_File_Path in opts {
when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
last := 0;
for r, i in location.file_path do if r == delimiter do last = i+1;
@@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
- if Option.Procedure in opts {
+ if .Procedure in opts {
if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
fmt.sbprintf(buf, "%s()", location.procedure);
}
- if Option.Line in opts {
- if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":");
+ if .Line in opts {
+ if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
fmt.sbprint(buf, location.line);
}
diff --git a/core/log/log.odin b/core/log/log.odin
index 13e370b91..76b8550e8 100644
--- a/core/log/log.odin
+++ b/core/log/log.odin
@@ -11,30 +11,30 @@ Level :: enum {
}
Option :: enum {
- Level,
- Date,
- Time,
- Short_File_Path,
- Long_File_Path,
- Line,
- Procedure,
- Terminal_Color
+ Level,
+ Date,
+ Time,
+ Short_File_Path,
+ Long_File_Path,
+ Line,
+ Procedure,
+ Terminal_Color
}
Options :: bit_set[Option];
Full_Timestamp_Opts :: Options{
- Option.Date,
- Option.Time
+ .Date,
+ .Time
};
Location_Header_Opts :: Options{
- Option.Short_File_Path,
- Option.Long_File_Path,
- Option.Line,
- Option.Procedure,
+ .Short_File_Path,
+ .Long_File_Path,
+ .Line,
+ .Procedure,
};
Location_File_Opts :: Options{
- Option.Short_File_Path,
- Option.Long_File_Path
+ .Short_File_Path,
+ .Long_File_Path
};
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
@@ -42,30 +42,34 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt
Logger :: struct {
procedure: Logger_Proc,
data: rawptr,
- options: Options,
+ options: Options,
}
Multi_Logger_Data :: struct {
- loggers : []Logger,
+ loggers : []Logger,
}
create_multi_logger :: proc(logs: ..Logger) -> Logger {
- data := new(Multi_Logger_Data);
- data.loggers = make([]Logger, len(logs));
- copy(data.loggers, logs);
- return Logger{multi_logger_proc, data, nil};
+ data := new(Multi_Logger_Data);
+ data.loggers = make([]Logger, len(logs));
+ copy(data.loggers, logs);
+ return Logger{multi_logger_proc, data, nil};
}
-destroy_multi_logger ::proc(log : ^Logger) {
- free(log.data);
- log^ = nil_logger();
+destroy_multi_logger :: proc(log : ^Logger) {
+ free(log.data);
+ log^ = nil_logger();
}
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
options: Options, location := #caller_location) {
- data := cast(^Multi_Logger_Data)logger_data;
- if data.loggers == nil || len(data.loggers) == 0 do return;
- for log in data.loggers do log.procedure(log.data, level, text, log.options, location);
+ data := cast(^Multi_Logger_Data)logger_data;
+ if data.loggers == nil || len(data.loggers) == 0 {
+ return;
+ }
+ for log in data.loggers {
+ log.procedure(log.data, level, text, log.options, location);
+ }
}
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
@@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, nil};
}
+// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
@@ -83,7 +88,7 @@ error :: proc(fmt_str : string, args : ..any, location := #caller_location) do l
fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location);
logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) {
- logger := context.logger;
- str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
- logger.procedure(logger.data, level, str, logger.options, location);
+ logger := context.logger;
+ str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
+ logger.procedure(logger.data, level, str, logger.options, location);
}
diff --git a/core/math/linalg/linalg.odin b/core/math/linalg/linalg.odin
new file mode 100644
index 000000000..ceef645cb
--- /dev/null
+++ b/core/math/linalg/linalg.odin
@@ -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;
+}
diff --git a/core/math/math.odin b/core/math/math.odin
index 016e8143a..583da00d0 100644
--- a/core/math/math.odin
+++ b/core/math/math.odin
@@ -1,36 +1,41 @@
package math
+import "intrinsics"
+
+Float_Class :: enum {
+ Normal, // an ordinary nonzero floating point value
+ Subnormal, // a subnormal floating point value
+ Zero, // zero
+ Neg_Zero, // the negative zero
+ NaN, // Not-A-Number (NaN)
+ Inf, // positive infinity
+ Neg_Inf // negative infinity
+};
+
TAU :: 6.28318530717958647692528676655900576;
PI :: 3.14159265358979323846264338327950288;
E :: 2.71828182845904523536;
-SQRT_TWO :: 1.41421356237309504880168872420969808;
-SQRT_THREE :: 1.73205080756887729352744634150587236;
-SQRT_FIVE :: 2.23606797749978969640917366873127623;
-
-LOG_TWO :: 0.693147180559945309417232121458176568;
-LOG_TEN :: 2.30258509299404568401799145468436421;
-
-EPSILON :: 1.19209290e-7;
Ï„ :: TAU;
Ï€ :: PI;
+e :: E;
-Vec2 :: distinct [2]f32;
-Vec3 :: distinct [3]f32;
-Vec4 :: distinct [4]f32;
+SQRT_TWO :: 1.41421356237309504880168872420969808;
+SQRT_THREE :: 1.73205080756887729352744634150587236;
+SQRT_FIVE :: 2.23606797749978969640917366873127623;
-// Column major
-Mat2 :: distinct [2][2]f32;
-Mat3 :: distinct [3][3]f32;
-Mat4 :: distinct [4][4]f32;
+LN2 :: 0.693147180559945309417232121458176568;
+LN10 :: 2.30258509299404568401799145468436421;
-Quat :: struct {x, y, z, w: f32};
+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'
-QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1};
+RAD_PER_DEG :: TAU/360.0;
+DEG_PER_RAD :: 360.0/TAU;
-@(default_calling_convention="c")
+@(default_calling_convention="none")
foreign _ {
@(link_name="llvm.sqrt.f32")
sqrt_f32 :: proc(x: f32) -> f32 ---;
@@ -58,9 +63,9 @@ foreign _ {
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
@(link_name="llvm.log.f32")
- log_f32 :: proc(x: f32) -> f32 ---;
+ ln_f32 :: proc(x: f32) -> f32 ---;
@(link_name="llvm.log.f64")
- log_f64 :: proc(x: f64) -> f64 ---;
+ ln_f64 :: proc(x: f64) -> f64 ---;
@(link_name="llvm.exp.f32")
exp_f32 :: proc(x: f32) -> f32 ---;
@@ -68,20 +73,40 @@ foreign _ {
exp_f64 :: proc(x: f64) -> f64 ---;
}
-log :: proc{log_f32, log_f64};
-exp :: proc{exp_f32, exp_f64};
+sqrt :: proc{sqrt_f32, sqrt_f64};
+sin :: proc{sin_f32, sin_f64};
+cos :: proc{cos_f32, cos_f64};
+pow :: proc{pow_f32, pow_f64};
+fmuladd :: proc{fmuladd_f32, fmuladd_f64};
+ln :: proc{ln_f32, ln_f64};
+exp :: proc{exp_f32, exp_f64};
+
+log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
+log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
+log :: proc{log_f32, log_f64};
+
+log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
+log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
+log2 :: proc{log2_f32, log2_f64};
+
+log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
+log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
+log10 :: proc{log10_f32, log10_f64};
+
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
+tan :: proc{tan_f32, tan_f64};
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
+unlerp :: proc{unlerp_f32, unlerp_f64};
-
-sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
-sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
+sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
+sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
+sign :: proc{sign_f32, sign_f64};
copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x;
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix |= iy & 0x8000_0000;
return transmute(f32)ix;
}
-
copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix := transmute(u64)x;
iy := transmute(u64)y;
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64)ix;
}
+copy_sign :: proc{copy_sign_f32, copy_sign_f64};
-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};
+to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
+to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
+to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
+to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
+to_radians :: proc{to_radians_f32, to_radians_f64};
+to_degrees :: proc{to_degrees_f32, to_degrees_f64};
+
+trunc_f32 :: proc(x: f32) -> f32 {
+ trunc_internal :: proc(f: f32) -> f32 {
+ mask :: 0xff;
+ shift :: 32 - 9;
+ bias :: 0x7f;
+
+ if f < 1 {
+ switch {
+ case f < 0: return -trunc_internal(-f);
+ case f == 0: return f;
+ case: return 0;
+ }
+ }
+ x := transmute(u32)f;
+ e := (x >> shift) & mask - bias;
-round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
-round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
+ if e < shift {
+ x &= ~(1 << (shift-e)) - 1;
+ }
+ return transmute(f32)x;
+ }
+ switch classify(x) {
+ case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
+ return x;
+ }
+ return trunc_internal(x);
+}
+
+trunc_f64 :: proc(x: f64) -> f64 {
+ trunc_internal :: proc(f: f64) -> f64 {
+ mask :: 0x7ff;
+ shift :: 64 - 12;
+ bias :: 0x3ff;
+
+ if f < 1 {
+ switch {
+ case f < 0: return -trunc_internal(-f);
+ case f == 0: return f;
+ case: return 0;
+ }
+ }
+
+ x := transmute(u64)f;
+ e := (x >> shift) & mask - bias;
+
+ if e < shift {
+ x &= ~(1 << (shift-e)) - 1;
+ }
+ return transmute(f64)x;
+ }
+ switch classify(x) {
+ case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
+ return x;
+ }
+ return trunc_internal(x);
+}
+
+trunc :: proc{trunc_f32, trunc_f64};
+
+round_f32 :: proc(x: f32) -> f32 {
+ return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
+}
+round_f64 :: proc(x: f64) -> f64 {
+ return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
+}
round :: proc{round_f32, round_f64};
+
+ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
+ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
+ceil :: proc{ceil_f32, ceil_f64};
+
floor_f32 :: proc(x: f32) -> f32 {
if x == 0 || is_nan(x) || is_inf(x) {
return x;
@@ -144,33 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
}
floor :: proc{floor_f32, floor_f64};
-ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); }
-ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); }
-ceil :: proc{ceil_f32, ceil_f64};
-remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
-remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
-remainder :: proc{remainder_f32, remainder_f64};
-
-mod_f32 :: proc(x, y: f32) -> (n: f32) {
- z := abs(y);
- n = remainder(abs(x), z);
- if sign(n) < 0 {
- n += z;
+floor_div :: proc(x, y: $T) -> T
+ where intrinsics.type_is_integer(T) {
+ a := x / y;
+ r := x % y;
+ if (r > 0 && y < 0) || (r < 0 && y > 0) {
+ a -= 1;
}
- return copy_sign(n, x);
+ return a;
}
-mod_f64 :: proc(x, y: f64) -> (n: f64) {
- z := abs(y);
- n = remainder(abs(x), z);
- if sign(n) < 0 {
- n += z;
+
+floor_mod :: proc(x, y: $T) -> T
+ where intrinsics.type_is_integer(T) {
+ r := x % y;
+ if (r > 0 && y < 0) || (r < 0 && y > 0) {
+ r += y;
}
- return copy_sign(n, x);
+ return r;
}
-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) {
shift :: 32 - 8 - 1;
mask :: 0xff;
@@ -190,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
i := transmute(u32)x;
e := uint(i>>shift)&mask - bias;
- if e < 32-9 {
- i &~= 1<<(32-9-e) - 1;
+ if e < shift {
+ i &~= 1<<(shift-e) - 1;
}
int = transmute(f32)i;
frac = x - int;
@@ -216,361 +301,275 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
i := transmute(u64)x;
e := uint(i>>shift)&mask - bias;
- if e < 64-12 {
- i &~= 1<<(64-12-e) - 1;
+ if e < shift {
+ i &~= 1<<(shift-e) - 1;
}
int = transmute(f64)i;
frac = x - int;
return;
}
modf :: proc{modf_f32, modf_f64};
+split_decimal :: modf;
-is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; }
-is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; }
-is_nan :: proc{is_nan_f32, is_nan_f64};
-
-is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); }
-is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); }
-is_finite :: proc{is_finite_f32, is_finite_f64};
-
-is_inf_f32 :: proc(x: f32, sign := 0) -> bool {
- return sign >= 0 && x > F32_MAX || sign <= 0 && x < -F32_MAX;
+mod_f32 :: proc(x, y: f32) -> (n: f32) {
+ z := abs(y);
+ n = remainder(abs(x), z);
+ if sign(n) < 0 {
+ n += z;
+ }
+ return copy_sign(n, x);
}
-is_inf_f64 :: proc(x: f64, sign := 0) -> bool {
- return sign >= 0 && x > F64_MAX || sign <= 0 && x < -F64_MAX;
+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);
}
-// 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};
-
-
-
-to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; }
-to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
-
-
-
+mod :: proc{mod_f32, mod_f64};
-mul :: proc{
- mat3_mul,
- mat4_mul, mat4_mul_vec4,
- quat_mul, quat_mulf,
-};
+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};
-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];
+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 res;
+ return abs(x);
}
-cross2 :: proc(a, b: $T/[2]$E) -> E {
- return a[0]*b[1] - a[1]*b[0];
+lcm :: proc(x, y: $T) -> T
+ where intrinsics.type_is_ordered_numeric(T) {
+ return x / gcd(x, y) * y;
}
-cross3 :: proc(a, b: $T/[3]$E) -> T {
- i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
- j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
- return T(i - j);
+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};
-length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); }
-
-norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); }
-norm0 :: proc(v: $T/[$N]$E) -> T {
- m := length(v);
- return m == 0 ? 0 : v/m;
-}
+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,
+ };
+ }
-identity :: proc($T: typeid/[$N][N]$E) -> T {
- m: T;
- for i in 0..<N do m[i][i] = E(1);
- return m;
+ assert(n >= 0, "parameter must not be negative");
+ assert(n < len(table), "parameter is too large to lookup in the table");
+ return 0;
}
-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];
+classify_f32 :: proc(x: f32) -> Float_Class {
+ switch {
+ case x == 0:
+ i := transmute(i32)x;
+ if i < 0 {
+ return .Neg_Zero;
}
- }
- return m;
-}
-
-mat3_mul :: proc(a, b: Mat3) -> Mat3 {
- c: Mat3;
- for j in 0..<3 {
- for i in 0..<3 {
- c[j][i] = a[0][i]*b[j][0] +
- a[1][i]*b[j][1] +
- a[2][i]*b[j][2];
+ return .Zero;
+ case x*0.5 == x:
+ if x < 0 {
+ return .Neg_Inf;
}
+ return .Inf;
+ case x != x:
+ return .NaN;
}
- return c;
-}
-mat4_mul :: proc(a, b: Mat4) -> Mat4 {
- c: Mat4;
- for j in 0..<4 {
- for i in 0..<4 {
- c[j][i] = a[0][i]*b[j][0] +
- a[1][i]*b[j][1] +
- a[2][i]*b[j][2] +
- a[3][i]*b[j][3];
+ 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;
}
- 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;
+ 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};
-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;
-}
-
+is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; }
+is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; }
+is_inf :: proc{is_inf_f32, is_inf_f64};
-// 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;
+is_power_of_two :: proc(x: int) -> bool {
+ return x > 0 && (x & (x-1)) == 0;
}
-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);
+next_power_of_two :: proc(x: int) -> int {
+ 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;
+}
+
+sum :: proc(x: $T/[]$E) -> (res: E)
+ where intrinsics.BuiltinProc_type_is_numeric(E) {
+ for i in x {
+ res += i;
+ }
+ return;
}
-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};
+prod :: proc(x: $T/[]$E) -> (res: E)
+ where intrinsics.BuiltinProc_type_is_numeric(E) {
+ for i in x {
+ res *= i;
+ }
+ return;
}
-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);
+cumsum_inplace :: proc(x: $T/[]$E) -> T
+ where intrinsics.BuiltinProc_type_is_numeric(E) {
+ for i in 1..<len(x) {
+ x[i] = x[i-1] + x[i];
+ }
}
-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;
+cumsum :: proc(dst, src: $T/[]$E) -> T
+ where intrinsics.BuiltinProc_type_is_numeric(E) {
+ N := min(len(dst), len(src));
+ if N > 0 {
+ dst[0] = src[0];
+ for i in 1..<N {
+ dst[i] = dst[i-1] + src[i];
+ }
+ }
+ return dst[:N];
}
-
-
F32_DIG :: 6;
F32_EPSILON :: 1.192092896e-07;
F32_GUARD :: 0;
diff --git a/core/math/rand/normal.odin b/core/math/rand/normal.odin
index 82c2dda6d..4e4810660 100644
--- a/core/math/rand/normal.odin
+++ b/core/math/rand/normal.odin
@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
if i == 0 {
for {
- x = -math.log(float64(r)) * (1.0/ rn);
- y := -math.log(float64(r));
+ x = -math.ln(float64(r)) * (1.0/ rn);
+ y := -math.ln(float64(r));
if y+y >= x*x {
break;
}
diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin
index 04b0fd0b1..7ef094bc1 100644
--- a/core/mem/allocators.odin
+++ b/core/mem/allocators.odin
@@ -1,7 +1,5 @@
package mem
-
-
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
diff --git a/core/mem/raw.odin b/core/mem/raw.odin
index c7f4ee9db..97cd71e7a 100644
--- a/core/mem/raw.odin
+++ b/core/mem/raw.odin
@@ -31,6 +31,12 @@ Raw_Map :: struct {
entries: Raw_Dynamic_Array,
}
+Raw_Complex64 :: struct {real, imag: f32};
+Raw_Complex128 :: struct {real, imag: f64};
+Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32};
+Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64};
+Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32};
+Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64};
make_any :: inline proc(data: rawptr, id: typeid) -> any {
return transmute(any)Raw_Any{data, id};
diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin
index c0d2948ee..309d2c147 100644
--- a/core/odin/ast/ast.odin
+++ b/core/odin/ast/ast.odin
@@ -1,11 +1,10 @@
package odin_ast
-import "core:odin/token"
+import "core:odin/tokenizer"
Proc_Tag :: enum {
Bounds_Check,
No_Bounds_Check,
- Require_Results,
}
Proc_Tags :: distinct bit_set[Proc_Tag; u32];
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
Comment_Group :: struct {
- list: []token.Token,
+ list: []tokenizer.Token,
}
Node :: struct {
- pos: token.Pos,
- end: token.Pos,
+ pos: tokenizer.Pos,
+ end: tokenizer.Pos,
derived: any,
state_flags: Node_State_Flags,
}
@@ -68,29 +67,29 @@ Ident :: struct {
Implicit :: struct {
using node: Expr,
- tok: token.Token,
+ tok: tokenizer.Token,
}
Undef :: struct {
using node: Expr,
- tok: token.Kind,
+ tok: tokenizer.Token_Kind,
}
Basic_Lit :: struct {
using node: Expr,
- tok: token.Token,
+ tok: tokenizer.Token,
}
Basic_Directive :: struct {
using node: Expr,
- tok: token.Token,
+ tok: tokenizer.Token,
name: string,
}
Ellipsis :: struct {
using node: Expr,
- tok: token.Kind,
+ tok: tokenizer.Token_Kind,
expr: ^Expr,
}
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
body: ^Stmt,
tags: Proc_Tags,
inlining: Proc_Inlining,
+ where_token: tokenizer.Token,
+ where_clauses: []^Expr,
}
Comp_Lit :: struct {
using node: Expr,
type: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
elems: []^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Tag_Expr :: struct {
using node: Expr,
- op: token.Token,
+ op: tokenizer.Token,
name: string,
expr: ^Expr,
}
Unary_Expr :: struct {
using node: Expr,
- op: token.Token,
+ op: tokenizer.Token,
expr: ^Expr,
}
Binary_Expr :: struct {
using node: Expr,
left: ^Expr,
- op: token.Token,
+ op: tokenizer.Token,
right: ^Expr,
}
Paren_Expr :: struct {
using node: Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
expr: ^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Selector_Expr :: struct {
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
index: ^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Deref_Expr :: struct {
using node: Expr,
expr: ^Expr,
- op: token.Token,
+ op: tokenizer.Token,
}
Slice_Expr :: struct {
using node: Expr,
expr: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
low: ^Expr,
- interval: token.Token,
+ interval: tokenizer.Token,
high: ^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Call_Expr :: struct {
using node: Expr,
inlining: Proc_Inlining,
expr: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
args: []^Expr,
- ellipsis: token.Token,
- close: token.Pos,
+ ellipsis: tokenizer.Token,
+ close: tokenizer.Pos,
}
Field_Value :: struct {
using node: Expr,
field: ^Expr,
- sep: token.Pos,
+ sep: tokenizer.Pos,
value: ^Expr,
}
Ternary_Expr :: struct {
using node: Expr,
cond: ^Expr,
- op1: token.Token,
+ op1: tokenizer.Token,
x: ^Expr,
- op2: token.Token,
+ op2: tokenizer.Token,
y: ^Expr,
}
Type_Assertion :: struct {
using node: Expr,
expr: ^Expr,
- dot: token.Pos,
- open: token.Pos,
+ dot: tokenizer.Pos,
+ open: tokenizer.Pos,
type: ^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Type_Cast :: struct {
using node: Expr,
- tok: token.Token,
- open: token.Pos,
+ tok: tokenizer.Token,
+ open: tokenizer.Pos,
type: ^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
expr: ^Expr,
}
Auto_Cast :: struct {
using node: Expr,
- op: token.Token,
+ op: tokenizer.Token,
expr: ^Expr,
}
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
Empty_Stmt :: struct {
using node: Stmt,
- semicolon: token.Pos, // Position of the following ';'
+ semicolon: tokenizer.Pos, // Position of the following ';'
}
Expr_Stmt :: struct {
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
Tag_Stmt :: struct {
using node: Stmt,
- op: token.Token,
+ op: tokenizer.Token,
name: string,
stmt: ^Stmt,
}
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
Assign_Stmt :: struct {
using node: Stmt,
lhs: []^Expr,
- op: token.Token,
+ op: tokenizer.Token,
rhs: []^Expr,
}
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
Block_Stmt :: struct {
using node: Stmt,
label: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
stmts: []^Stmt,
- close: token.Pos,
+ close: tokenizer.Pos,
}
If_Stmt :: struct {
using node: Stmt,
label: ^Expr,
- if_pos: token.Pos,
+ if_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
@@ -277,7 +278,7 @@ If_Stmt :: struct {
When_Stmt :: struct {
using node: Stmt,
- when_pos: token.Pos,
+ when_pos: tokenizer.Pos,
cond: ^Expr,
body: ^Stmt,
else_stmt: ^Stmt,
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
For_Stmt :: struct {
using node: Stmt,
label: ^Expr,
- for_pos: token.Pos,
+ for_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
post: ^Stmt,
@@ -306,10 +307,10 @@ For_Stmt :: struct {
Range_Stmt :: struct {
using node: Stmt,
label: ^Expr,
- for_pos: token.Pos,
+ for_pos: tokenizer.Pos,
val0: ^Expr,
val1: ^Expr,
- in_pos: token.Pos,
+ in_pos: tokenizer.Pos,
expr: ^Expr,
body: ^Stmt,
}
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
Case_Clause :: struct {
using node: Stmt,
- case_pos: token.Pos,
+ case_pos: tokenizer.Pos,
list: []^Expr,
- terminator: token.Token,
+ terminator: tokenizer.Token,
body: []^Stmt,
}
Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
- switch_pos: token.Pos,
+ switch_pos: tokenizer.Pos,
init: ^Stmt,
cond: ^Expr,
body: ^Stmt,
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
Type_Switch_Stmt :: struct {
using node: Stmt,
label: ^Expr,
- switch_pos: token.Pos,
+ switch_pos: tokenizer.Pos,
tag: ^Stmt,
expr: ^Expr,
body: ^Stmt,
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
Branch_Stmt :: struct {
using node: Stmt,
- tok: token.Token,
+ tok: tokenizer.Token,
label: ^Ident,
}
@@ -376,7 +377,7 @@ Value_Decl :: struct {
Package_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
- token: token.Token,
+ token: tokenizer.Token,
name: string,
comment: ^Comment_Group,
}
@@ -385,9 +386,9 @@ Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
is_using: bool,
- import_tok: token.Token,
- name: token.Token,
- relpath: token.Token,
+ import_tok: tokenizer.Token,
+ name: tokenizer.Token,
+ relpath: tokenizer.Token,
fullpath: string,
comment: ^Comment_Group,
}
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
- tok: token.Token,
+ tok: tokenizer.Token,
foreign_library: ^Expr,
body: ^Stmt,
}
@@ -404,8 +405,8 @@ Foreign_Block_Decl :: struct {
Foreign_Import_Decl :: struct {
using node: Decl,
docs: ^Comment_Group,
- foreign_tok: token.Token,
- import_tok: token.Token,
+ foreign_tok: tokenizer.Token,
+ import_tok: tokenizer.Token,
name: ^Ident,
collection_name: string,
fullpaths: []string,
@@ -435,7 +436,9 @@ Field_Flag :: enum {
C_Vararg,
Auto_Cast,
In,
+
Results,
+ Tags,
Default_Parameters,
Typeid_Token,
}
@@ -443,18 +446,19 @@ Field_Flag :: enum {
Field_Flags :: distinct bit_set[Field_Flag];
Field_Flags_Struct :: Field_Flags{
- Field_Flag.Using,
+ .Using,
+ .Tags,
};
Field_Flags_Record_Poly_Params :: Field_Flags{
- Field_Flag.Typeid_Token,
+ .Typeid_Token,
};
Field_Flags_Signature :: Field_Flags{
- Field_Flag.Ellipsis,
- Field_Flag.Using,
- Field_Flag.No_Alias,
- Field_Flag.C_Vararg,
- Field_Flag.Auto_Cast,
- Field_Flag.Default_Parameters,
+ .Ellipsis,
+ .Using,
+ .No_Alias,
+ .C_Vararg,
+ .Auto_Cast,
+ .Default_Parameters,
};
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
@@ -463,18 +467,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
Proc_Group :: struct {
using node: Expr,
- tok: token.Token,
- open: token.Pos,
+ tok: tokenizer.Token,
+ open: tokenizer.Pos,
args: []^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Attribute :: struct {
using node: Node,
- tok: token.Kind,
- open: token.Pos,
+ tok: tokenizer.Token_Kind,
+ open: tokenizer.Pos,
elems: []^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Field :: struct {
@@ -483,56 +487,57 @@ Field :: struct {
names: []^Expr, // Could be polymorphic
type: ^Expr,
default_value: ^Expr,
+ tag: tokenizer.Token,
flags: Field_Flags,
comment: ^Comment_Group,
}
Field_List :: struct {
using node: Node,
- open: token.Pos,
+ open: tokenizer.Pos,
list: []^Field,
- close: token.Pos,
+ close: tokenizer.Pos,
}
// Types
Typeid_Type :: struct {
using node: Expr,
- tok: token.Kind,
+ tok: tokenizer.Token_Kind,
specialization: ^Expr,
}
Helper_Type :: struct {
using node: Expr,
- tok: token.Kind,
+ tok: tokenizer.Token_Kind,
type: ^Expr,
}
Distinct_Type :: struct {
using node: Expr,
- tok: token.Kind,
+ tok: tokenizer.Token_Kind,
type: ^Expr,
}
Opaque_Type :: struct {
using node: Expr,
- tok: token.Kind,
+ tok: tokenizer.Token_Kind,
type: ^Expr,
}
Poly_Type :: struct {
using node: Expr,
- dollar: token.Pos,
+ dollar: tokenizer.Pos,
type: ^Ident,
specialization: ^Expr,
}
Proc_Type :: struct {
using node: Expr,
- tok: token.Token,
+ tok: tokenizer.Token,
calling_convention: Proc_Calling_Convention,
params: ^Field_List,
- arrow: token.Pos,
+ arrow: tokenizer.Pos,
results: ^Field_List,
tags: Proc_Tags,
generic: bool,
@@ -541,77 +546,81 @@ Proc_Type :: struct {
Pointer_Type :: struct {
using node: Expr,
- pointer: token.Pos,
+ pointer: tokenizer.Pos,
elem: ^Expr,
}
Array_Type :: struct {
using node: Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
- close: token.Pos,
+ close: tokenizer.Pos,
elem: ^Expr,
}
Dynamic_Array_Type :: struct {
using node: Expr,
- open: token.Pos,
- dynamic_pos: token.Pos,
- close: token.Pos,
+ open: tokenizer.Pos,
+ dynamic_pos: tokenizer.Pos,
+ close: tokenizer.Pos,
elem: ^Expr,
}
Struct_Type :: struct {
using node: Expr,
- tok_pos: token.Pos,
- poly_params: ^Field_List,
- align: ^Expr,
- is_packed: bool,
- is_raw_union: bool,
- fields: ^Field_List,
- name_count: int,
+ tok_pos: tokenizer.Pos,
+ poly_params: ^Field_List,
+ align: ^Expr,
+ fields: ^Field_List,
+ name_count: int,
+ where_token: tokenizer.Token,
+ where_clauses: []^Expr,
+ is_packed: bool,
+ is_raw_union: bool,
}
Union_Type :: struct {
using node: Expr,
- tok_pos: token.Pos,
+ tok_pos: tokenizer.Pos,
poly_params: ^Field_List,
align: ^Expr,
variants: []^Expr,
+ where_token: tokenizer.Token,
+ where_clauses: []^Expr,
}
Enum_Type :: struct {
using node: Expr,
- tok_pos: token.Pos,
+ tok_pos: tokenizer.Pos,
base_type: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
fields: []^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
is_using: bool,
}
Bit_Field_Type :: struct {
using node: Expr,
- tok_pos: token.Pos,
+ tok_pos: tokenizer.Pos,
align: ^Expr,
- open: token.Pos,
+ open: tokenizer.Pos,
fields: []^Field_Value, // Field_Value with ':' rather than '='
- close: token.Pos,
+ close: tokenizer.Pos,
}
Bit_Set_Type :: struct {
using node: Expr,
- tok_pos: token.Pos,
- open: token.Pos,
+ tok_pos: tokenizer.Pos,
+ open: tokenizer.Pos,
elem: ^Expr,
underlying: ^Expr,
- close: token.Pos,
+ close: tokenizer.Pos,
}
Map_Type :: struct {
using node: Expr,
- tok_pos: token.Pos,
+ tok_pos: tokenizer.Pos,
key: ^Expr,
value: ^Expr,
}
diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin
index ded47a931..ddb3068f1 100644
--- a/core/odin/ast/clone.odin
+++ b/core/odin/ast/clone.odin
@@ -2,9 +2,9 @@ package odin_ast
import "core:mem"
import "core:fmt"
-import "core:odin/token"
+import "core:odin/tokenizer"
-new :: proc($T: typeid, pos, end: token.Pos) -> ^T {
+new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
n := mem.new(T);
n.pos = pos;
n.end = end;
diff --git a/core/odin/ast/file.odin b/core/odin/ast/file.odin
index 9d7550f45..dafb10e14 100644
--- a/core/odin/ast/file.odin
+++ b/core/odin/ast/file.odin
@@ -1,6 +1,6 @@
package odin_ast
-import "core:odin/token"
+import "core:odin/tokenizer"
Package_Kind :: enum {
Normal,
@@ -26,7 +26,7 @@ File :: struct {
src: []byte,
pkg_decl: ^Package_Decl,
- pkg_token: token.Token,
+ pkg_token: tokenizer.Token,
pkg_name: string,
decls: [dynamic]^Stmt,
diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin
index 077e04cc9..fb3a87e8b 100644
--- a/core/odin/parser/parser.odin
+++ b/core/odin/parser/parser.odin
@@ -1,13 +1,12 @@
package odin_parser
import "core:odin/ast"
-import "core:odin/token"
import "core:odin/tokenizer"
import "core:fmt"
-Warning_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
-Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
+Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any);
+Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any);
Parser :: struct {
file: ^ast.File,
@@ -16,8 +15,8 @@ Parser :: struct {
warn: Warning_Handler,
err: Error_Handler,
- prev_tok: token.Token,
- curr_tok: token.Token,
+ prev_tok: tokenizer.Token,
+ curr_tok: tokenizer.Token,
// >= 0: In Expression
// < 0: In Control Clause
@@ -50,25 +49,25 @@ Import_Decl_Kind :: enum {
-default_warning_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
- fmt.printf_err("%s(%d:%d): Warning: ", pos.file, pos.line, pos.column);
- fmt.printf_err(msg, ..args);
- fmt.printf_err("\n");
+default_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) {
+ fmt.eprintf("%s(%d:%d): Warning: ", pos.file, pos.line, pos.column);
+ fmt.eprintf(msg, ..args);
+ fmt.eprintf("\n");
}
-default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
- fmt.printf_err("%s(%d:%d): ", pos.file, pos.line, pos.column);
- fmt.printf_err(msg, ..args);
- fmt.printf_err("\n");
+default_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) {
+ fmt.eprintf("%s(%d:%d): ", pos.file, pos.line, pos.column);
+ fmt.eprintf(msg, ..args);
+ fmt.eprintf("\n");
}
-warn :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) {
+warn :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, args: ..any) {
if p.warn != nil {
p.warn(pos, msg, ..args);
}
p.file.syntax_warning_count += 1;
}
-error :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) {
+error :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, args: ..any) {
if p.err != nil {
p.err(pos, msg, ..args);
}
@@ -77,11 +76,11 @@ error :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) {
}
-end_pos :: proc(tok: token.Token) -> token.Pos {
+end_pos :: proc(tok: tokenizer.Token) -> tokenizer.Pos {
pos := tok.pos;
pos.offset += len(tok.text);
- if tok.kind == token.Comment {
+ if tok.kind == .Comment {
if tok.text[:2] != "/*" {
pos.column += len(tok.text);
} else {
@@ -133,13 +132,13 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
docs := p.lead_comment;
- p.file.pkg_token = expect_token(p, token.Package);
- if p.file.pkg_token.kind != token.Package {
+ p.file.pkg_token = expect_token(p, .Package);
+ if p.file.pkg_token.kind != .Package {
return false;
}
- pkg_name := expect_token_after(p, token.Ident, "package");
- if pkg_name.kind == token.Ident {
+ pkg_name := expect_token_after(p, .Ident, "package");
+ if pkg_name.kind == .Ident {
if is_blank_ident(pkg_name) {
error(p, pkg_name.pos, "invalid package name '_'");
}
@@ -161,7 +160,7 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
p.file.decls = make([dynamic]^ast.Stmt);
- for p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != .EOF {
stmt := parse_stmt(p);
if stmt != nil {
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
@@ -181,16 +180,16 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
next_token0 :: proc(p: ^Parser) -> bool {
p.curr_tok = tokenizer.scan(&p.tok);
- if p.curr_tok.kind == token.EOF {
+ if p.curr_tok.kind == .EOF {
// error(p, p.curr_tok.pos, "token is EOF");
return false;
}
return true;
}
-consume_comment :: proc(p: ^Parser) -> (tok: token.Token, end_line: int) {
+consume_comment :: proc(p: ^Parser) -> (tok: tokenizer.Token, end_line: int) {
tok = p.curr_tok;
- assert(tok.kind == token.Comment);
+ assert(tok.kind == .Comment);
end_line = tok.pos.line;
if tok.text[1] == '*' {
@@ -210,11 +209,11 @@ consume_comment :: proc(p: ^Parser) -> (tok: token.Token, end_line: int) {
}
consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Group, end_line: int) {
- list: [dynamic]token.Token;
+ list: [dynamic]tokenizer.Token;
end_line = p.curr_tok.pos.line;
- for p.curr_tok.kind == token.Comment &&
+ for p.curr_tok.kind == .Comment &&
p.curr_tok.pos.line <= end_line+n {
- comment: token.Token;
+ comment: tokenizer.Token;
comment, end_line = consume_comment(p);
append(&list, comment);
}
@@ -228,31 +227,31 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro
return;
}
-consume_comment_groups :: proc(p: ^Parser, prev: token.Token) {
- if p.curr_tok.kind == token.Comment {
+consume_comment_groups :: proc(p: ^Parser, prev: tokenizer.Token) {
+ if p.curr_tok.kind == .Comment {
comment: ^ast.Comment_Group;
end_line := 0;
if p.curr_tok.pos.line == prev.pos.line {
comment, end_line = consume_comment_group(p, 0);
- if p.curr_tok.pos.line != end_line || p.curr_tok.kind == token.EOF {
+ if p.curr_tok.pos.line != end_line || p.curr_tok.kind == .EOF {
p.line_comment = comment;
}
}
end_line = -1;
- for p.curr_tok.kind == token.Comment {
+ for p.curr_tok.kind == .Comment {
comment, end_line = consume_comment_group(p, 1);
}
if end_line+1 >= p.curr_tok.pos.line || end_line < 0 {
p.lead_comment = comment;
}
- assert(p.curr_tok.kind != token.Comment);
+ assert(p.curr_tok.kind != .Comment);
}
}
-advance_token :: proc(p: ^Parser) -> token.Token {
+advance_token :: proc(p: ^Parser) -> tokenizer.Token {
p.lead_comment = nil;
p.line_comment = nil;
p.prev_tok = p.curr_tok;
@@ -264,39 +263,39 @@ advance_token :: proc(p: ^Parser) -> token.Token {
return prev;
}
-expect_token :: proc(p: ^Parser, kind: token.Kind) -> token.Token {
+expect_token :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> tokenizer.Token {
prev := p.curr_tok;
if prev.kind != kind {
- e := token.to_string(kind);
- g := token.to_string(prev.kind);
+ e := tokenizer.to_string(kind);
+ g := tokenizer.to_string(prev.kind);
error(p, prev.pos, "expected '%s', got '%s'", e, g);
}
advance_token(p);
return prev;
}
-expect_token_after :: proc(p: ^Parser, kind: token.Kind, msg: string) -> token.Token {
+expect_token_after :: proc(p: ^Parser, kind: tokenizer.Token_Kind, msg: string) -> tokenizer.Token {
prev := p.curr_tok;
if prev.kind != kind {
- e := token.to_string(kind);
- g := token.to_string(prev.kind);
+ e := tokenizer.to_string(kind);
+ g := tokenizer.to_string(prev.kind);
error(p, prev.pos, "expected '%s' after %s, got '%s'", e, msg, g);
}
advance_token(p);
return prev;
}
-expect_operator :: proc(p: ^Parser) -> token.Token {
+expect_operator :: proc(p: ^Parser) -> tokenizer.Token {
prev := p.curr_tok;
- if !token.is_operator(prev.kind) {
- g := token.to_string(prev.kind);
+ if !tokenizer.is_operator(prev.kind) {
+ g := tokenizer.to_string(prev.kind);
error(p, prev.pos, "expected an operator, got '%s'", g);
}
advance_token(p);
return prev;
}
-allow_token :: proc(p: ^Parser, kind: token.Kind) -> bool {
+allow_token :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> bool {
if p.curr_tok.kind == kind {
advance_token(p);
return true;
@@ -313,8 +312,8 @@ is_blank_ident :: proc{
is_blank_ident_string :: inline proc(str: string) -> bool {
return str == "_";
}
-is_blank_ident_token :: inline proc(tok: token.Token) -> bool {
- if tok.kind == token.Ident {
+is_blank_ident_token :: inline proc(tok: tokenizer.Token) -> bool {
+ if tok.kind == .Ident {
return is_blank_ident_string(tok.text);
}
return false;
@@ -347,7 +346,8 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
case ast.Pointer_Type:
return is_semicolon_optional_for_node(p, n.elem);
case ast.Struct_Type, ast.Union_Type, ast.Enum_Type, ast.Bit_Field_Type:
- return true;
+ // Require semicolon within a procedure body
+ return p.curr_proc == nil;
case ast.Proc_Lit:
return true;
@@ -371,16 +371,16 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool {
- if allow_token(p, token.Semicolon) {
+ if allow_token(p, .Semicolon) {
return true;
}
prev := p.prev_tok;
- if prev.kind == token.Semicolon {
+ if prev.kind == .Semicolon {
return true;
}
- if p.curr_tok.kind == token.EOF {
+ if p.curr_tok.kind == .EOF {
return true;
}
@@ -391,20 +391,20 @@ expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool {
}
} else {
switch p.curr_tok.kind {
- case token.Close_Brace:
- case token.Close_Paren:
- case token.Else:
+ case .Close_Brace:
+ case .Close_Paren:
+ case .Else:
return true;
}
}
}
- error(p, prev.pos, "expected ';', got %s", token.to_string(prev.kind));
+ error(p, prev.pos, "expected ';', got %s", tokenizer.to_string(prev.kind));
return false;
}
-new_blank_ident :: proc(p: ^Parser, pos: token.Pos) -> ^ast.Ident {
- tok: token.Token;
+new_blank_ident :: proc(p: ^Parser, pos: tokenizer.Pos) -> ^ast.Ident {
+ tok: tokenizer.Token;
tok.pos = pos;
i := ast.new(ast.Ident, pos, end_pos(tok));
i.name = "_";
@@ -415,11 +415,11 @@ parse_ident :: proc(p: ^Parser) -> ^ast.Ident {
tok := p.curr_tok;
pos := tok.pos;
name := "_";
- if tok.kind == token.Ident {
+ if tok.kind == .Ident {
name = tok.text;
advance_token(p);
} else {
- expect_token(p, token.Ident);
+ expect_token(p, .Ident);
}
i := ast.new(ast.Ident, pos, end_pos(tok));
i.name = name;
@@ -428,9 +428,9 @@ parse_ident :: proc(p: ^Parser) -> ^ast.Ident {
parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt {
list: [dynamic]^ast.Stmt;
- for p.curr_tok.kind != token.Case &&
- p.curr_tok.kind != token.Close_Brace &&
- p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != .Case &&
+ p.curr_tok.kind != .Close_Brace &&
+ p.curr_tok.kind != .EOF {
stmt := parse_stmt(p);
if stmt != nil {
if _, ok := stmt.derived.(ast.Empty_Stmt); !ok {
@@ -454,7 +454,7 @@ parse_block_stmt :: proc(p: ^Parser, is_when: bool) -> ^ast.Stmt {
}
parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt {
- tok := expect_token(p, token.When);
+ tok := expect_token(p, .When);
cond: ^ast.Expr;
body: ^ast.Stmt;
@@ -468,20 +468,20 @@ parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt {
if cond == nil {
error(p, p.curr_tok.pos, "expected a condition for when statement");
}
- if allow_token(p, token.Do) {
+ if allow_token(p, .Do) {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_block_stmt(p, true);
}
- if allow_token(p, token.Else) {
+ if allow_token(p, .Else) {
switch p.curr_tok.kind {
- case token.When:
+ case .When:
else_stmt = parse_when_stmt(p);
- case token.Open_Brace:
+ case .Open_Brace:
else_stmt = parse_block_stmt(p, true);
- case token.Do:
- expect_token(p, token.Do);
+ case .Do:
+ expect_token(p, .Do);
else_stmt = convert_stmt_to_body(p, parse_stmt(p));
case:
error(p, p.curr_tok.pos, "expected when statement block statement");
@@ -513,7 +513,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast.
}
parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
- tok := expect_token(p, token.If);
+ tok := expect_token(p, .If);
init: ^ast.Stmt;
cond: ^ast.Expr;
@@ -524,11 +524,11 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
p.expr_level = -1;
prev_allow_in_expr := p.allow_in_expr;
p.allow_in_expr = true;
- if allow_token(p, token.Semicolon) {
+ if allow_token(p, .Semicolon) {
cond = parse_expr(p, false);
} else {
init = parse_simple_stmt(p, nil);
- if allow_token(p, token.Semicolon) {
+ if allow_token(p, .Semicolon) {
cond = parse_expr(p, false);
} else {
cond = convert_stmt_to_expr(p, init, "boolean expression");
@@ -543,20 +543,20 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
error(p, p.curr_tok.pos, "expected a condition for if statement");
}
- if allow_token(p, token.Do) {
+ if allow_token(p, .Do) {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_block_stmt(p, false);
}
- if allow_token(p, token.Else) {
+ if allow_token(p, .Else) {
switch p.curr_tok.kind {
- case token.If:
+ case .If:
else_stmt = parse_if_stmt(p);
- case token.Open_Brace:
+ case .Open_Brace:
else_stmt = parse_block_stmt(p, false);
- case token.Do:
- expect_token(p, token.Do);
+ case .Do:
+ expect_token(p, .Do);
else_stmt = convert_stmt_to_body(p, parse_stmt(p));
case:
error(p, p.curr_tok.pos, "expected if statement block statement");
@@ -582,7 +582,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
error(p, p.curr_tok.pos, "you cannot use a for statement in the file scope");
}
- tok := expect_token(p, token.For);
+ tok := expect_token(p, .For);
init: ^ast.Stmt;
cond: ^ast.Stmt;
@@ -590,13 +590,13 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body: ^ast.Stmt;
is_range := false;
- if p.curr_tok.kind != token.Open_Brace && p.curr_tok.kind != token.Do {
+ if p.curr_tok.kind != .Open_Brace && p.curr_tok.kind != .Do {
prev_level := p.expr_level;
defer p.expr_level = prev_level;
p.expr_level = -1;
- if p.curr_tok.kind == token.In {
- in_tok := expect_token(p, token.In);
+ if p.curr_tok.kind == .In {
+ in_tok := expect_token(p, .In);
rhs: ^ast.Expr;
prev_allow_range := p.allow_range;
@@ -604,7 +604,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
rhs = parse_expr(p, false);
p.allow_range = prev_allow_range;
- if allow_token(p, token.Do) {
+ if allow_token(p, .Do) {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_body(p);
@@ -618,27 +618,27 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return range_stmt;
}
- if p.curr_tok.kind != token.Semicolon {
+ if p.curr_tok.kind != .Semicolon {
cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In});
- if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == token.In {
+ if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
is_range = true;
}
}
- if !is_range && allow_token(p, token.Semicolon) {
+ if !is_range && allow_token(p, .Semicolon) {
init = cond;
cond = nil;
- if p.curr_tok.kind != token.Semicolon {
+ if p.curr_tok.kind != .Semicolon {
cond = parse_simple_stmt(p, nil);
}
expect_semicolon(p, cond);
- if p.curr_tok.kind != token.Open_Brace && p.curr_tok.kind != token.Do {
+ if p.curr_tok.kind != .Open_Brace && p.curr_tok.kind != .Do {
post = parse_simple_stmt(p, nil);
}
}
}
- if allow_token(p, token.Do) {
+ if allow_token(p, .Do) {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_body(p);
@@ -686,11 +686,11 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
}
parse_case_clause :: proc(p: ^Parser, is_type_switch: bool) -> ^ast.Case_Clause {
- tok := expect_token(p, token.Case);
+ tok := expect_token(p, .Case);
list: []^ast.Expr;
- if p.curr_tok.kind != token.Colon {
+ if p.curr_tok.kind != .Colon {
prev_allow_range, prev_allow_in_expr := p.allow_range, p.allow_in_expr;
defer p.allow_range, p.allow_in_expr = prev_allow_range, prev_allow_in_expr;
p.allow_range, p.allow_in_expr = !is_type_switch, !is_type_switch;
@@ -698,7 +698,7 @@ parse_case_clause :: proc(p: ^Parser, is_type_switch: bool) -> ^ast.Case_Clause
list = parse_rhs_expr_list(p);
}
- terminator := expect_token(p, token.Colon);
+ terminator := expect_token(p, .Colon);
stmts := parse_stmt_list(p);
@@ -710,20 +710,20 @@ parse_case_clause :: proc(p: ^Parser, is_type_switch: bool) -> ^ast.Case_Clause
}
parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
- tok := expect_token(p, token.Switch);
+ tok := expect_token(p, .Switch);
init: ^ast.Stmt;
tag: ^ast.Stmt;
is_type_switch := false;
clauses: [dynamic]^ast.Stmt;
- if p.curr_tok.kind != token.Open_Brace {
+ if p.curr_tok.kind != .Open_Brace {
prev_level := p.expr_level;
defer p.expr_level = prev_level;
p.expr_level = -1;
- if p.curr_tok.kind == token.In {
- in_tok := expect_token(p, token.In);
+ if p.curr_tok.kind == .In {
+ in_tok := expect_token(p, .In);
is_type_switch = true;
lhs := make([]^ast.Expr, 1);
@@ -738,12 +738,12 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
tag = as;
} else {
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In});
- if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == token.In {
+ if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
is_type_switch = true;
- } else if allow_token(p, token.Semicolon) {
+ } else if allow_token(p, .Semicolon) {
init = tag;
tag = nil;
- if p.curr_tok.kind != token.Open_Brace {
+ if p.curr_tok.kind != .Open_Brace {
tag = parse_simple_stmt(p, nil);
}
}
@@ -751,14 +751,14 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
}
- open := expect_token(p, token.Open_Brace);
+ open := expect_token(p, .Open_Brace);
- for p.curr_tok.kind == token.Case {
+ for p.curr_tok.kind == .Case {
clause := parse_case_clause(p, is_type_switch);
append(&clauses, clause);
}
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
body := ast.new(ast.Block_Stmt, open.pos, end_pos(close));
body.stmts = clauses[:];
@@ -778,23 +778,23 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
}
}
-parse_attribute :: proc(p: ^Parser, tok: token.Token, open_kind, close_kind: token.Kind, docs: ^ast.Comment_Group) -> ^ast.Stmt {
+parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: tokenizer.Token_Kind, docs: ^ast.Comment_Group) -> ^ast.Stmt {
elems: [dynamic]^ast.Expr;
- open, close: token.Token;
+ open, close: tokenizer.Token;
- if p.curr_tok.kind == token.Ident {
+ if p.curr_tok.kind == .Ident {
elem := parse_ident(p);
append(&elems, elem);
} else {
open = expect_token(p, open_kind);
p.expr_level += 1;
for p.curr_tok.kind != close_kind &&
- p.curr_tok.kind != token.EOF {
+ p.curr_tok.kind != .EOF {
elem: ^ast.Expr;
elem = parse_ident(p);
- if p.curr_tok.kind == token.Eq {
- eq := expect_token(p, token.Eq);
+ if p.curr_tok.kind == .Eq {
+ eq := expect_token(p, .Eq);
value := parse_value(p);
fv := ast.new(ast.Field_Value, elem.pos, value.end);
fv.field = elem;
@@ -805,7 +805,7 @@ parse_attribute :: proc(p: ^Parser, tok: token.Token, open_kind, close_kind: tok
}
append(&elems, elem);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
@@ -852,12 +852,12 @@ parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt {
}
-parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_Decl {
+parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Block_Decl {
docs := p.lead_comment;
foreign_library: ^ast.Expr;
switch p.curr_tok.kind {
- case token.Open_Brace:
+ case .Open_Brace:
i := ast.new(ast.Ident, tok.pos, end_pos(tok));
i.name = "_";
foreign_library = i;
@@ -871,14 +871,14 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_
defer p.in_foreign_block = prev_in_foreign_block;
p.in_foreign_block = true;
- open := expect_token(p, token.Open_Brace);
- for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF {
+ open := expect_token(p, .Open_Brace);
+ for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
decl := parse_foreign_block_decl(p);
if decl != nil {
append(&decls, decl);
}
}
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
body := ast.new(ast.Block_Stmt, open.pos, end_pos(close));
body.open = open.pos;
@@ -896,16 +896,16 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_
parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
docs := p.lead_comment;
- tok := expect_token(p, token.Foreign);
+ tok := expect_token(p, .Foreign);
switch p.curr_tok.kind {
- case token.Ident, token.Open_Brace:
+ case .Ident, .Open_Brace:
return parse_foreign_block(p, tok);
- case token.Import:
- import_tok := expect_token(p, token.Import);
+ case .Import:
+ import_tok := expect_token(p, .Import);
name: ^ast.Ident;
- if p.curr_tok.kind == token.Ident {
+ if p.curr_tok.kind == .Ident {
name = parse_ident(p);
}
@@ -914,19 +914,19 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
}
fullpaths: [dynamic]string;
- if allow_token(p, token.Open_Brace) {
- for p.curr_tok.kind != token.Close_Brace &&
- p.curr_tok.kind != token.EOF {
- path := expect_token(p, token.String);
+ if allow_token(p, .Open_Brace) {
+ for p.curr_tok.kind != .Close_Brace &&
+ p.curr_tok.kind != .EOF {
+ path := expect_token(p, .String);
append(&fullpaths, path.text);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
- expect_token(p, token.Close_Brace);
+ expect_token(p, .Close_Brace);
} else {
- path := expect_token(p, token.String);
+ path := expect_token(p, .String);
reserve(&fullpaths, 1);
append(&fullpaths, path.text);
}
@@ -954,28 +954,29 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
switch p.curr_tok.kind {
// Operands
- case token.Context, // Also allows for 'context = '
- token.Inline, token.No_Inline,
- token.Ident,
- token.Integer, token.Float, token.Imag,
- token.Rune, token.String,
- token.Open_Paren,
- token.Pointer,
+ case .Context, // Also allows for 'context = '
+ .Proc,
+ .Inline, .No_Inline,
+ .Ident,
+ .Integer, .Float, .Imag,
+ .Rune, .String,
+ .Open_Paren,
+ .Pointer,
// Unary Expressions
- token.Add, token.Sub, token.Xor, token.Not, token.And:
+ .Add, .Sub, .Xor, .Not, .And:
s := parse_simple_stmt(p, {Stmt_Allow_Flag.Label});
expect_semicolon(p, s);
return s;
- case token.Import: return parse_import_decl(p);
- case token.Foreign: return parse_foreign_decl(p);
- case token.If: return parse_if_stmt(p);
- case token.When: return parse_when_stmt(p);
- case token.For: return parse_for_stmt(p);
- case token.Switch: return parse_switch_stmt(p);
+ case .Import: return parse_import_decl(p);
+ case .Foreign: return parse_foreign_decl(p);
+ case .If: return parse_if_stmt(p);
+ case .When: return parse_when_stmt(p);
+ case .For: return parse_for_stmt(p);
+ case .Switch: return parse_switch_stmt(p);
- case token.Defer:
+ case .Defer:
tok := advance_token(p);
stmt := parse_stmt(p);
switch s in stmt.derived {
@@ -991,7 +992,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
ds.stmt = stmt;
return ds;
- case token.Return:
+ case .Return:
tok := advance_token(p);
if p.expr_level > 0 {
@@ -999,11 +1000,11 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
}
results: [dynamic]^ast.Expr;
- for p.curr_tok.kind != token.Semicolon {
+ for p.curr_tok.kind != .Semicolon {
result := parse_expr(p, false);
append(&results, result);
- if p.curr_tok.kind != token.Comma ||
- p.curr_tok.kind == token.EOF {
+ if p.curr_tok.kind != .Comma ||
+ p.curr_tok.kind == .EOF {
break;
}
advance_token(p);
@@ -1018,10 +1019,10 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
rs.results = results[:];
return rs;
- case token.Break, token.Continue, token.Fallthrough:
+ case .Break, .Continue, .Fallthrough:
tok := advance_token(p);
label: ^ast.Expr;
- if tok.kind != token.Fallthrough && p.curr_tok.kind == token.Ident {
+ if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident {
label = parse_ident(p);
}
end := label != nil ? label.end : end_pos(tok);
@@ -1029,11 +1030,11 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
expect_semicolon(p, s);
return s;
- case token.Using:
+ case .Using:
docs := p.lead_comment;
- tok := expect_token(p, token.Using);
+ tok := expect_token(p, .Using);
- if p.curr_tok.kind == token.Import {
+ if p.curr_tok.kind == .Import {
return parse_import_decl(p, Import_Decl_Kind.Using);
}
@@ -1044,14 +1045,14 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok));
}
- if p.curr_tok.kind != token.Colon {
+ if p.curr_tok.kind != .Colon {
end := list[len(list)-1];
expect_semicolon(p, end);
us := ast.new(ast.Using_Stmt, tok.pos, end.end);
us.list = list;
return us;
}
- expect_token_after(p, token.Colon, "identifier list");
+ expect_token_after(p, .Colon, "identifier list");
decl := parse_value_decl(p, list, docs);
if decl != nil do switch d in &decl.derived {
case ast.Value_Decl:
@@ -1062,14 +1063,14 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
error(p, tok.pos, "illegal use of 'using' statement");
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok));
- case token.At:
+ case .At:
docs := p.lead_comment;
tok := advance_token(p);
- return parse_attribute(p, tok, token.Open_Paren, token.Close_Paren, docs);
+ return parse_attribute(p, tok, .Open_Paren, .Close_Paren, docs);
- case token.Hash:
- tok := expect_token(p, token.Hash);
- tag := expect_token(p, token.Ident);
+ case .Hash:
+ tok := expect_token(p, .Hash);
+ tag := expect_token(p, .Ident);
name := tag.text;
switch name {
@@ -1090,7 +1091,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case: error(p, stmt.pos, "#complete can only be applied to a switch statement");
}
return stmt;
- case "assert":
+ case "assert", "panic":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(tag));
bd.tok = tok;
bd.name = name;
@@ -1109,51 +1110,51 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
te.stmt = stmt;
return te;
}
- case token.Open_Brace:
+ case .Open_Brace:
return parse_block_stmt(p, false);
- case token.Semicolon:
+ case .Semicolon:
tok := advance_token(p);
s := ast.new(ast.Empty_Stmt, tok.pos, end_pos(tok));
return s;
}
tok := advance_token(p);
- error(p, tok.pos, "expected a statement, got %s", token.to_string(tok.kind));
+ error(p, tok.pos, "expected a statement, got %s", tokenizer.to_string(tok.kind));
s := ast.new(ast.Bad_Stmt, tok.pos, end_pos(tok));
return s;
}
-token_precedence :: proc(p: ^Parser, kind: token.Kind) -> int {
+token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
switch kind {
- case token.Question:
+ case .Question:
return 1;
- case token.Ellipsis, token.Range_Half:
+ case .Ellipsis, .Range_Half:
if !p.allow_range {
return 0;
}
return 2;
- case token.Cmp_Or:
+ case .Cmp_Or:
return 3;
- case token.Cmp_And:
+ case .Cmp_And:
return 4;
- case token.Cmp_Eq, token.Not_Eq,
- token.Lt, token.Gt,
- token.Lt_Eq, token.Gt_Eq:
+ case .Cmp_Eq, .Not_Eq,
+ .Lt, .Gt,
+ .Lt_Eq, .Gt_Eq:
return 5;
- case token.In, token.Notin:
- if p.expr_level >= 0 || p.allow_in_expr {
- return 6;
+ case .In, .Notin:
+ if p.expr_level < 0 && !p.allow_in_expr {
+ return 0;
}
- return 0;
- case token.Add, token.Sub, token.Or, token.Xor:
+ fallthrough;
+ case .Add, .Sub, .Or, .Xor:
+ return 6;
+ case .Mul, .Quo,
+ .Mod, .Mod_Mod,
+ .And, .And_Not,
+ .Shl, .Shr:
return 7;
- case token.Mul, token.Quo,
- token.Mod, token.Mod_Mod,
- token.And, token.And_Not,
- token.Shl, token.Shr:
- return 8;
}
return 0;
}
@@ -1186,9 +1187,9 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt {
defer p.expr_level = prev_expr_level;
p.expr_level = 0;
- open := expect_token(p, token.Open_Brace);
+ open := expect_token(p, .Open_Brace);
stmts := parse_stmt_list(p);
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
bs := ast.new(ast.Block_Stmt, open.pos, end_pos(close));
bs.open = open.pos;
@@ -1215,7 +1216,7 @@ convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
}
new_ast_field :: proc(names: []^ast.Expr, type: ^ast.Expr, default_value: ^ast.Expr) -> ^ast.Field {
- pos, end: token.Pos;
+ pos, end: tokenizer.Pos;
if len(names) > 0 {
pos = names[0].pos;
@@ -1305,22 +1306,22 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
using Field_Prefix;
switch p.curr_tok.kind {
- case token.EOF:
+ case .EOF:
return Invalid;
- case token.Using:
+ case .Using:
advance_token(p);
return Using;
- case token.In:
+ case .In:
advance_token(p);
return In;
- case token.Auto_Cast:
+ case .Auto_Cast:
advance_token(p);
return Auto_Cast;
- case token.Hash:
+ case .Hash:
advance_token(p);
defer advance_token(p);
switch p.curr_tok.kind {
- case token.Ident:
+ case .Ident:
switch p.curr_tok.text {
case "no_alias":
return No_Alias;
@@ -1387,19 +1388,18 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
for flag in ast.Field_Flag {
if flag notin allowed_flags && flag in flags {
- using ast.Field_Flag;
#complete switch flag {
- case Using:
+ case .Using:
error(p, p.curr_tok.pos, "'using' is not allowed within this field list");
- case No_Alias:
+ case .No_Alias:
error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list");
- case C_Vararg:
+ case .C_Vararg:
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
- case Auto_Cast:
+ case .Auto_Cast:
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
- case In:
+ case .In:
error(p, p.curr_tok.pos, "'in' is not allowed within this field list");
- case Ellipsis, Results, Default_Parameters, Typeid_Token:
+ case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
panic("Impossible prefixes");
}
flags &~= {flag};
@@ -1414,7 +1414,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
}
parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr {
- if ast.Field_Flag.Ellipsis in flags && p.curr_tok.kind == token.Ellipsis {
+ if ast.Field_Flag.Ellipsis in flags && p.curr_tok.kind == .Ellipsis {
tok := advance_token(p);
type := parse_type_or_ident(p);
if type == nil {
@@ -1426,11 +1426,11 @@ parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr {
return e;
}
type: ^ast.Expr;
- if ast.Field_Flag.Typeid_Token in flags && p.curr_tok.kind == token.Typeid {
- tok := expect_token(p, token.Typeid);
+ if ast.Field_Flag.Typeid_Token in flags && p.curr_tok.kind == .Typeid {
+ tok := expect_token(p, .Typeid);
specialization: ^ast.Expr;
end := tok.pos;
- if allow_token(p, token.Quo) {
+ if allow_token(p, .Quo) {
specialization = parse_type(p);
end = specialization.end;
}
@@ -1482,8 +1482,8 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr {
list: [dynamic]^ast.Expr;
for {
- if allow_poly_names && p.curr_tok.kind == token.Dollar {
- tok := expect_token(p, token.Dollar);
+ if allow_poly_names && p.curr_tok.kind == .Dollar {
+ tok := expect_token(p, .Dollar);
ident := parse_ident(p);
if is_blank_ident(ident) {
error(p, ident.pos, "invalid polymorphic type definition with a blank identifier");
@@ -1495,8 +1495,8 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr {
ident := parse_ident(p);
append(&list, ident);
}
- if p.curr_tok.kind != token.Comma ||
- p.curr_tok.kind == token.EOF {
+ if p.curr_tok.kind != .Comma ||
+ p.curr_tok.kind == .EOF {
break;
}
advance_token(p);
@@ -1507,7 +1507,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr {
-parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Field_Flags) -> (field_list: ^ast.Field_List, total_name_count: int) {
+parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags: ast.Field_Flags) -> (field_list: ^ast.Field_List, total_name_count: int) {
handle_field :: proc(p: ^Parser,
seen_ellipsis: ^bool, fields: ^[dynamic]^ast.Field,
docs: ^ast.Comment_Group,
@@ -1517,10 +1517,10 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
expect_field_separator :: proc(p: ^Parser, param: ^ast.Expr) -> bool {
tok := p.curr_tok;
- if allow_token(p, token.Comma) {
+ if allow_token(p, .Comma) {
return true;
}
- if allow_token(p, token.Semicolon) {
+ if allow_token(p, .Semicolon) {
error(p, tok.pos, "expected a comma, got a semicolon");
return true;
}
@@ -1539,9 +1539,10 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
type: ^ast.Expr;
default_value: ^ast.Expr;
+ tag: tokenizer.Token;
- expect_token_after(p, token.Colon, "field list");
- if p.curr_tok.kind != token.Eq {
+ expect_token_after(p, .Colon, "field list");
+ if p.curr_tok.kind != .Eq {
type = parse_var_type(p, allowed_flags);
tt := ast.unparen_expr(type);
if is_signature && !any_polymorphic_names {
@@ -1551,7 +1552,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
}
}
- if allow_token(p, token.Eq) {
+ if allow_token(p, .Eq) {
default_value = parse_expr(p, false);
if ast.Field_Flag.Default_Parameters notin allowed_flags {
error(p, p.curr_tok.pos, "default parameters are only allowed for procedures");
@@ -1578,9 +1579,19 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
error(p, p.curr_tok.pos, "extra parameter after ellipsis without a default value");
}
+ if type != nil && default_value == nil {
+ if p.curr_tok.kind == .String {
+ tag = expect_token(p, .String);
+ if .Tags notin allowed_flags {
+ error(p, tag.pos, "Field tags are only allowed within structures");
+ }
+ }
+ }
+
ok := expect_field_separator(p, type);
field := new_ast_field(names, type, default_value);
+ field.tag = tag;
field.docs = docs;
field.flags = flags;
field.comment = p.line_comment;
@@ -1605,8 +1616,8 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
allow_poly_names := allow_typeid_token;
for p.curr_tok.kind != follow &&
- p.curr_tok.kind != token.Colon &&
- p.curr_tok.kind != token.EOF {
+ p.curr_tok.kind != .Colon &&
+ p.curr_tok.kind != .EOF {
prefix_flags := parse_field_prefixes(p);
param := parse_var_type(p, allowed_flags & {ast.Field_Flag.Typeid_Token, ast.Field_Flag.Ellipsis});
if _, ok := param.derived.(ast.Ellipsis); ok {
@@ -1620,15 +1631,15 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
eaf := Expr_And_Flags{param, prefix_flags};
append(&list, eaf);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
- if p.curr_tok.kind != token.Colon {
+ if p.curr_tok.kind != .Colon {
for eaf in list {
type := eaf.expr;
- tok: token.Token;
+ tok: tokenizer.Token;
tok.pos = type.pos;
if ast.Field_Flag.Results notin allowed_flags {
tok.text = "_";
@@ -1659,7 +1670,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
total_name_count += len(names);
handle_field(p, &seen_ellipsis, &fields, docs, names, allowed_flags, set_flags);
- for p.curr_tok.kind != follow && p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != follow && p.curr_tok.kind != .EOF {
docs = p.lead_comment;
set_flags = parse_field_prefixes(p);
names = parse_ident_list(p, allow_poly_names);
@@ -1679,11 +1690,11 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) {
- if !allow_token(p, token.Arrow_Right) {
+ if !allow_token(p, .Arrow_Right) {
return;
}
- if allow_token(p, token.Not) {
+ if allow_token(p, .Not) {
diverging = true;
return;
}
@@ -1691,7 +1702,7 @@ parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) {
prev_level := p.expr_level;
defer p.expr_level = prev_level;
- if p.curr_tok.kind != token.Open_Paren {
+ if p.curr_tok.kind != .Open_Paren {
type := parse_type(p);
field := new_ast_field(nil, type, nil);
@@ -1701,9 +1712,9 @@ parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) {
return;
}
- expect_token(p, token.Open_Paren);
- list, _ = parse_field_list(p, token.Close_Paren, ast.Field_Flags_Signature_Results);
- expect_token_after(p, token.Close_Paren, "parameter list");
+ expect_token(p, .Open_Paren);
+ list, _ = parse_field_list(p, .Close_Paren, ast.Field_Flags_Signature_Results);
+ expect_token_after(p, .Close_Paren, "parameter list");
return;
}
@@ -1729,13 +1740,11 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention {
}
parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
- for p.curr_tok.kind == token.Hash {
- tok := expect_token(p, token.Hash);
- ident := expect_token(p, token.Ident);
+ for p.curr_tok.kind == .Hash {
+ _ = expect_token(p, .Hash);
+ ident := expect_token(p, .Ident);
switch ident.text {
- case "require_results":
- tags |= {.Require_Results};
case "bounds_check":
tags |= {.Bounds_Check};
case "no_bounds_check":
@@ -1751,10 +1760,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
return;
}
-parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type {
+parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type {
cc := ast.Proc_Calling_Convention.Invalid;
- if p.curr_tok.kind == token.String {
- str := expect_token(p, token.String);
+ if p.curr_tok.kind == .String {
+ str := expect_token(p, .String);
cc = string_to_calling_convention(str.text);
if cc == ast.Proc_Calling_Convention.Invalid {
error(p, str.pos, "unknown calling convention '%s'", str.text);
@@ -1769,9 +1778,9 @@ parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type {
}
}
- expect_token(p, token.Open_Paren);
- params, _ := parse_field_list(p, token.Close_Paren, ast.Field_Flags_Signature_Params);
- expect_token(p, token.Close_Paren);
+ expect_token(p, .Open_Paren);
+ params, _ := parse_field_list(p, .Close_Paren, ast.Field_Flags_Signature_Params);
+ expect_token(p, .Close_Paren);
results, diverging := parse_results(p);
is_generic := false;
@@ -1802,7 +1811,7 @@ parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type {
return pt;
}
-check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok: token.Token) {
+check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok: tokenizer.Token) {
if poly_params == nil {
return;
}
@@ -1821,46 +1830,46 @@ check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok
parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
switch p.curr_tok.kind {
- case token.Ident:
+ case .Ident:
return parse_ident(p);
- case token.Undef:
- tok := expect_token(p, token.Undef);
+ case .Undef:
+ tok := expect_token(p, .Undef);
undef := ast.new(ast.Undef, tok.pos, end_pos(tok));
undef.tok = tok.kind;
return undef;
- case token.Context:
- tok := expect_token(p, token.Context);
+ case .Context:
+ tok := expect_token(p, .Context);
ctx := ast.new(ast.Implicit, tok.pos, end_pos(tok));
ctx.tok = tok;
return ctx;
- case token.Integer, token.Float, token.Imag,
- token.Rune, token.String:
+ case .Integer, .Float, .Imag,
+ .Rune, .String:
tok := advance_token(p);
bl := ast.new(ast.Basic_Lit, tok.pos, end_pos(tok));
bl.tok = tok;
return bl;
- case token.Size_Of, token.Align_Of, token.Offset_Of:
+ case .Size_Of, .Align_Of, .Offset_Of:
tok := advance_token(p);
expr := ast.new(ast.Implicit, tok.pos, end_pos(tok));
expr.tok = tok;
return parse_call_expr(p, expr);
- case token.Open_Brace:
+ case .Open_Brace:
if !lhs {
return parse_literal_value(p, nil);
}
- case token.Open_Paren:
- open := expect_token(p, token.Open_Paren);
+ case .Open_Paren:
+ open := expect_token(p, .Open_Paren);
p.expr_level += 1;
expr := parse_expr(p, false);
p.expr_level -= 1;
- close := expect_token(p, token.Close_Paren);
+ close := expect_token(p, .Close_Paren);
pe := ast.new(ast.Paren_Expr, open.pos, end_pos(close));
pe.open = open.pos;
@@ -1868,7 +1877,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
pe.close = close.pos;
return pe;
- case token.Distinct:
+ case .Distinct:
tok := advance_token(p);
type := parse_type(p);
dt := ast.new(ast.Distinct_Type, tok.pos, type.end);
@@ -1876,16 +1885,16 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
dt.type = type;
return dt;
- case token.Opaque:
+ case .Opaque:
tok := advance_token(p);
type := parse_type(p);
ot := ast.new(ast.Opaque_Type, tok.pos, type.end);
ot.tok = tok.kind;
ot.type = type;
return ot;
- case token.Hash:
- tok := expect_token(p, token.Hash);
- name := expect_token(p, token.Ident);
+ case .Hash:
+ tok := expect_token(p, .Hash);
+ name := expect_token(p, .Ident);
switch name.text {
case "type":
type := parse_type(p);
@@ -1913,15 +1922,15 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return te;
}
- case token.Inline, token.No_Inline:
+ case .Inline, .No_Inline:
tok := advance_token(p);
expr := parse_unary_expr(p, lhs);
pi := ast.Proc_Inlining.None;
switch tok.kind {
- case token.Inline:
+ case .Inline:
pi = ast.Proc_Inlining.Inline;
- case token.No_Inline:
+ case .No_Inline:
pi = ast.Proc_Inlining.No_Inline;
}
@@ -1942,25 +1951,25 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
return expr;
- case token.Proc:
- tok := expect_token(p, token.Proc);
+ case .Proc:
+ tok := expect_token(p, .Proc);
- if p.curr_tok.kind == token.Open_Brace {
- open := expect_token(p, token.Open_Brace);
+ if p.curr_tok.kind == .Open_Brace {
+ open := expect_token(p, .Open_Brace);
args: [dynamic]^ast.Expr;
- for p.curr_tok.kind != token.Close_Brace &&
- p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != .Close_Brace &&
+ p.curr_tok.kind != .EOF {
elem := parse_expr(p, false);
append(&args, elem);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
if len(args) == 0 {
error(p, tok.pos, "expected at least 1 argument in procedure group");
@@ -1976,19 +1985,35 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
type := parse_proc_type(p, tok);
+ where_token: tokenizer.Token;
+ where_clauses: []^ast.Expr;
+ if (p.curr_tok.kind == .Where) {
+ where_token = expect_token(p, .Where);
+ prev_level := p.expr_level;
+ p.expr_level = -1;
+ where_clauses = parse_rhs_expr_list(p);
+ p.expr_level = prev_level;
+ }
+
if p.allow_type && p.expr_level < 0 {
+ if where_token.kind != .Invalid {
+ error(p, where_token.pos, "'where' clauses are not allowed on procedure types");
+ }
return type;
}
body: ^ast.Stmt;
- if allow_token(p, token.Undef) {
+ if allow_token(p, .Undef) {
// Okay
- } else if p.curr_tok.kind == token.Open_Brace {
+ if where_token.kind != .Invalid {
+ error(p, where_token.pos, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---");
+ }
+ } else if p.curr_tok.kind == .Open_Brace {
prev_proc := p.curr_proc;
p.curr_proc = type;
body = parse_body(p);
p.curr_proc = prev_proc;
- } else if allow_token(p, token.Do) {
+ } else if allow_token(p, .Do) {
prev_proc := p.curr_proc;
p.curr_proc = type;
body = convert_stmt_to_body(p, parse_stmt(p));
@@ -2000,15 +2025,17 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
pl := ast.new(ast.Proc_Lit, tok.pos, end_pos(p.prev_tok));
pl.type = type;
pl.body = body;
+ pl.where_token = where_token;
+ pl.where_clauses = where_clauses;
return pl;
- case token.Dollar:
+ case .Dollar:
tok := advance_token(p);
type := parse_ident(p);
end := type.end;
specialization: ^ast.Expr;
- if allow_token(p, token.Quo) {
+ if allow_token(p, .Quo) {
specialization = parse_type(p);
end = specialization.pos;
}
@@ -2022,19 +2049,19 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
pt.specialization = specialization;
return pt;
- case token.Typeid:
+ case .Typeid:
tok := advance_token(p);
ti := ast.new(ast.Typeid_Type, tok.pos, end_pos(tok));
ti.tok = tok.kind;
ti.specialization = nil;
return ti;
- case token.Type_Of:
+ case .Type_Of:
tok := advance_token(p);
i := ast.new(ast.Implicit, tok.pos, end_pos(tok));
i.tok = tok;
type: ^ast.Expr = parse_call_expr(p, i);
- for p.curr_tok.kind == token.Period {
+ for p.curr_tok.kind == .Period {
period := advance_token(p);
field := parse_ident(p);
@@ -2048,24 +2075,24 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return type;
- case token.Pointer:
- tok := expect_token(p, token.Pointer);
+ case .Pointer:
+ tok := expect_token(p, .Pointer);
elem := parse_type(p);
ptr := ast.new(ast.Pointer_Type, tok.pos, elem.end);
ptr.elem = elem;
return ptr;
- case token.Open_Bracket:
- open := expect_token(p, token.Open_Bracket);
+ case .Open_Bracket:
+ open := expect_token(p, .Open_Bracket);
count: ^ast.Expr;
- if p.curr_tok.kind == token.Question {
- tok := expect_token(p, token.Question);
+ if p.curr_tok.kind == .Question {
+ tok := expect_token(p, .Question);
q := ast.new(ast.Unary_Expr, tok.pos, end_pos(tok));
q.op = tok;
count = q;
- } else if p.curr_tok.kind == token.Dynamic {
- tok := expect_token(p, token.Dynamic);
- close := expect_token(p, token.Close_Bracket);
+ } else if p.curr_tok.kind == .Dynamic {
+ tok := expect_token(p, .Dynamic);
+ close := expect_token(p, .Close_Bracket);
elem := parse_type(p);
da := ast.new(ast.Dynamic_Array_Type, open.pos, elem.end);
da.open = open.pos;
@@ -2074,12 +2101,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
da.elem = elem;
return da;
- } else if p.curr_tok.kind != token.Close_Bracket {
+ } else if p.curr_tok.kind != .Close_Bracket {
p.expr_level += 1;
count = parse_expr(p, false);
p.expr_level -= 1;
}
- close := expect_token(p, token.Close_Bracket);
+ close := expect_token(p, .Close_Bracket);
elem := parse_type(p);
at := ast.new(ast.Array_Type, open.pos, elem.end);
at.open = open.pos;
@@ -2088,11 +2115,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
at.elem = elem;
return at;
- case token.Map:
- tok := expect_token(p, token.Map);
- expect_token(p, token.Open_Bracket);
+ case .Map:
+ tok := expect_token(p, .Map);
+ expect_token(p, .Open_Bracket);
key := parse_type(p);
- expect_token(p, token.Close_Bracket);
+ expect_token(p, .Close_Bracket);
value := parse_type(p);
mt := ast.new(ast.Map_Type, tok.pos, value.end);
@@ -2101,8 +2128,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
mt.value = value;
return mt;
- case token.Struct:
- tok := expect_token(p, token.Struct);
+ case .Struct:
+ tok := expect_token(p, .Struct);
poly_params: ^ast.Field_List;
align: ^ast.Expr;
@@ -2111,21 +2138,21 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
fields: ^ast.Field_List;
name_count: int;
- if allow_token(p, token.Open_Paren) {
+ if allow_token(p, .Open_Paren) {
param_count: int;
- poly_params, param_count = parse_field_list(p, token.Close_Paren, ast.Field_Flags_Record_Poly_Params);
+ poly_params, param_count = parse_field_list(p, .Close_Paren, ast.Field_Flags_Record_Poly_Params);
if param_count == 0 {
error(p, poly_params.pos, "expected at least 1 polymorphic parameter");
poly_params = nil;
}
- expect_token_after(p, token.Close_Paren, "parameter list");
+ expect_token_after(p, .Close_Paren, "parameter list");
check_poly_params_for_type(p, poly_params, tok);
}
prev_level := p.expr_level;
p.expr_level = -1;
- for allow_token(p, token.Hash) {
- tag := expect_token_after(p, token.Ident, "#");
+ for allow_token(p, .Hash) {
+ tag := expect_token_after(p, .Ident, "#");
switch tag.text {
case "packed":
if is_packed do error(p, tag.pos, "duplicate struct tag '#%s'", tag.text);
@@ -2147,39 +2174,51 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
error(p, tok.pos, "'#raw_union' cannot also be '#packed");
}
- expect_token(p, token.Open_Brace);
- fields, name_count = parse_field_list(p, token.Close_Brace, ast.Field_Flags_Struct);
- close := expect_token(p, token.Close_Brace);
+ where_token: tokenizer.Token;
+ where_clauses: []^ast.Expr;
+ if (p.curr_tok.kind == .Where) {
+ where_token = expect_token(p, .Where);
+ prev_level := p.expr_level;
+ p.expr_level = -1;
+ where_clauses = parse_rhs_expr_list(p);
+ p.expr_level = prev_level;
+ }
+
+ expect_token(p, .Open_Brace);
+ fields, name_count = parse_field_list(p, .Close_Brace, ast.Field_Flags_Struct);
+ close := expect_token(p, .Close_Brace);
st := ast.new(ast.Struct_Type, tok.pos, end_pos(close));
- st.poly_params = poly_params;
- st.align = align;
- st.is_packed = is_packed;
- st.is_raw_union = is_raw_union;
- st.fields = fields;
- st.name_count = name_count;
+ st.poly_params = poly_params;
+ st.align = align;
+ st.is_packed = is_packed;
+ st.is_raw_union = is_raw_union;
+ st.fields = fields;
+ st.name_count = name_count;
+ st.where_token = where_token;
+ st.where_clauses = where_clauses;
return st;
- case token.Union:
- tok := expect_token(p, token.Union);
+ case .Union:
+ tok := expect_token(p, .Union);
poly_params: ^ast.Field_List;
align: ^ast.Expr;
- if allow_token(p, token.Open_Paren) {
+ if allow_token(p, .Open_Paren) {
param_count: int;
- poly_params, param_count = parse_field_list(p, token.Close_Paren, ast.Field_Flags_Record_Poly_Params);
+ poly_params, param_count = parse_field_list(p, .Close_Paren, ast.Field_Flags_Record_Poly_Params);
if param_count == 0 {
error(p, poly_params.pos, "expected at least 1 polymorphic parameter");
poly_params = nil;
}
- expect_token_after(p, token.Close_Paren, "parameter list");
+ expect_token_after(p, .Close_Paren, "parameter list");
check_poly_params_for_type(p, poly_params, tok);
}
prev_level := p.expr_level;
p.expr_level = -1;
- for allow_token(p, token.Hash) {
- tag := expect_token_after(p, token.Ident, "#");
+ for allow_token(p, .Hash) {
+ tag := expect_token_after(p, .Ident, "#");
switch tag.text {
case "align":
if align != nil do error(p, tag.pos, "duplicate union tag '#%s'", tag.text);
@@ -2190,38 +2229,50 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
p.expr_level = prev_level;
+ where_token: tokenizer.Token;
+ where_clauses: []^ast.Expr;
+ if (p.curr_tok.kind == .Where) {
+ where_token = expect_token(p, .Where);
+ prev_level := p.expr_level;
+ p.expr_level = -1;
+ where_clauses = parse_rhs_expr_list(p);
+ p.expr_level = prev_level;
+ }
+
variants: [dynamic]^ast.Expr;
- expect_token_after(p, token.Open_Brace, "union");
+ expect_token_after(p, .Open_Brace, "union");
- for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
type := parse_type(p);
if _, ok := type.derived.(ast.Bad_Expr); !ok {
append(&variants, type);
}
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
ut := ast.new(ast.Union_Type, tok.pos, end_pos(close));
- ut.poly_params = poly_params;
- ut.variants = variants[:];
- ut.align = align;
+ ut.poly_params = poly_params;
+ ut.variants = variants[:];
+ ut.align = align;
+ ut.where_token = where_token;
+ ut.where_clauses = where_clauses;
return ut;
- case token.Enum:
- tok := expect_token(p, token.Enum);
+ case .Enum:
+ tok := expect_token(p, .Enum);
base_type: ^ast.Expr;
- if p.curr_tok.kind != token.Open_Brace {
+ if p.curr_tok.kind != .Open_Brace {
base_type = parse_type(p);
}
- open := expect_token(p, token.Open_Brace);
+ open := expect_token(p, .Open_Brace);
fields := parse_elem_list(p);
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
et := ast.new(ast.Enum_Type, tok.pos, end_pos(close));
et.base_type = base_type;
@@ -2230,8 +2281,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
et.close = close.pos;
return et;
- case token.Bit_Field:
- tok := expect_token(p, token.Bit_Field);
+ case .Bit_Field:
+ tok := expect_token(p, .Bit_Field);
fields: [dynamic]^ast.Field_Value;
align: ^ast.Expr;
@@ -2239,8 +2290,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
prev_level := p.expr_level;
p.expr_level = -1;
- for allow_token(p, token.Hash) {
- tag := expect_token_after(p, token.Ident, "#");
+ for allow_token(p, .Hash) {
+ tag := expect_token_after(p, .Ident, "#");
switch tag.text {
case "align":
if align != nil {
@@ -2254,11 +2305,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
p.expr_level = prev_level;
- open := expect_token_after(p, token.Open_Brace, "bit_field");
+ open := expect_token_after(p, .Open_Brace, "bit_field");
- for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
name := parse_ident(p);
- colon := expect_token(p, token.Colon);
+ colon := expect_token(p, .Colon);
value := parse_expr(p, true);
fv := ast.new(ast.Field_Value, name.pos, value.end);
@@ -2267,12 +2318,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
fv.value = value;
append(&fields, fv);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
- close := expect_token(p, token.Close_Brace);
+ close := expect_token(p, .Close_Brace);
bft := ast.new(ast.Bit_Field_Type, tok.pos, end_pos(close));
bft.tok_pos = tok.pos;
@@ -2283,9 +2334,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return bft;
- case token.Bit_Set:
- tok := expect_token(p, token.Bit_Set);
- open := expect_token(p, token.Open_Bracket);
+ case .Bit_Set:
+ tok := expect_token(p, .Bit_Set);
+ open := expect_token(p, .Open_Bracket);
elem, underlying: ^ast.Expr;
prev_allow_range := p.allow_range;
@@ -2293,12 +2344,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
elem = parse_expr(p, false);
p.allow_range = prev_allow_range;
- if allow_token(p, token.Semicolon) {
+ if allow_token(p, .Semicolon) {
underlying = parse_type(p);
}
- close := expect_token(p, token.Close_Bracket);
+ close := expect_token(p, .Close_Bracket);
bst := ast.new(ast.Bit_Set_Type, tok.pos, end_pos(close));
bst.tok_pos = tok.pos;
@@ -2337,19 +2388,22 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool {
}
parse_value :: proc(p: ^Parser) -> ^ast.Expr {
- if p.curr_tok.kind == token.Open_Brace {
+ if p.curr_tok.kind == .Open_Brace {
return parse_literal_value(p, nil);
}
+ prev_allow_range = p.allow_range;
+ defer p.allow_range = prev_allow_range;
+ p.allow_range = true;
return parse_expr(p, false);
}
parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
elems: [dynamic]^ast.Expr;
- for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF {
+ for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
elem := parse_value(p);
- if p.curr_tok.kind == token.Eq {
- eq := expect_token(p, token.Eq);
+ if p.curr_tok.kind == .Eq {
+ eq := expect_token(p, .Eq);
value := parse_value(p);
fv := ast.new(ast.Field_Value, elem.pos, value.end);
@@ -2362,7 +2416,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
append(&elems, elem);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
@@ -2372,14 +2426,14 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit {
elems: []^ast.Expr;
- open := expect_token(p, token.Open_Brace);
+ open := expect_token(p, .Open_Brace);
p.expr_level += 1;
- if p.curr_tok.kind != token.Close_Brace {
+ if p.curr_tok.kind != .Close_Brace {
elems = parse_elem_list(p);
}
p.expr_level -= 1;
- close := expect_token_after(p, token.Close_Brace, "compound literal");
+ close := expect_token_after(p, .Close_Brace, "compound literal");
pos := type != nil ? type.pos : open.pos;
lit := ast.new(ast.Comp_Lit, pos, end_pos(close));
@@ -2393,30 +2447,30 @@ parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit {
parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Call_Expr {
args: [dynamic]^ast.Expr;
- ellipsis: token.Token;
+ ellipsis: tokenizer.Token;
p.expr_level += 1;
- open := expect_token(p, token.Open_Paren);
+ open := expect_token(p, .Open_Paren);
- for p.curr_tok.kind != token.Close_Paren &&
- p.curr_tok.kind != token.EOF &&
+ for p.curr_tok.kind != .Close_Paren &&
+ p.curr_tok.kind != .EOF &&
ellipsis.pos.line == 0 {
- if p.curr_tok.kind == token.Comma {
+ if p.curr_tok.kind == .Comma {
error(p, p.curr_tok.pos, "expected an expression not ,");
- } else if p.curr_tok.kind == token.Eq {
+ } else if p.curr_tok.kind == .Eq {
error(p, p.curr_tok.pos, "expected an expression not =");
}
prefix_ellipsis := false;
- if p.curr_tok.kind == token.Ellipsis {
+ if p.curr_tok.kind == .Ellipsis {
prefix_ellipsis = true;
- ellipsis = expect_token(p, token.Ellipsis);
+ ellipsis = expect_token(p, .Ellipsis);
}
arg := parse_expr(p, false);
- if p.curr_tok.kind == token.Eq {
- eq := expect_token(p, token.Eq);
+ if p.curr_tok.kind == .Eq {
+ eq := expect_token(p, .Eq);
if prefix_ellipsis {
error(p, ellipsis.pos, "'..' must be applied to value rather than a field name");
@@ -2433,12 +2487,12 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Call_Expr {
append(&args, arg);
- if !allow_token(p, token.Comma) {
+ if !allow_token(p, .Comma) {
break;
}
}
- close := expect_token_after(p, token.Close_Paren, "argument list");
+ close := expect_token_after(p, .Close_Paren, "argument list");
p.expr_level -= 1;
ce := ast.new(ast.Call_Expr, operand.pos, end_pos(close));
@@ -2469,23 +2523,23 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case:
loop = false;
- case token.Open_Paren:
+ case .Open_Paren:
operand = parse_call_expr(p, operand);
- case token.Open_Bracket:
+ case .Open_Bracket:
prev_allow_range := p.allow_range;
defer p.allow_range = prev_allow_range;
p.allow_range = false;
indicies: [2]^ast.Expr;
- interval: token.Token;
+ interval: tokenizer.Token;
is_slice_op := false;
p.expr_level += 1;
- open := expect_token(p, token.Open_Bracket);
+ open := expect_token(p, .Open_Bracket);
switch p.curr_tok.kind {
- case token.Colon, token.Ellipsis, token.Range_Half:
+ case .Colon, .Ellipsis, .Range_Half:
// NOTE(bill): Do not err yet
break;
case:
@@ -2493,18 +2547,18 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
}
switch p.curr_tok.kind {
- case token.Ellipsis, token.Range_Half:
+ case .Ellipsis, .Range_Half:
error(p, p.curr_tok.pos, "expected a colon, not a range");
fallthrough;
- case token.Colon:
+ case .Colon:
interval = advance_token(p);
is_slice_op = true;
- if (p.curr_tok.kind != token.Close_Bracket && p.curr_tok.kind != token.EOF) {
+ if (p.curr_tok.kind != .Close_Bracket && p.curr_tok.kind != .EOF) {
indicies[1] = parse_expr(p, false);
}
}
- close := expect_token(p, token.Close_Bracket);
+ close := expect_token(p, .Close_Bracket);
p.expr_level -= 1;
if is_slice_op {
@@ -2528,10 +2582,10 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
}
- case token.Period:
- tok := expect_token(p, token.Period);
+ case .Period:
+ tok := expect_token(p, .Period);
switch p.curr_tok.kind {
- case token.Ident:
+ case .Ident:
field := parse_ident(p);
sel := ast.new(ast.Selector_Expr, operand.pos, field.end);
@@ -2540,10 +2594,10 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
operand = sel;
- case token.Open_Paren:
- open := expect_token(p, token.Open_Paren);
+ case .Open_Paren:
+ open := expect_token(p, .Open_Paren);
type := parse_type(p);
- close := expect_token(p, token.Close_Paren);
+ close := expect_token(p, .Close_Paren);
ta := ast.new(ast.Type_Assertion, operand.pos, end_pos(close));
ta.expr = operand;
@@ -2559,15 +2613,15 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
operand = ast.new(ast.Bad_Expr, operand.pos, end_pos(tok));
}
- case token.Pointer:
- op := expect_token(p, token.Pointer);
+ case .Pointer:
+ op := expect_token(p, .Pointer);
deref := ast.new(ast.Deref_Expr, operand.pos, end_pos(op));
deref.expr = operand;
deref.op = op;
operand = deref;
- case token.Open_Brace:
+ case .Open_Brace:
if !is_lhs && is_literal_type(operand) && p.expr_level >= 0 {
operand = parse_literal_value(p, operand);
} else {
@@ -2588,11 +2642,11 @@ parse_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
switch p.curr_tok.kind {
- case token.Transmute, token.Cast:
+ case .Transmute, .Cast:
tok := advance_token(p);
- open := expect_token(p, token.Open_Paren);
+ open := expect_token(p, .Open_Paren);
type := parse_type(p);
- close := expect_token(p, token.Close_Paren);
+ close := expect_token(p, .Close_Paren);
expr := parse_unary_expr(p, lhs);
tc := ast.new(ast.Type_Cast, tok.pos, expr.end);
@@ -2603,7 +2657,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tc.expr = expr;
return tc;
- case token.Auto_Cast:
+ case .Auto_Cast:
op := advance_token(p);
expr := parse_unary_expr(p, lhs);
@@ -2612,9 +2666,9 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
ac.expr = expr;
return ac;
- case token.Add, token.Sub,
- token.Not, token.Xor,
- token.And:
+ case .Add, .Sub,
+ .Not, .Xor,
+ .And:
op := advance_token(p);
expr := parse_unary_expr(p, lhs);
@@ -2623,7 +2677,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
ue.expr = expr;
return ue;
- case token.Period:
+ case .Period:
op := advance_token(p);
field := parse_ident(p);
ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end);
@@ -2644,10 +2698,10 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr {
}
expect_operator(p);
- if op.kind == token.Question {
+ if op.kind == .Question {
cond := expr;
x := parse_expr(p, lhs);
- colon := expect_token(p, token.Colon);
+ colon := expect_token(p, .Colon);
y := parse_expr(p, lhs);
te := ast.new(ast.Ternary_Expr, expr.pos, end_pos(p.prev_tok));
te.cond = cond;
@@ -2681,7 +2735,7 @@ parse_expr_list :: proc(p: ^Parser, lhs: bool) -> ([]^ast.Expr) {
for {
expr := parse_expr(p, lhs);
append(&list, expr);
- if p.curr_tok.kind != token.Comma || p.curr_tok.kind == token.EOF {
+ if p.curr_tok.kind != .Comma || p.curr_tok.kind == .EOF {
break;
}
advance_token(p);
@@ -2703,7 +2757,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
lhs := parse_lhs_expr_list(p);
op := p.curr_tok;
switch {
- case token.is_assignment_operator(op.kind):
+ case tokenizer.is_assignment_operator(op.kind):
// if p.curr_proc == nil {
// error(p, p.curr_tok.pos, "simple statements are not allowed at the file scope");
// return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok));
@@ -2720,9 +2774,9 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
stmt.rhs = rhs;
return stmt;
- case op.kind == token.In:
+ case op.kind == .In:
if .In in flags {
- allow_token(p, token.In);
+ allow_token(p, .In);
prev_allow_range := p.allow_range;
p.allow_range = true;
expr := parse_expr(p, false);
@@ -2737,11 +2791,11 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
stmt.rhs = rhs;
return stmt;
}
- case op.kind == token.Colon:
- expect_token_after(p, token.Colon, "identifier list");
+ case op.kind == .Colon:
+ expect_token_after(p, .Colon, "identifier list");
if .Label in flags && len(lhs) == 1 {
switch p.curr_tok.kind {
- case token.Open_Brace, token.If, token.For, token.Switch:
+ case .Open_Brace, .If, .For, .Switch:
label := lhs[0];
stmt := parse_stmt(p);
@@ -2776,9 +2830,9 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou
type := parse_type_or_ident(p);
switch p.curr_tok.kind {
- case token.Eq, token.Colon:
+ case .Eq, .Colon:
sep := advance_token(p);
- is_mutable = sep.kind != token.Colon;
+ is_mutable = sep.kind != .Colon;
values = parse_rhs_expr_list(p);
if len(values) > len(names) {
@@ -2807,7 +2861,7 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou
if !is_mutable && len(values) > 0 {
end = values[len(values)-1];
}
- if p.curr_tok.kind == token.Close_Brace &&
+ if p.curr_tok.kind == .Close_Brace &&
p.curr_tok.pos.line == p.prev_tok.pos.line {
} else {
@@ -2833,13 +2887,13 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou
parse_import_decl :: proc(p: ^Parser, kind := Import_Decl_Kind.Standard) -> ^ast.Import_Decl {
docs := p.lead_comment;
- tok := expect_token(p, token.Import);
+ tok := expect_token(p, .Import);
- import_name: token.Token;
+ import_name: tokenizer.Token;
is_using := kind != Import_Decl_Kind.Standard;
switch p.curr_tok.kind {
- case token.Ident:
+ case .Ident:
import_name = advance_token(p);
case:
import_name.pos = p.curr_tok.pos;
@@ -2849,7 +2903,7 @@ parse_import_decl :: proc(p: ^Parser, kind := Import_Decl_Kind.Standard) -> ^ast
error(p, import_name.pos, "illegal import name: '_'");
}
- path := expect_token_after(p, token.String, "import");
+ path := expect_token_after(p, .String, "import");
decl := ast.new(ast.Import_Decl, tok.pos, end_pos(path));
decl.docs = docs;
diff --git a/core/odin/token/token.odin b/core/odin/tokenizer/token.odin
index 8ce98d1d9..d692da5d9 100644
--- a/core/odin/token/token.odin
+++ b/core/odin/tokenizer/token.odin
@@ -1,9 +1,9 @@
-package odin_token
+package odin_tokenizer
import "core:strings"
Token :: struct {
- kind: Kind,
+ kind: Token_Kind,
text: string,
pos: Pos,
}
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
return strings.compare(lhs.file, rhs.file);
}
-using Kind :: enum u32 {
+Token_Kind :: enum u32 {
Invalid,
EOF,
Comment,
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
Package,
Typeid,
When,
+ Where,
If,
Else,
For,
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
Offset_Of,
Type_Of,
Const,
- Asm,
- Yield,
- Await,
B_Keyword_End,
COUNT,
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
// ... Custom keywords
};
-tokens := [Kind.COUNT]string {
+tokens := [Token_Kind.COUNT]string {
"Invalid",
"EOF",
"Comment",
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
"package",
"typeid",
"when",
+ "where",
"if",
"else",
"for",
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
"offset_of",
"type_of",
"const",
- "asm",
- "yield",
- "await",
"",
};
custom_keyword_tokens: []string;
-to_string :: proc(kind: Kind) -> string {
- if Invalid <= kind && kind < COUNT {
+to_string :: proc(kind: Token_Kind) -> string {
+ if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
return tokens[kind];
}
- if B_Custom_Keyword_Begin < kind {
- n := int(u16(kind)-u16(B_Custom_Keyword_Begin));
+ if Token_Kind.B_Custom_Keyword_Begin < kind {
+ n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
if n < len(custom_keyword_tokens) {
return custom_keyword_tokens[n];
}
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
return "Invalid";
}
-is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; }
-is_operator :: proc(kind: Kind) -> bool {
+is_literal :: proc(kind: Token_Kind) -> bool {
+ return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
+}
+is_operator :: proc(kind: Token_Kind) -> bool {
switch kind {
- case B_Operator_Begin..B_Operator_End:
+ case .B_Operator_Begin .. .B_Operator_End:
return true;
- case In, Notin:
+ case .In, .Notin:
return true;
}
return false;
}
-is_assignment_operator :: proc(kind: Kind) -> bool {
- return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
+is_assignment_operator :: proc(kind: Token_Kind) -> bool {
+ return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
}
-is_keyword :: proc(kind: Kind) -> bool {
+is_keyword :: proc(kind: Token_Kind) -> bool {
switch {
- case B_Keyword_Begin < kind && kind < B_Keyword_End:
+ case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
return true;
- case B_Custom_Keyword_Begin < kind:
+ case Token_Kind.B_Custom_Keyword_Begin < kind:
return true;
}
return false;
diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin
index 764fe6e34..26aab7c1c 100644
--- a/core/odin/tokenizer/tokenizer.odin
+++ b/core/odin/tokenizer/tokenizer.odin
@@ -1,10 +1,9 @@
package odin_tokenizer
import "core:fmt"
-import "core:odin/token"
import "core:unicode/utf8"
-Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
+Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
Tokenizer :: struct {
// Immutable data
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
}
@(private)
-offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
+offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
line := t.line_count;
column := offset - t.line_offset + 1;
- return token.Pos {
+ return Pos {
file = t.path,
offset = offset,
line = line,
@@ -53,10 +52,10 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
};
}
-default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
- fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column);
- fmt.printf_err(msg, ..args);
- fmt.printf_err("\n");
+default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
+ fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
+ fmt.eprintf(msg, ..args);
+ fmt.eprintf("\n");
}
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
return string(t.src[offset : t.offset]);
}
-scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) {
+scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
for digit_val(t.ch) < base || t.ch == '_' {
advance_rune(t);
}
}
- scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) {
+ scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) {
if t.ch == 'e' || t.ch == 'E' {
- kind^ = token.Float;
+ kind^ = .Float;
advance_rune(t);
if t.ch == '-' || t.ch == '+' {
advance_rune(t);
@@ -343,17 +342,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
}
// NOTE(bill): This needs to be here for sanity's sake
- if t.ch == 'i' {
- kind^ = token.Imag;
+ switch t.ch {
+ case 'i', 'j', 'k':
+ kind^ = .Imag;
advance_rune(t);
}
}
- scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) {
+ scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
if t.ch == '.' && peek_byte(t) == '.' {
return true;
}
if t.ch == '.' {
- kind^ = token.Float;
+ kind^ = .Float;
advance_rune(t);
scan_mantissa(t, 10);
}
@@ -362,22 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
offset := t.offset;
- kind := token.Integer;
+ kind := Token_Kind.Integer;
seen_point := seen_decimal_point;
if seen_point {
offset -= 1;
- kind = token.Float;
+ kind = .Float;
scan_mantissa(t, 10);
scan_exponent(t, &kind);
} else {
if t.ch == '0' {
- int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) {
+ int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) {
prev := t.offset;
advance_rune(t);
scan_mantissa(t, base);
if t.offset - prev <= 1 {
- kind^ = token.Invalid;
+ kind^ = .Invalid;
error(t, t.offset, msg);
}
}
@@ -394,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
advance_rune(t);
scan_mantissa(t, 16);
if t.offset - prev <= 1 {
- kind = token.Invalid;
+ kind = .Invalid;
error(t, t.offset, "illegal hexadecimal floating-point number");
} else {
sub := t.src[prev+1 : t.offset];
@@ -439,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
}
-scan :: proc(t: ^Tokenizer) -> token.Token {
- switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind {
+scan :: proc(t: ^Tokenizer) -> Token {
+ switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
}
return tok0;
}
- switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind {
+ switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
@@ -458,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
}
return tok0;
}
- switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind {
+ switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
if t.ch == '=' {
advance_rune(t);
return tok1;
@@ -479,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
offset := t.offset;
- kind: token.Kind;
+ kind: Token_Kind;
lit: string;
pos := offset_to_pos(t, offset);
switch ch := t.ch; true {
case is_letter(ch):
lit = scan_identifier(t);
- kind = token.Ident;
+ kind = .Ident;
check_keyword: if len(lit) > 1 {
// TODO(bill): Maybe have a hash table lookup rather than this linear search
- for i in token.B_Keyword_Begin .. token.B_Keyword_End {
- if lit == token.tokens[i] {
- kind = token.Kind(i);
+ for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End {
+ if lit == tokens[i] {
+ kind = Token_Kind(i);
break check_keyword;
}
}
- for keyword, i in token.custom_keyword_tokens {
+ for keyword, i in custom_keyword_tokens {
if lit == keyword {
- kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin;
+ kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
break check_keyword;
}
}
@@ -508,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
advance_rune(t);
switch ch {
case -1:
- kind = token.EOF;
+ kind = .EOF;
case '"':
- kind = token.String;
+ kind = .String;
lit = scan_string(t);
case '\'':
- kind = token.Rune;
+ kind = .Rune;
lit = scan_rune(t);
case '`':
- kind = token.String;
+ kind = .String;
lit = scan_raw_string(t);
case '=':
if t.ch == '>' {
advance_rune(t);
- kind = token.Double_Arrow_Right;
+ kind = .Double_Arrow_Right;
} else {
- kind = switch2(t, token.Eq, token.Cmp_Eq);
+ kind = switch2(t, .Eq, .Cmp_Eq);
}
- case '!': kind = switch2(t, token.Not, token.Not_Eq);
+ case '!': kind = switch2(t, .Not, .Not_Eq);
case '#':
- kind = token.Hash;
+ kind = .Hash;
if t.ch == '!' {
- kind = token.Comment;
+ kind = .Comment;
lit = scan_comment(t);
}
- case '?': kind = token.Question;
- case '@': kind = token.At;
- case '$': kind = token.Dollar;
- case '^': kind = token.Pointer;
- case '+': kind = switch2(t, token.Add, token.Add_Eq);
+ case '?': kind = .Question;
+ case '@': kind = .At;
+ case '$': kind = .Dollar;
+ case '^': kind = .Pointer;
+ case '+': kind = switch2(t, .Add, .Add_Eq);
case '-':
if t.ch == '>' {
advance_rune(t);
- kind = token.Arrow_Right;
+ kind = .Arrow_Right;
} else if t.ch == '-' && peek_byte(t) == '-' {
advance_rune(t);
advance_rune(t);
- kind = token.Undef;
+ kind = .Undef;
} else {
- kind = switch2(t, token.Sub, token.Sub_Eq);
+ kind = switch2(t, .Sub, .Sub_Eq);
}
- case '*': kind = switch2(t, token.Mul, token.Mul_Eq);
+ case '*': kind = switch2(t, .Mul, .Mul_Eq);
case '/':
if t.ch == '/' || t.ch == '*' {
- kind = token.Comment;
+ kind = .Comment;
lit = scan_comment(t);
} else {
- kind = switch2(t, token.Quo, token.Quo_Eq);
+ kind = switch2(t, .Quo, .Quo_Eq);
}
- case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq);
+ case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
case '&':
if t.ch == '~' {
advance_rune(t);
- kind = switch2(t, token.And_Not, token.And_Not_Eq);
+ kind = switch2(t, .And_Not, .And_Not_Eq);
} else {
- kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And);
+ kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
}
- case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or);
- case '~': kind = token.Xor;
+ case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
+ case '~': kind = .Xor;
case '<':
if t.ch == '-' {
advance_rune(t);
- kind = token.Arrow_Left;
+ kind = .Arrow_Left;
} else {
- kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq);
+ kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
}
- case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq);
+ case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
- case '≠': kind = token.Not_Eq;
- case '≤': kind = token.Lt_Eq;
- case '≥': kind = token.Gt_Eq;
- case '∈': kind = token.In;
- case '∉': kind = token.Notin;
+ case '≠': kind = .Not_Eq;
+ case '≤': kind = .Lt_Eq;
+ case '≥': kind = .Gt_Eq;
+ case '∈': kind = .In;
+ case '∉': kind = .Notin;
case '.':
if '0' <= t.ch && t.ch <= '9' {
kind, lit = scan_number(t, true);
} else {
- kind = token.Period;
+ kind = .Period;
if t.ch == '.' {
advance_rune(t);
- kind = token.Ellipsis;
+ kind = .Ellipsis;
if t.ch == '<' {
advance_rune(t);
- kind = token.Range_Half;
+ kind = .Range_Half;
}
}
}
- case ':': kind = token.Colon;
- case ',': kind = token.Comma;
- case ';': kind = token.Semicolon;
- case '(': kind = token.Open_Paren;
- case ')': kind = token.Close_Paren;
- case '[': kind = token.Open_Bracket;
- case ']': kind = token.Close_Bracket;
- case '{': kind = token.Open_Brace;
- case '}': kind = token.Close_Brace;
-
- case '\\': kind = token.Back_Slash;
+ case ':': kind = .Colon;
+ case ',': kind = .Comma;
+ case ';': kind = .Semicolon;
+ case '(': kind = .Open_Paren;
+ case ')': kind = .Close_Paren;
+ case '[': kind = .Open_Bracket;
+ case ']': kind = .Close_Bracket;
+ case '{': kind = .Open_Brace;
+ case '}': kind = .Close_Brace;
+
+ case '\\': kind = .Back_Slash;
case:
if ch != utf8.RUNE_BOM {
error(t, t.offset, "illegal character '%r': %d", ch, ch);
}
- kind = token.Invalid;
+ kind = .Invalid;
}
}
if lit == "" {
lit = string(t.src[offset : t.offset]);
}
- return token.Token{kind, lit, pos};
+ return Token{kind, lit, pos};
}
diff --git a/core/os/os_osx.odin b/core/os/os_darwin.odin
index e0950dee1..f48a547b6 100644
--- a/core/os/os_osx.odin
+++ b/core/os/os_darwin.odin
@@ -6,7 +6,7 @@ foreign import libc "system:c"
import "core:runtime"
import "core:strings"
-OS :: "osx";
+OS :: "darwin";
Handle :: distinct i32;
File_Time :: distinct u64;
@@ -319,9 +319,9 @@ dlerror :: proc() -> string {
_alloc_command_line_arguments :: proc() -> []string {
- args := make([]string, len(runtime.args__));
+ res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ {
- args[i] = string(arg);
+ res[i] = string(arg);
}
- return args;
+ return res;
}
diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin
index 2fe62b873..d11c0503b 100644
--- a/core/os/os_essence.odin
+++ b/core/os/os_essence.odin
@@ -1,180 +1,2440 @@
-package os
+package os;
+Data :: struct { _private : [4]rawptr, }
+Generic :: rawptr;
+Element :: struct { _private : u8, };
+Object :: rawptr;
+LongDouble :: struct { value : [10]u8, };
+NodeType :: u64;
+Error :: int;
+Handle :: uint;
+Response :: i32;
+FileOffset :: u64;
+ListViewIndex :: i32;
+ThreadEntryFunction :: distinct #type proc (Generic);
+ComparisonCallbackFunction :: distinct #type proc (rawptr, rawptr, Generic) -> i32;
+SwapCallbackFunction :: distinct #type proc (rawptr, rawptr, Generic);
+CRTComparisonCallback :: distinct #type proc (rawptr, rawptr) -> i32;
+MessageCallbackFunction :: distinct #type proc (Object, ^Message, ^Response);
+UICallbackFunction :: distinct #type proc (^Element, ^Message, ^Response);
+Window :: struct { using element : Element, };
+Panel :: struct { using element : Element, };
+Scrollbar :: struct { using element : Element, };
+Button :: struct { using element : Element, };
+Textbox :: struct { using element : Element, };
+ListView :: struct { using element : Element, };
+NumericEntry :: struct { using element : Element, };
+Menu :: struct { using element : Element, };
+MenuCallbackFunction :: distinct #type proc (^Element, Generic);
+INSTANCE_TYPE :: Instance;
+SCANCODE_A :: (0x1C);
+SCANCODE_B :: (0x32);
+SCANCODE_C :: (0x21);
+SCANCODE_D :: (0x23);
+SCANCODE_E :: (0x24);
+SCANCODE_F :: (0x2B);
+SCANCODE_G :: (0x34);
+SCANCODE_H :: (0x33);
+SCANCODE_I :: (0x43);
+SCANCODE_J :: (0x3B);
+SCANCODE_K :: (0x42);
+SCANCODE_L :: (0x4B);
+SCANCODE_M :: (0x3A);
+SCANCODE_N :: (0x31);
+SCANCODE_O :: (0x44);
+SCANCODE_P :: (0x4D);
+SCANCODE_Q :: (0x15);
+SCANCODE_R :: (0x2D);
+SCANCODE_S :: (0x1B);
+SCANCODE_T :: (0x2C);
+SCANCODE_U :: (0x3C);
+SCANCODE_V :: (0x2A);
+SCANCODE_W :: (0x1D);
+SCANCODE_X :: (0x22);
+SCANCODE_Y :: (0x35);
+SCANCODE_Z :: (0x1A);
+SCANCODE_0 :: (0x45);
+SCANCODE_1 :: (0x16);
+SCANCODE_2 :: (0x1E);
+SCANCODE_3 :: (0x26);
+SCANCODE_4 :: (0x25);
+SCANCODE_5 :: (0x2E);
+SCANCODE_6 :: (0x36);
+SCANCODE_7 :: (0x3D);
+SCANCODE_8 :: (0x3E);
+SCANCODE_9 :: (0x46);
+SCANCODE_CAPS_LOCK :: (0x58);
+SCANCODE_SCROLL_LOCK :: (0x7E);
+SCANCODE_NUM_LOCK :: (0x77) ;
+SCANCODE_LEFT_SHIFT :: (0x12);
+SCANCODE_LEFT_CTRL :: (0x14);
+SCANCODE_LEFT_ALT :: (0x11);
+SCANCODE_LEFT_FLAG :: (0x11F);
+SCANCODE_RIGHT_SHIFT :: (0x59);
+SCANCODE_RIGHT_CTRL :: (0x114);
+SCANCODE_RIGHT_ALT :: (0x111);
+SCANCODE_PAUSE :: (0xE1);
+SCANCODE_CONTEXT_MENU :: (0x127);
+SCANCODE_BACKSPACE :: (0x66);
+SCANCODE_ESCAPE :: (0x76);
+SCANCODE_INSERT :: (0x170);
+SCANCODE_HOME :: (0x16C);
+SCANCODE_PAGE_UP :: (0x17D);
+SCANCODE_DELETE :: (0x171);
+SCANCODE_END :: (0x169);
+SCANCODE_PAGE_DOWN :: (0x17A);
+SCANCODE_UP_ARROW :: (0x175);
+SCANCODE_LEFT_ARROW :: (0x16B);
+SCANCODE_DOWN_ARROW :: (0x172);
+SCANCODE_RIGHT_ARROW :: (0x174);
+SCANCODE_SPACE :: (0x29);
+SCANCODE_TAB :: (0x0D);
+SCANCODE_ENTER :: (0x5A);
+SCANCODE_SLASH :: (0x4A);
+SCANCODE_BACKSLASH :: (0x5D);
+SCANCODE_LEFT_BRACE :: (0x54);
+SCANCODE_RIGHT_BRACE :: (0x5B);
+SCANCODE_EQUALS :: (0x55);
+SCANCODE_BACKTICK :: (0x0E);
+SCANCODE_HYPHEN :: (0x4E);
+SCANCODE_SEMICOLON :: (0x4C);
+SCANCODE_QUOTE :: (0x52);
+SCANCODE_COMMA :: (0x41);
+SCANCODE_PERIOD :: (0x49);
+SCANCODE_NUM_DIVIDE :: (0x14A);
+SCANCODE_NUM_MULTIPLY :: (0x7C);
+SCANCODE_NUM_SUBTRACT :: (0x7B);
+SCANCODE_NUM_ADD :: (0x79);
+SCANCODE_NUM_ENTER :: (0x15A);
+SCANCODE_NUM_POINT :: (0x71);
+SCANCODE_NUM_0 :: (0x70);
+SCANCODE_NUM_1 :: (0x69);
+SCANCODE_NUM_2 :: (0x72);
+SCANCODE_NUM_3 :: (0x7A);
+SCANCODE_NUM_4 :: (0x6B);
+SCANCODE_NUM_5 :: (0x73);
+SCANCODE_NUM_6 :: (0x74);
+SCANCODE_NUM_7 :: (0x6C);
+SCANCODE_NUM_8 :: (0x75);
+SCANCODE_NUM_9 :: (0x7D);
+SCANCODE_PRINT_SCREEN_1 :: (0x112) ;
+SCANCODE_PRINT_SCREEN_2 :: (0x17C);
+SCANCODE_F1 :: (0x05);
+SCANCODE_F2 :: (0x06);
+SCANCODE_F3 :: (0x04);
+SCANCODE_F4 :: (0x0C);
+SCANCODE_F5 :: (0x03);
+SCANCODE_F6 :: (0x0B);
+SCANCODE_F7 :: (0x83);
+SCANCODE_F8 :: (0x0A);
+SCANCODE_F9 :: (0x01);
+SCANCODE_F10 :: (0x09);
+SCANCODE_F11 :: (0x78);
+SCANCODE_F12 :: (0x07);
+SCANCODE_ACPI_POWER :: (0x137);
+SCANCODE_ACPI_SLEEP :: (0x13F);
+SCANCODE_ACPI_WAKE :: (0x15E);
+SCANCODE_MM_NEXT :: (0x14D);
+SCANCODE_MM_PREVIOUS :: (0x115);
+SCANCODE_MM_STOP :: (0x13B);
+SCANCODE_MM_PAUSE :: (0x134);
+SCANCODE_MM_MUTE :: (0x123);
+SCANCODE_MM_QUIETER :: (0x121);
+SCANCODE_MM_LOUDER :: (0x132);
+SCANCODE_MM_SELECT :: (0x150);
+SCANCODE_MM_EMAIL :: (0x148);
+SCANCODE_MM_CALC :: (0x12B);
+SCANCODE_MM_FILES :: (0x140);
+SCANCODE_WWW_SEARCH :: (0x110);
+SCANCODE_WWW_HOME :: (0x13A);
+SCANCODE_WWW_BACK :: (0x138);
+SCANCODE_WWW_FORWARD :: (0x130);
+SCANCODE_WWW_STOP :: (0x128);
+SCANCODE_WWW_REFRESH :: (0x120);
+SCANCODE_WWW_STARRED :: (0x118);
+PROCESS_STATE_ALL_THREADS_TERMINATED :: (1);
+PROCESS_STATE_TERMINATING :: (2);
+PROCESS_STATE_CRASHED :: (4);
+FLAGS_DEFAULT :: (0);
+SUCCESS :: (-1);
+ERROR_BUFFER_TOO_SMALL :: (-2);
+ERROR_UNKNOWN_OPERATION_FAILURE :: (-7);
+ERROR_NO_MESSAGES_AVAILABLE :: (-9);
+ERROR_MESSAGE_QUEUE_FULL :: (-10);
+ERROR_MESSAGE_NOT_HANDLED_BY_GUI :: (-13);
+ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14);
+ERROR_PATH_NOT_TRAVERSABLE :: (-15);
+ERROR_FILE_ALREADY_EXISTS :: (-19);
+ERROR_FILE_DOES_NOT_EXIST :: (-20);
+ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) ;
+ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) ;
+ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23);
+ERROR_FILE_IN_EXCLUSIVE_USE :: (-24);
+ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25);
+ERROR_INCORRECT_NODE_TYPE :: (-26);
+ERROR_EVENT_NOT_SET :: (-27);
+ERROR_TIMEOUT_REACHED :: (-29);
+ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: (-30);
+ERROR_NO_CHARACTER_AT_COORDINATE :: (-31);
+ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32);
+ERROR_USER_CANCELED_IO :: (-33);
+ERROR_INVALID_DIMENSIONS :: (-34);
+ERROR_DRIVE_CONTROLLER_REPORTED :: (-35);
+ERROR_COULD_NOT_ISSUE_PACKET :: (-36);
+ERROR_HANDLE_TABLE_FULL :: (-37);
+ERROR_COULD_NOT_RESIZE_FILE :: (-38);
+ERROR_DIRECTORY_NOT_EMPTY :: (-39);
+ERROR_UNSUPPORTED_FILESYSTEM :: (-40);
+ERROR_NODE_ALREADY_DELETED :: (-41);
+ERROR_NODE_IS_ROOT :: (-42);
+ERROR_VOLUME_MISMATCH :: (-43);
+ERROR_TARGET_WITHIN_SOURCE :: (-44);
+ERROR_TARGET_INVALID_TYPE :: (-45);
+ERROR_NOTHING_TO_DRAW :: (-46);
+ERROR_MALFORMED_NODE_PATH :: (-47);
+ERROR_OUT_OF_CACHE_RESOURCES :: (-48);
+ERROR_TARGET_IS_SOURCE :: (-49);
+ERROR_INVALID_NAME :: (-50);
+ERROR_CORRUPT_DATA :: (-51);
+ERROR_INSUFFICIENT_RESOURCES :: (-52);
+ERROR_UNSUPPORTED_FEATURE :: (-53);
+ERROR_FILE_TOO_FRAGMENTED :: (-54);
+ERROR_DRIVE_FULL :: (-55);
+ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56);
+ERROR_ALREADY_EMBEDDED :: (-57);
+SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0);
+SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (2);
+SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (3);
+SYSTEM_CONSTANT_RIGHT_TO_LEFT :: (4);
+INVALID_HANDLE :: ((Handle) (0));
+CURRENT_THREAD :: ((Handle) (0x10));
+CURRENT_PROCESS :: ((Handle) (0x11));
+SURFACE_UI_SHEET :: ((Handle) (0x20));
+SURFACE_WALLPAPER :: ((Handle) (0x21));
+DRAW_ALPHA_OVERWRITE :: (0x100);
+DRAW_ALPHA_FULL :: (0x200) ;
+WAIT_NO_TIMEOUT :: (-1);
+MAX_WAIT_COUNT :: (16);
+MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256);
+PROCESS_EXECUTABLE_NOT_LOADED :: 0;
+PROCESS_EXECUTABLE_FAILED_TO_LOAD :: 1;
+PROCESS_EXECUTABLE_LOADED :: 2;
+SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80);
+SYSTEM_SNAPSHOT_PROCESSES :: (1);
+SYSTEM_SNAPSHOT_DRIVES :: (2);
+NOT_HANDLED :: (-1);
+HANDLED :: (0);
+REJECTED :: (-2);
+SHARED_MEMORY_MAXIMUM_SIZE :: ( (1024) * 1024 * 1024 * 1024);
+SHARED_MEMORY_NAME_MAX_LENGTH :: (32);
+MAP_OBJECT_ALL :: (0);
+DRAW_STRING_HALIGN_LEFT :: (1);
+DRAW_STRING_HALIGN_RIGHT :: (2);
+DRAW_STRING_HALIGN_CENTER :: (3);
+DRAW_STRING_VALIGN_TOP :: (4);
+DRAW_STRING_VALIGN_BOTTOM :: (8);
+DRAW_STRING_VALIGN_CENTER :: (12);
+DRAW_STRING_CLIP :: (0);
+DRAW_STRING_WORD_WRAP :: (16);
+DRAW_STRING_ELLIPSIS :: (32);
+NODE_READ_NONE :: (0x0);
+NODE_READ_BLOCK :: (0x1);
+NODE_READ_ACCESS :: (0x2);
+NODE_READ_EXCLUSIVE :: (0x3);
+NODE_WRITE_NONE :: (0x00);
+NODE_WRITE_BLOCK :: (0x10);
+NODE_WRITE_ACCESS :: (0x20);
+NODE_WRITE_EXCLUSIVE :: (0x30);
+NODE_RESIZE_NONE :: (0x000);
+NODE_RESIZE_BLOCK :: (0x100);
+NODE_RESIZE_ACCESS :: (0x200);
+NODE_RESIZE_EXCLUSIVE :: (0x300);
+NODE_FAIL_IF_FOUND :: (0x1000);
+NODE_FAIL_IF_NOT_FOUND :: (0x2000);
+NODE_CREATE_DIRECTORIES :: (0x8000) ;
+NODE_POSIX_NAMESPACE :: (0x10000) ;
+DIRECTORY_CHILDREN_UNKNOWN :: ( (-1));
+MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000);
+MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000);
+MAP_OBJECT_READ_WRITE :: (0);
+MAP_OBJECT_READ_ONLY :: (1);
+MAP_OBJECT_COPY_ON_WRITE :: (2);
+BOX_STYLE_OUTWARDS :: (0x01) ;
+BOX_STYLE_INWARDS :: (0x02) ;
+BOX_STYLE_NEUTRAL :: (0x03) ;
+BOX_STYLE_FLAT :: (0x04) ;
+BOX_STYLE_NONE :: (0x05) ;
+BOX_STYLE_SELECTED :: (0x06) ;
+BOX_STYLE_PUSHED :: (0x07) ;
+BOX_STYLE_DOTTED :: (0x80);
+BOX_COLOR_GRAY :: (0xC0C0C0);
+BOX_COLOR_DARK_GRAY :: (0x808080);
+BOX_COLOR_WHITE :: (0xFFFFFF);
+BOX_COLOR_BLUE :: (0x000080);
+BOX_COLOR_TRANSPARENT :: (0xFF00FF);
+BOX_COLOR_BLACK :: (0x000000);
+STRING_FORMAT_ENOUGH_SPACE :: ( (-1));
+POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000);
+PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0);
+PERMISSION_ACCESS_USER_FILES :: (1 << 1);
+PERMISSION_PROCESS_CREATE :: (1 << 2);
+PERMISSION_PROCESS_OPEN :: (1 << 3);
+PERMISSION_SCREEN_MODIFY :: (1 << 4) ;
+PERMISSION_SHUTDOWN :: (1 << 5);
+PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6);
+PERMISSION_WINDOW_OPEN :: (1 << 7);
+PERMISSION_ALL :: ( (-1));
+PERMISSION_INHERIT :: ( (1 << 63));
+PANEL_STYLE_DEFAULT :: "Panel.Default";
+PANEL_STYLE_MENU_COLUMN :: "Panel.Menu.Column";
+PANEL_WRAP :: ( (0x0001) << 32);
+PANEL_H_LEFT :: ( (0x0010) << 32);
+PANEL_H_RIGHT :: ( (0x0020) << 32);
+PANEL_H_CENTER :: ( (0x0040) << 32);
+PANEL_H_JUSTIFY :: ( (0x0080) << 32);
+PANEL_V_TOP :: ( (0x0100) << 32);
+PANEL_V_BOTTOM :: ( (0x0200) << 32);
+PANEL_V_CENTER :: ( (0x0400) << 32);
+PANEL_V_JUSTIFY :: ( (0x0800) << 32);
+PANEL_H_SCROLL :: ( (0x1000) << 32);
+PANEL_V_SCROLL :: ( (0x2000) << 32);
+CELL_H_PUSH :: ( (0x0001) << 16);
+CELL_H_EXPAND :: ( (0x0002) << 16);
+CELL_H_LEFT :: ( (0x0004) << 16);
+CELL_H_RIGHT :: ( (0x0008) << 16);
+CELL_H_SHRINK :: ( (0x0010) << 16);
+CELL_V_PUSH :: ( (0x0100) << 16);
+CELL_V_EXPAND :: ( (0x0200) << 16);
+CELL_V_TOP :: ( (0x0400) << 16);
+CELL_V_BOTTOM :: ( (0x0800) << 16);
+CELL_V_SHRINK :: ( (0x1000) << 16);
+CELL_NEW_BAND :: ( (0x8000) << 16);
+CELL_HIDDEN :: ( (0xFFFF) << 16);
+ELEMENT_DO_NOT_FREE_STYLE_OVERRIDE :: (1 << 0);
+ELEMENT_RICH_TEXT :: (1 << 1);
+ELEMENT_FOCUSABLE :: (1 << 2);
+ELEMENT_Z_STACK :: (1 << 3) ;
+ELEMENT_HIDDEN :: (1 << 4);
+ELEMENT_USE_CHILD_AS_PARENT :: (1 << 5) ;
+ELEMENT_DISABLED :: (1 << 6);
+ELEMENT_WINDOW_COORDS_FOR_MOUSE :: (1 << 7) ;
+TEXTBOX_MULTILINE :: (1 << 0);
+TEXTBOX_BORDERED :: (1 << 1);
+BUTTON_DEFAULT :: ( (1) << 32);
+BUTTON_DANGEROUS :: ( (1) << 33);
+BUTTON_MENU_ITEM :: ( (1) << 34);
+BUTTON_NOT_FOCUSABLE :: ( (1) << 35);
+BUTTON_TOOLBAR :: ( (1) << 36);
+SCROLLBAR_VERTICAL :: ( (0) << 32);
+SCROLLBAR_HORIZONTAL :: ( (1) << 32);
+LIST_VIEW_INDEX_GROUP_HEADER :: (-1);
+LIST_VIEW_ITEM_CONTENT_TEXT :: (1 << 0);
+LIST_VIEW_ITEM_CONTENT_ICON :: (1 << 1);
+LIST_VIEW_ITEM_CONTENT_INDENTATION :: (1 << 2);
+LIST_VIEW_ITEM_STATE_SELECTED :: (1 << 0);
+LIST_VIEW_ITEM_STATE_CHECKED :: (1 << 1);
+LIST_VIEW_ITEM_STATE_HIDDEN :: (1 << 2);
+LIST_VIEW_ITEM_STATE_EXPANDABLE :: (1 << 3);
+LIST_VIEW_ITEM_STATE_CHECKABLE :: (1 << 4);
+LIST_VIEW_ITEM_STATE_DROP_TARGET :: (1 << 5);
+LIST_VIEW_ITEM_STATE_COLLAPSABLE :: (1 << 6);
+LIST_VIEW_ITEM_STATE_PARTIAL_CHECK :: (1 << 7);
+LIST_VIEW_ITEM_STATE_DRAG_SOURCE :: (1 << 8);
+LIST_VIEW_ITEM_STATE_CUT :: (1 << 9);
+LIST_VIEW_FIND_ITEM_FROM_Y_POSITION :: (0);
+LIST_VIEW_FIND_ITEM_FROM_TEXT_PREFIX :: (1);
+LIST_VIEW_FIND_ITEM_NON_HIDDEN :: (2);
+LIST_VIEW_FIND_ITEM_PARENT :: (3);
+LIST_VIEW_COLUMN_DEFAULT_WIDTH_PRIMARY :: (270);
+LIST_VIEW_COLUMN_DEFAULT_WIDTH_SECONDARY :: (130);
+LIST_VIEW_COLUMN_PRIMARY :: (1);
+LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (2);
+LIST_VIEW_COLUMN_SORT_ASCENDING :: (8);
+LIST_VIEW_COLUMN_SORT_DESCENDING :: (16);
+LIST_VIEW_COLUMN_SORTABLE :: (32);
+LIST_VIEW_SINGLE_SELECT :: ( (1) << 32) ;
+LIST_VIEW_MULTI_SELECT :: ( (1) << 33) ;
+LIST_VIEW_HAS_COLUMNS :: ( (1) << 34) ;
+LIST_VIEW_HAS_GROUPS :: ( (1) << 35) ;
+LIST_VIEW_FIXED_HEIGHT :: ( (1) << 36) ;
+LIST_VIEW_VARIABLE_HEIGHT :: ( (1) << 37) ;
+LIST_VIEW_TREE :: ( (1) << 38) ;
+LIST_VIEW_TILED :: ( (1) << 39) ;
+LIST_VIEW_BORDERED :: ( (1) << 41) ;
+LIST_VIEW_DROP_TARGET_ORDERED :: ( (1) << 43) ;
+LIST_VIEW_DROP_TARGET_UNORDERED :: ( (1) << 44) ;
+LIST_VIEW_ROW_DIVIDERS :: ( (1) << 45) ;
+LIST_VIEW_STATIC_GROUP_HEADERS :: ( (1) << 46) ;
+LIST_VIEW_COLLAPSABLE_GROUPS :: ( (1) << 47) ;
+LIST_VIEW_INTERNAL_SELECTION_STORAGE :: ( (1) << 48) ;
+LIST_VIEW_HAND_CURSOR :: ( (1) << 49) ;
+LIST_VIEW_NO_ITEM_BACKGROUNDS :: ( (1) << 50) ;
+LIST_VIEW_RICH_TEXT :: ( (1) << 52) ;
+LIST_VIEW_LABELS_BELOW :: ( (1) << 53) ;
+LIST_VIEW_MAXIMUM_ITEMS :: (10 * 1000 * 1000);
+LIST_VIEW_MAXIMUM_GROUPS :: (10 * 1000);
+LIST_VIEW_TRANSITION_BACKWARDS :: (1);
+LIST_VIEW_TRANSITION_DRAW_NEW_CONTENTS_ONCE :: (2) ;
+MENU_AT_CURSOR :: (1 << 0);
+StandardIcon :: enum {
+ ICON_ACTION_UNAVAILABLE_SYMBOLIC,
+ ICON_ADDRESS_BOOK_NEW,
+ ICON_ADDRESS_BOOK_NEW_SYMBOLIC,
+ ICON_ALIGN_HORIZONTAL_CENTER,
+ ICON_ALIGN_HORIZONTAL_CENTER_SYMBOLIC,
+ ICON_ALIGN_HORIZONTAL_LEFT,
+ ICON_ALIGN_HORIZONTAL_LEFT_SYMBOLIC,
+ ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR,
+ ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR_SYMBOLIC,
+ ICON_ALIGN_HORIZONTAL_RIGHT,
+ ICON_ALIGN_HORIZONTAL_RIGHT_SYMBOLIC,
+ ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR,
+ ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR_SYMBOLIC,
+ ICON_ALIGN_VERTICAL_BOTTOM,
+ ICON_ALIGN_VERTICAL_BOTTOM_SYMBOLIC,
+ ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR,
+ ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR_SYMBOLIC,
+ ICON_ALIGN_VERTICAL_CENTER,
+ ICON_ALIGN_VERTICAL_CENTER_SYMBOLIC,
+ ICON_ALIGN_VERTICAL_TOP,
+ ICON_ALIGN_VERTICAL_TOP_SYMBOLIC,
+ ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR,
+ ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR_SYMBOLIC,
+ ICON_APPLICATION_ADD_SYMBOLIC,
+ ICON_APPOINTMENT_NEW,
+ ICON_APPOINTMENT_NEW_SYMBOLIC,
+ ICON_APPOINTMENT_SYMBOLIC,
+ ICON_BOOKMARK_NEW,
+ ICON_BOOKMARK_NEW_SYMBOLIC,
+ ICON_CALL_START,
+ ICON_CALL_START_SYMBOLIC,
+ ICON_CALL_STOP,
+ ICON_CALL_STOP_SYMBOLIC,
+ ICON_COLOR_FILL,
+ ICON_COLOR_GRADIENT,
+ ICON_COLOR_GRADIENT_MESH,
+ ICON_COLOR_SELECT_SYMBOLIC,
+ ICON_CONTACT_NEW,
+ ICON_CONTACT_NEW_SYMBOLIC,
+ ICON_DISTRIBUTE_HORIZONTAL_CENTER,
+ ICON_DISTRIBUTE_HORIZONTAL_GAPS,
+ ICON_DISTRIBUTE_HORIZONTAL_LEFT,
+ ICON_DISTRIBUTE_HORIZONTAL_RIGHT,
+ ICON_DISTRIBUTE_VERTICAL_BOTTOM,
+ ICON_DISTRIBUTE_VERTICAL_CENTER,
+ ICON_DISTRIBUTE_VERTICAL_GAPS,
+ ICON_DISTRIBUTE_VERTICAL_TOP,
+ ICON_DOCUMENT_EDIT,
+ ICON_DOCUMENT_EDIT_SYMBOLIC,
+ ICON_DOCUMENT_EXPORT,
+ ICON_DOCUMENT_EXPORT_SYMBOLIC,
+ ICON_DOCUMENT_IMPORT,
+ ICON_DOCUMENT_IMPORT_SYMBOLIC,
+ ICON_DOCUMENT_NEW,
+ ICON_DOCUMENT_NEW_SYMBOLIC,
+ ICON_DOCUMENT_OPEN_RECENT,
+ ICON_DOCUMENT_OPEN_RECENT_SYMBOLIC,
+ ICON_DOCUMENT_OPEN_SYMBOLIC,
+ ICON_DOCUMENT_PAGE_SETUP,
+ ICON_DOCUMENT_PAGE_SETUP_SYMBOLIC,
+ ICON_DOCUMENT_PRINT_PREVIEW,
+ ICON_DOCUMENT_PRINT_PREVIEW_SYMBOLIC,
+ ICON_DOCUMENT_PRINT_SYMBOLIC,
+ ICON_DOCUMENT_PROPERTIES,
+ ICON_DOCUMENT_PROPERTIES_SYMBOLIC,
+ ICON_DOCUMENT_REVERT,
+ ICON_DOCUMENT_REVERT_SYMBOLIC,
+ ICON_DOCUMENT_SAVE_AS,
+ ICON_DOCUMENT_SAVE_AS_SYMBOLIC,
+ ICON_DOCUMENT_SAVE_SYMBOLIC,
+ ICON_DOCUMENT_SEND,
+ ICON_DOCUMENT_SEND_SYMBOLIC,
+ ICON_DRAW_CUBOID,
+ ICON_DRAW_ELLIPSE,
+ ICON_DRAW_ERASER,
+ ICON_DRAW_FREEHAND,
+ ICON_DRAW_PATH,
+ ICON_DRAW_POLYGON_STAR,
+ ICON_DRAW_RECTANGLE,
+ ICON_DRAW_SPIRAL,
+ ICON_DRAW_TEXT,
+ ICON_EDIT_CLEAR,
+ ICON_EDIT_CLEAR_ALL_SYMBOLIC,
+ ICON_EDIT_CLEAR_SYMBOLIC,
+ ICON_EDIT_COPY,
+ ICON_EDIT_COPY_SYMBOLIC,
+ ICON_EDIT_CUT,
+ ICON_EDIT_CUT_SYMBOLIC,
+ ICON_EDIT_DELETE_SYMBOLIC,
+ ICON_EDIT_FIND,
+ ICON_EDIT_FIND_REPLACE,
+ ICON_EDIT_FIND_REPLACE_SYMBOLIC,
+ ICON_EDIT_FIND_SYMBOLIC,
+ ICON_EDIT_FLAG,
+ ICON_EDIT_FLAG_SYMBOLIC,
+ ICON_EDIT_MARK,
+ ICON_EDIT_PASTE,
+ ICON_EDIT_PASTE_SYMBOLIC,
+ ICON_EDIT_REDO,
+ ICON_EDIT_REDO_SYMBOLIC,
+ ICON_EDIT_SELECT_ALL,
+ ICON_EDIT_SELECT_ALL_SYMBOLIC,
+ ICON_EDIT_SELECT_SYMBOLIC,
+ ICON_EDIT_UNDO,
+ ICON_EDIT_UNDO_ARCHIVE,
+ ICON_EDIT_UNDO_SYMBOLIC,
+ ICON_ERROR_CORRECT_SYMBOLIC,
+ ICON_EVENT_NEW,
+ ICON_FIND_LOCATION,
+ ICON_FIND_LOCATION_SYMBOLIC,
+ ICON_FOLDER_COPY,
+ ICON_FOLDER_MOVE,
+ ICON_FOLDER_NEW,
+ ICON_FOLDER_NEW_SYMBOLIC,
+ ICON_FONT_SELECT_SYMBOLIC,
+ ICON_FORMAT_INDENT_LESS,
+ ICON_FORMAT_INDENT_LESS_SYMBOLIC,
+ ICON_FORMAT_INDENT_MORE,
+ ICON_FORMAT_INDENT_MORE_SYMBOLIC,
+ ICON_FORMAT_JUSTIFY_CENTER,
+ ICON_FORMAT_JUSTIFY_CENTER_SYMBOLIC,
+ ICON_FORMAT_JUSTIFY_FILL,
+ ICON_FORMAT_JUSTIFY_FILL_SYMBOLIC,
+ ICON_FORMAT_JUSTIFY_LEFT,
+ ICON_FORMAT_JUSTIFY_LEFT_SYMBOLIC,
+ ICON_FORMAT_JUSTIFY_RIGHT,
+ ICON_FORMAT_JUSTIFY_RIGHT_SYMBOLIC,
+ ICON_FORMAT_TEXT_BOLD,
+ ICON_FORMAT_TEXT_BOLD_ES_SYMBOLIC,
+ ICON_FORMAT_TEXT_BOLD_FR_SYMBOLIC,
+ ICON_FORMAT_TEXT_BOLD_SYMBOLIC,
+ ICON_FORMAT_TEXT_CLEAR_FORMATTING_SYMBOLIC,
+ ICON_FORMAT_TEXT_DIRECTION_LTR_SYMBOLIC,
+ ICON_FORMAT_TEXT_HIGHLIGHT,
+ ICON_FORMAT_TEXT_ITALIC,
+ ICON_FORMAT_TEXT_ITALIC_ES_SYMBOLIC,
+ ICON_FORMAT_TEXT_ITALIC_SYMBOLIC,
+ ICON_FORMAT_TEXT_LARGER_SYMBOLIC,
+ ICON_FORMAT_TEXT_NONE,
+ ICON_FORMAT_TEXT_SMALLER_SYMBOLIC,
+ ICON_FORMAT_TEXT_STRIKETHROUGH,
+ ICON_FORMAT_TEXT_STRIKETHROUGH_FR_SYMBOLIC,
+ ICON_FORMAT_TEXT_STRIKETHROUGH_SYMBOLIC,
+ ICON_FORMAT_TEXT_UNDERLINE,
+ ICON_FORMAT_TEXT_UNDERLINE_FR_SYMBOLIC,
+ ICON_FORMAT_TEXT_UNDERLINE_SYMBOLIC,
+ ICON_GO_BOTTOM,
+ ICON_GO_BOTTOM_SYMBOLIC,
+ ICON_GO_DOWN,
+ ICON_GO_DOWN_SYMBOLIC,
+ ICON_GO_FIRST,
+ ICON_GO_FIRST_SYMBOLIC,
+ ICON_GO_HOME_SYMBOLIC,
+ ICON_GO_JUMP,
+ ICON_GO_JUMP_SYMBOLIC,
+ ICON_GO_LAST,
+ ICON_GO_LAST_SYMBOLIC,
+ ICON_GO_NEXT,
+ ICON_GO_NEXT_SYMBOLIC,
+ ICON_GO_PREVIOUS,
+ ICON_GO_PREVIOUS_SYMBOLIC,
+ ICON_GO_TOP,
+ ICON_GO_TOP_SYMBOLIC,
+ ICON_GO_UP,
+ ICON_GO_UP_SYMBOLIC,
+ ICON_HELP_ABOUT,
+ ICON_HELP_ABOUT_SYMBOLIC,
+ ICON_HELP_CONTENTS,
+ ICON_HELP_CONTENTS_SYMBOLIC,
+ ICON_HELP_INFO_SYMBOLIC,
+ ICON_IMAGE_ADJUST,
+ ICON_IMAGE_AUTO_ADJUST,
+ ICON_IMAGE_CROP,
+ ICON_IMAGE_CROP_SYMBOLIC,
+ ICON_IMAGE_RED_EYE,
+ ICON_IMAGE_RED_EYE_SYMBOLIC,
+ ICON_INSERT_IMAGE,
+ ICON_INSERT_IMAGE_SYMBOLIC,
+ ICON_INSERT_LINK,
+ ICON_INSERT_LINK_SYMBOLIC,
+ ICON_INSERT_OBJECT,
+ ICON_INSERT_OBJECT_SYMBOLIC,
+ ICON_INSERT_TEXT_SYMBOLIC,
+ ICON_LIST_ADD,
+ ICON_LIST_ADD_SYMBOLIC,
+ ICON_LIST_REMOVE,
+ ICON_LIST_REMOVE_SYMBOLIC,
+ ICON_MAIL_ARCHIVE,
+ ICON_MAIL_FORWARD,
+ ICON_MAIL_FORWARD_SYMBOLIC,
+ ICON_MAIL_MARK_IMPORTANT,
+ ICON_MAIL_MARK_IMPORTANT_SYMBOLIC,
+ ICON_MAIL_MARK_JUNK,
+ ICON_MAIL_MARK_JUNK_SYMBOLIC,
+ ICON_MAIL_MARK_NOTJUNK,
+ ICON_MAIL_MARK_NOTJUNK_SYMBOLIC,
+ ICON_MAIL_MESSAGE_NEW,
+ ICON_MAIL_MESSAGE_NEW_SYMBOLIC,
+ ICON_MAIL_MOVE,
+ ICON_MAIL_MOVE_SYMBOLIC,
+ ICON_MAIL_REPLY_ALL,
+ ICON_MAIL_REPLY_ALL_SYMBOLIC,
+ ICON_MAIL_REPLY_SENDER,
+ ICON_MAIL_REPLY_SENDER_SYMBOLIC,
+ ICON_MAIL_SEND,
+ ICON_MAIL_SEND_RECEIVE_SYMBOLIC,
+ ICON_MAIL_SEND_SYMBOLIC,
+ ICON_MARK_LOCATION_SYMBOLIC,
+ ICON_MEDIA_EJECT,
+ ICON_MEDIA_EJECT_SYMBOLIC,
+ ICON_MEDIA_EQ_SYMBOLIC,
+ ICON_MEDIA_PLAYBACK_PAUSE,
+ ICON_MEDIA_PLAYBACK_PAUSE_SYMBOLIC,
+ ICON_MEDIA_PLAYBACK_START,
+ ICON_MEDIA_PLAYBACK_START_SYMBOLIC,
+ ICON_MEDIA_PLAYBACK_STOP,
+ ICON_MEDIA_PLAYBACK_STOP_SYMBOLIC,
+ ICON_MEDIA_RECORD,
+ ICON_MEDIA_RECORD_SYMBOLIC,
+ ICON_MEDIA_SEEK_BACKWARD,
+ ICON_MEDIA_SEEK_BACKWARD_SYMBOLIC,
+ ICON_MEDIA_SEEK_FORWARD,
+ ICON_MEDIA_SEEK_FORWARD_SYMBOLIC,
+ ICON_MEDIA_SKIP_BACKWARD,
+ ICON_MEDIA_SKIP_FORWARD,
+ ICON_MEDIA_VIEW_SUBTITLES_SYMBOLIC,
+ ICON_NODE_ADD,
+ ICON_NODE_ALIGN_HORIZONTAL,
+ ICON_NODE_ALIGN_VERTICAL,
+ ICON_NODE_BREAK,
+ ICON_NODE_CUSP,
+ ICON_NODE_DELETE,
+ ICON_NODE_DELETE_SEGMENT,
+ ICON_NODE_DISTRIBUTE_HORIZONTAL,
+ ICON_NODE_DISTRIBUTE_VERTICAL,
+ ICON_NODE_INSERT,
+ ICON_NODE_JOIN,
+ ICON_NODE_JOIN_SEGMENT,
+ ICON_NODE_SMOOTH,
+ ICON_NODE_SYMMETRIC,
+ ICON_OBJECT_FLIP_HORIZONTAL,
+ ICON_OBJECT_FLIP_HORIZONTAL_SYMBOLIC,
+ ICON_OBJECT_FLIP_VERTICAL,
+ ICON_OBJECT_FLIP_VERTICAL_SYMBOLIC,
+ ICON_OBJECT_GROUP,
+ ICON_OBJECT_GROUP_SYMBOLIC,
+ ICON_OBJECT_INVERSE,
+ ICON_OBJECT_INVERSE_SYMBOLIC,
+ ICON_OBJECT_MERGE,
+ ICON_OBJECT_ROTATE_LEFT,
+ ICON_OBJECT_ROTATE_LEFT_SYMBOLIC,
+ ICON_OBJECT_ROTATE_RIGHT,
+ ICON_OBJECT_ROTATE_RIGHT_SYMBOLIC,
+ ICON_OBJECT_SELECT_SYMBOLIC,
+ ICON_OBJECT_STRAIGHTEN,
+ ICON_OBJECT_TO_PATH,
+ ICON_OBJECT_UNGROUP,
+ ICON_OBJECT_UNGROUP_SYMBOLIC,
+ ICON_OPEN_MENU,
+ ICON_OPEN_MENU_SYMBOLIC,
+ ICON_PAN_DOWN_SYMBOLIC,
+ ICON_PAN_END_SYMBOLIC,
+ ICON_PAN_START_SYMBOLIC,
+ ICON_PAN_UP_SYMBOLIC,
+ ICON_PANE_HIDE_SYMBOLIC,
+ ICON_PANE_SHOW_SYMBOLIC,
+ ICON_PATH_BREAK_APART,
+ ICON_PATH_BREAK_APART_SYMBOLIC,
+ ICON_PATH_COMBINE,
+ ICON_PATH_COMBINE_SYMBOLIC,
+ ICON_PATH_DIFFERENCE,
+ ICON_PATH_DIFFERENCE_SYMBOLIC,
+ ICON_PATH_DIVISION,
+ ICON_PATH_DIVISION_SYMBOLIC,
+ ICON_PATH_EXCLUSION,
+ ICON_PATH_EXCLUSION_SYMBOLIC,
+ ICON_PATH_INTERSECTION,
+ ICON_PATH_INTERSECTION_SYMBOLIC,
+ ICON_PATH_UNION,
+ ICON_PATH_UNION_SYMBOLIC,
+ ICON_PROCESS_STOP,
+ ICON_PROCESS_STOP_SYMBOLIC,
+ ICON_SEGMENT_CURVE,
+ ICON_SEGMENT_LINE,
+ ICON_SELECTION_ADD,
+ ICON_SELECTION_BOTTOM,
+ ICON_SELECTION_BOTTOM_SYMBOLIC,
+ ICON_SELECTION_CHECKED,
+ ICON_SELECTION_END_SYMBOLIC,
+ ICON_SELECTION_LOWER,
+ ICON_SELECTION_LOWER_SYMBOLIC,
+ ICON_SELECTION_RAISE,
+ ICON_SELECTION_RAISE_SYMBOLIC,
+ ICON_SELECTION_REMOVE,
+ ICON_SELECTION_START_SYMBOLIC,
+ ICON_SELECTION_TOP,
+ ICON_SELECTION_TOP_SYMBOLIC,
+ ICON_SEND_TO,
+ ICON_SEND_TO_SYMBOLIC,
+ ICON_STAR_NEW_SYMBOLIC,
+ ICON_STROKE_TO_PATH,
+ ICON_SYSTEM_LOCK_SCREEN,
+ ICON_SYSTEM_LOCK_SCREEN_SYMBOLIC,
+ ICON_SYSTEM_LOG_OUT,
+ ICON_SYSTEM_REBOOT,
+ ICON_SYSTEM_RUN,
+ ICON_SYSTEM_RUN_SYMBOLIC,
+ ICON_SYSTEM_SHUTDOWN,
+ ICON_SYSTEM_SHUTDOWN_SYMBOLIC,
+ ICON_SYSTEM_SUSPEND,
+ ICON_TAB_NEW_SYMBOLIC,
+ ICON_TAG_NEW,
+ ICON_TAG_NEW_SYMBOLIC,
+ ICON_TOOL_MEASURE,
+ ICON_TOOL_NODE_EDITOR,
+ ICON_TOOLS_CHECK_SPELLING_SYMBOLIC,
+ ICON_TOOLS_TIMER_SYMBOLIC,
+ ICON_VIEW_COLUMN_SYMBOLIC,
+ ICON_VIEW_CONTINUOUS_SYMBOLIC,
+ ICON_VIEW_DUAL_SYMBOLIC,
+ ICON_VIEW_FILTER_SYMBOLIC,
+ ICON_VIEW_FULLSCREEN_SYMBOLIC,
+ ICON_VIEW_GRID_SYMBOLIC,
+ ICON_VIEW_LIST_COMPACT_SYMBOLIC,
+ ICON_VIEW_LIST_IMAGES_SYMBOLIC,
+ ICON_VIEW_LIST_SYMBOLIC,
+ ICON_VIEW_LIST_VIDEO_SYMBOLIC,
+ ICON_VIEW_MORE_HORIZONTAL_SYMBOLIC,
+ ICON_VIEW_MORE_SYMBOLIC,
+ ICON_VIEW_PAGED_SYMBOLIC,
+ ICON_VIEW_PIN_SYMBOLIC,
+ ICON_VIEW_REFRESH,
+ ICON_VIEW_REFRESH_SYMBOLIC,
+ ICON_VIEW_RESTORE_SYMBOLIC,
+ ICON_VIEW_SORT_ASCENDING_SYMBOLIC,
+ ICON_VIEW_SORT_DESCENDING_SYMBOLIC,
+ ICON_WINDOW_CLOSE,
+ ICON_WINDOW_CLOSE_SYMBOLIC,
+ ICON_WINDOW_MAXIMIZE_SYMBOLIC,
+ ICON_WINDOW_MINIMIZE_SYMBOLIC,
+ ICON_WINDOW_NEW,
+ ICON_WINDOW_NEW_SYMBOLIC,
+ ICON_WINDOW_POP_OUT_SYMBOLIC,
+ ICON_WINDOW_RESTORE_SYMBOLIC,
+ ICON_ZOOM_FIT_BEST,
+ ICON_ZOOM_FIT_BEST_SYMBOLIC,
+ ICON_ZOOM_IN,
+ ICON_ZOOM_IN_SYMBOLIC,
+ ICON_ZOOM_ORIGINAL,
+ ICON_ZOOM_ORIGINAL_SYMBOLIC,
+ ICON_ZOOM_OUT,
+ ICON_ZOOM_OUT_SYMBOLIC,
+ ICON_ACCESSORIES_CALCULATOR,
+ ICON_ACCESSORIES_CALCULATOR_SYMBOLIC,
+ ICON_ACCESSORIES_SCREENSHOT,
+ ICON_ACCESSORIES_TEXT_EDITOR,
+ ICON_ACCESSORIES_TEXT_EDITOR_SYMBOLIC,
+ ICON_APPLICATION_DEFAULT_ICON,
+ ICON_ARCHIVE_MANAGER,
+ ICON_INTERNET_CHAT,
+ ICON_INTERNET_CHAT_SYMBOLIC,
+ ICON_INTERNET_MAIL,
+ ICON_INTERNET_MAIL_SYMBOLIC,
+ ICON_INTERNET_NEWS_READER,
+ ICON_INTERNET_NEWS_READER_SYMBOLIC,
+ ICON_INTERNET_WEB_BROWSER,
+ ICON_INTERNET_WEB_BROWSER_SYMBOLIC,
+ ICON_MULTIMEDIA_AUDIO_PLAYER,
+ ICON_MULTIMEDIA_PHOTO_MANAGER,
+ ICON_MULTIMEDIA_VIDEO_PLAYER,
+ ICON_OFFICE_ADDRESS_BOOK,
+ ICON_OFFICE_CALENDAR,
+ ICON_OFFICE_CALENDAR_SYMBOLIC,
+ ICON_ONBOARD,
+ ICON_POSTSCRIPT_VIEWER,
+ ICON_PREFERENCES_DESKTOP,
+ ICON_PREFERENCES_DESKTOP_FONT,
+ ICON_SYSTEM_FILE_MANAGER,
+ ICON_SYSTEM_OS_INSTALLER,
+ ICON_SYSTEM_SOFTWARE_INSTALL,
+ ICON_SYSTEM_SOFTWARE_INSTALL_SYMBOLIC,
+ ICON_SYSTEM_SOFTWARE_UPDATE,
+ ICON_SYSTEM_USERS,
+ ICON_SYSTEM_USERS_SYMBOLIC,
+ ICON_UTILITIES_SYSTEM_MONITOR,
+ ICON_UTILITIES_TERMINAL,
+ ICON_UTILITIES_TERMINAL_SYMBOLIC,
+ ICON_APPLICATIONS_ACCESSORIES,
+ ICON_APPLICATIONS_AUDIO_SYMBOLIC,
+ ICON_APPLICATIONS_DEVELOPMENT,
+ ICON_APPLICATIONS_DEVELOPMENT_SYMBOLIC,
+ ICON_APPLICATIONS_EDUCATION,
+ ICON_APPLICATIONS_EDUCATION_SYMBOLIC,
+ ICON_APPLICATIONS_ENGINEERING_SYMBOLIC,
+ ICON_APPLICATIONS_FONTS,
+ ICON_APPLICATIONS_GAMES,
+ ICON_APPLICATIONS_GAMES_SYMBOLIC,
+ ICON_APPLICATIONS_GRAPHICS,
+ ICON_APPLICATIONS_GRAPHICS_SYMBOLIC,
+ ICON_APPLICATIONS_INTERFACEDESIGN,
+ ICON_APPLICATIONS_INTERNET_SYMBOLIC,
+ ICON_APPLICATIONS_MULTIMEDIA,
+ ICON_APPLICATIONS_MULTIMEDIA_SYMBOLIC,
+ ICON_APPLICATIONS_OFFICE,
+ ICON_APPLICATIONS_OFFICE_SYMBOLIC,
+ ICON_APPLICATIONS_OTHER,
+ ICON_APPLICATIONS_OTHER_SYMBOLIC,
+ ICON_APPLICATIONS_PHOTOGRAPHY,
+ ICON_APPLICATIONS_SCIENCE,
+ ICON_APPLICATIONS_SCIENCE_SYMBOLIC,
+ ICON_APPLICATIONS_UTILITIES,
+ ICON_APPLICATIONS_UTILITIES_SYMBOLIC,
+ ICON_APPLICATIONS_VIDEO_SYMBOLIC,
+ ICON_BUG,
+ ICON_BUG_SYMBOLIC,
+ ICON_EMOJI_ACTIVITY_SYMBOLIC,
+ ICON_EMOJI_BODY_SYMBOLIC,
+ ICON_EMOJI_FOOD_SYMBOLIC,
+ ICON_EMOJI_NATURE_SYMBOLIC,
+ ICON_EMOJI_OBJECTS_SYMBOLIC,
+ ICON_EMOJI_TRAVEL_SYMBOLIC,
+ ICON_EVENT_BIRTHDAY_SYMBOLIC,
+ ICON_PREFERENCES_BLUETOOTH_SYMBOLIC,
+ ICON_PREFERENCES_COLOR,
+ ICON_PREFERENCES_COLOR_SYMBOLIC,
+ ICON_PREFERENCES_DESKTOP_ACCESSIBILITY,
+ ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_POINTING,
+ ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_SYMBOLIC,
+ ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_ZOOM,
+ ICON_PREFERENCES_DESKTOP_APPLICATIONS,
+ ICON_PREFERENCES_DESKTOP_DISPLAY,
+ ICON_PREFERENCES_DESKTOP_DISPLAY_SYMBOLIC,
+ ICON_PREFERENCES_DESKTOP_KEYBOARD,
+ ICON_PREFERENCES_DESKTOP_KEYBOARD_SYMBOLIC,
+ ICON_PREFERENCES_DESKTOP_LOCALE,
+ ICON_PREFERENCES_DESKTOP_LOCALE_SYMBOLIC,
+ ICON_PREFERENCES_DESKTOP_ONLINE_ACCOUNTS,
+ ICON_PREFERENCES_DESKTOP_ONLINE_ACCOUNTS_SYMBOLIC,
+ ICON_PREFERENCES_DESKTOP_PERIPHERALS,
+ ICON_PREFERENCES_DESKTOP_SOUND,
+ ICON_PREFERENCES_DESKTOP_WALLPAPER,
+ ICON_PREFERENCES_OTHER_SYMBOLIC,
+ ICON_PREFERENCES_SYSTEM,
+ ICON_PREFERENCES_SYSTEM_NETWORK,
+ ICON_PREFERENCES_SYSTEM_NETWORK_SYMBOLIC,
+ ICON_PREFERENCES_SYSTEM_NOTIFICATIONS,
+ ICON_PREFERENCES_SYSTEM_PARENTAL_CONTROL_SYMBOLIC,
+ ICON_PREFERENCES_SYSTEM_PARENTAL_CONTROLS,
+ ICON_PREFERENCES_SYSTEM_POWER,
+ ICON_PREFERENCES_SYSTEM_POWER_SYMBOLIC,
+ ICON_PREFERENCES_SYSTEM_PRIVACY_HOUSEKEEPING,
+ ICON_PREFERENCES_SYSTEM_SHARING,
+ ICON_PREFERENCES_SYSTEM_SHARING_SYMBOLIC,
+ ICON_PREFERENCES_SYSTEM_TIME,
+ ICON_PREFERENCES_SYSTEM_TIME_SYMBOLIC,
+ ICON_PREFERENCES_SYSTEM_WINDOWS,
+ ICON_AC_ADAPTER_SYMBOLIC,
+ ICON_AUDIO_CARD_SYMBOLIC,
+ ICON_AUDIO_HEADPHONES,
+ ICON_AUDIO_HEADPHONES_SYMBOLIC,
+ ICON_AUDIO_HEADSET_SYMBOLIC,
+ ICON_AUDIO_HEADSETS,
+ ICON_AUDIO_INPUT_MICROPHONE,
+ ICON_AUDIO_INPUT_MICROPHONE_SYMBOLIC,
+ ICON_AUDIO_SPEAKER_CENTER,
+ ICON_AUDIO_SPEAKER_CENTER_BACK,
+ ICON_AUDIO_SPEAKER_CENTER_BACK_TESTING,
+ ICON_AUDIO_SPEAKER_CENTER_TESTING,
+ ICON_AUDIO_SPEAKER_LEFT,
+ ICON_AUDIO_SPEAKER_LEFT_BACK,
+ ICON_AUDIO_SPEAKER_LEFT_BACK_TESTING,
+ ICON_AUDIO_SPEAKER_LEFT_SIDE,
+ ICON_AUDIO_SPEAKER_LEFT_SIDE_TESTING,
+ ICON_AUDIO_SPEAKER_LEFT_TESTING,
+ ICON_AUDIO_SPEAKER_RIGHT,
+ ICON_AUDIO_SPEAKER_RIGHT_BACK,
+ ICON_AUDIO_SPEAKER_RIGHT_BACK_TESTING,
+ ICON_AUDIO_SPEAKER_RIGHT_SIDE,
+ ICON_AUDIO_SPEAKER_RIGHT_SIDE_TESTING,
+ ICON_AUDIO_SPEAKER_RIGHT_TESTING,
+ ICON_AUDIO_SPEAKERS,
+ ICON_AUDIO_SPEAKERS_SYMBOLIC,
+ ICON_AUDIO_SUBWOOFER,
+ ICON_AUDIO_SUBWOOFER_TESTING,
+ ICON_BATTERY,
+ ICON_BATTERY_SYMBOLIC,
+ ICON_BLUETOOTH,
+ ICON_BLUETOOTH_SYMBOLIC,
+ ICON_CAMERA_PHOTO,
+ ICON_CAMERA_PHOTO_SYMBOLIC,
+ ICON_CAMERA_VIDEO,
+ ICON_CAMERA_VIDEO_SYMBOLIC,
+ ICON_CAMERA_WEB,
+ ICON_CAMERA_WEB_SYMBOLIC,
+ ICON_COLORIMETER_COLORHUG_SYMBOLIC,
+ ICON_COMPUTER_LAPTOP,
+ ICON_COMPUTER_LAPTOP_SYMBOLIC,
+ ICON_DISPLAY_PROJECTOR_SYMBOLIC,
+ ICON_DRIVE_HARDDISK,
+ ICON_DRIVE_HARDDISK_IEEE1394_SYMBOLIC,
+ ICON_DRIVE_HARDDISK_SOLIDSTATE,
+ ICON_DRIVE_HARDDISK_SOLIDSTATE_SYMBOLIC,
+ ICON_DRIVE_HARDDISK_SYMBOLIC,
+ ICON_DRIVE_MULTIDISK_SYMBOLIC,
+ ICON_DRIVE_OPTICAL_SYMBOLIC,
+ ICON_DRIVE_REMOVABLE_MEDIA,
+ ICON_DRIVE_REMOVABLE_MEDIA_SYMBOLIC,
+ ICON_DRIVE_REMOVABLE_MEDIA_USB,
+ ICON_FINGERPRINT,
+ ICON_FINGERPRINT_SYMBOLIC,
+ ICON_GNOME_DEV_PRINTER_NEW,
+ ICON_INPUT_DIALPAD_SYMBOLIC,
+ ICON_INPUT_GAMING,
+ ICON_INPUT_GAMING_SYMBOLIC,
+ ICON_INPUT_KEYBOARD,
+ ICON_INPUT_KEYBOARD_SYMBOLIC,
+ ICON_INPUT_MOUSE,
+ ICON_INPUT_MOUSE_SYMBOLIC,
+ ICON_INPUT_TABLET,
+ ICON_INPUT_TABLET_SYMBOLIC,
+ ICON_INPUT_TOUCHPAD,
+ ICON_INPUT_TOUCHPAD_SYMBOLIC,
+ ICON_MEDIA_FLASH_CF,
+ ICON_MEDIA_FLASH_MS,
+ ICON_MEDIA_FLASH_SYMBOLIC,
+ ICON_MEDIA_FLOPPY_SYMBOLIC,
+ ICON_MEDIA_MEMORY,
+ ICON_MEDIA_MEMORY_SD,
+ ICON_MEDIA_MEMORY_SEMBOLIC,
+ ICON_MEDIA_MEMORY_SM,
+ ICON_MEDIA_OPTICAL,
+ ICON_MEDIA_OPTICAL_SYMBOLIC,
+ ICON_MEDIA_REMOVABLE_SYMBOLIC,
+ ICON_MEDIA_TAPE_SYMBOLIC,
+ ICON_MEDIA_ZIP_SYMBOLIC,
+ ICON_MODEM,
+ ICON_MODEM_SYMBOLIC,
+ ICON_MULTIMEDIA_PLAYER,
+ ICON_MULTIMEDIA_PLAYER_SYMBOLIC,
+ ICON_NETWORK_CELLULAR,
+ ICON_NETWORK_FIREWALL,
+ ICON_NETWORK_VPN,
+ ICON_NETWORK_WIRED,
+ ICON_NETWORK_WIRELESS,
+ ICON_NETWORK_WIRELESS_HOTSPOT,
+ ICON_NM_DEVICE_WWAN,
+ ICON_PDA_SYMBOLIC,
+ ICON_PHONE,
+ ICON_PHONE_SYMBOLIC,
+ ICON_PRINTER,
+ ICON_PRINTER_NETWORK,
+ ICON_PRINTER_SYMBOLIC,
+ ICON_SCANNER,
+ ICON_SCANNER_SYMBOLIC,
+ ICON_TABLET,
+ ICON_TABLET_SYMBOLIC,
+ ICON_TV_SYMBOLIC,
+ ICON_UNINTERRUPTIBLE_POWER_SUPPLY,
+ ICON_UNINTERRUPTIBLE_POWER_SUPPLY_SYMBOLIC,
+ ICON_VIDEO_DISPLAY,
+ ICON_VIDEO_DISPLAY_SYMBOLIC,
+ ICON_EMBLEM_DEFAULT_SYMBOLIC,
+ ICON_EMBLEM_DOCUMENTS_SYMBOLIC,
+ ICON_EMBLEM_FAVORITE_SYMBOLIC,
+ ICON_EMBLEM_IMPORTANT_SYMBOLIC,
+ ICON_EMBLEM_MUSIC_SYMBOLIC,
+ ICON_EMBLEM_OK_SYMBOLIC,
+ ICON_EMBLEM_PHOTOS_SYMBOLIC,
+ ICON_EMBLEM_READONLY,
+ ICON_EMBLEM_SHARED_SYMBOLIC,
+ ICON_EMBLEM_SYMBOLIC_LINK,
+ ICON_EMBLEM_SYNCHRONIZED,
+ ICON_EMBLEM_SYNCHRONIZING_SYMBOLIC,
+ ICON_EMBLEM_UNREADABLE,
+ ICON_EMBLEM_VIDEOS_SYMBOLIC,
+ ICON_FACE_ANGEL,
+ ICON_FACE_ANGEL_SYMBOLIC,
+ ICON_FACE_ANGRY,
+ ICON_FACE_ANGRY_SYMBOLIC,
+ ICON_FACE_COOL,
+ ICON_FACE_COOL_SYMBOLIC,
+ ICON_FACE_CRYING,
+ ICON_FACE_CRYING_SYMBOLIC,
+ ICON_FACE_DEVILISH,
+ ICON_FACE_DEVILISH_SYMBOLIC,
+ ICON_FACE_EMBARRASSED,
+ ICON_FACE_EMBARRASSED_SYMBOLIC,
+ ICON_FACE_HEART,
+ ICON_FACE_HEART_BROKEN,
+ ICON_FACE_HEART_BROKEN_SYMBOLIC,
+ ICON_FACE_HEART_SYMBOLIC,
+ ICON_FACE_KISS,
+ ICON_FACE_KISS_SYMBOLIC,
+ ICON_FACE_LAUGH,
+ ICON_FACE_LAUGH_SYMBOLIC,
+ ICON_FACE_MONKEY_SYMBOLIC,
+ ICON_FACE_PLAIN,
+ ICON_FACE_PLAIN_SYMBOLIC,
+ ICON_FACE_RASPBERRY,
+ ICON_FACE_RASPBERRY_SYMBOLIC,
+ ICON_FACE_SAD,
+ ICON_FACE_SAD_SYMBOLIC,
+ ICON_FACE_SICK,
+ ICON_FACE_SICK_SYMBOLIC,
+ ICON_FACE_SMILE,
+ ICON_FACE_SMILE_BIG,
+ ICON_FACE_SMILE_BIG_SYMBOLIC,
+ ICON_FACE_SMILE_SYMBOLIC,
+ ICON_FACE_SMIRK,
+ ICON_FACE_SMIRK_SYMBOLIC,
+ ICON_FACE_SURPRISE,
+ ICON_FACE_SURPRISE_SYMBOLIC,
+ ICON_FACE_TIRED,
+ ICON_FACE_TIRED_SYMBOLIC,
+ ICON_FACE_UNCERTAIN,
+ ICON_FACE_UNCERTAIN_SYMBOLIC,
+ ICON_FACE_WINK,
+ ICON_FACE_WINK_SYMBOLIC,
+ ICON_FACE_WORRIED,
+ ICON_FACE_WORRIED_SYMBOLIC,
+ ICON_APPLICATION_CERTIFICATE_SYMBOLIC,
+ ICON_APPLICATION_EPUB_ZIP,
+ ICON_APPLICATION_ILLUSTRATOR,
+ ICON_APPLICATION_JAVASCRIPT,
+ ICON_APPLICATION_MSWORD,
+ ICON_APPLICATION_OCTET_STREAM,
+ ICON_APPLICATION_PDF,
+ ICON_APPLICATION_PGP,
+ ICON_APPLICATION_RSS_XML_SYMBOLIC,
+ ICON_APPLICATION_VND,
+ ICON_APPLICATION_X_APPLIANCE_SYMBOLIC,
+ ICON_APPLICATION_X_BITTORRENT,
+ ICON_APPLICATION_X_CD_IMAGE,
+ ICON_APPLICATION_X_DESKTOP,
+ ICON_APPLICATION_X_EXECUTABLE_SYMBOLIC,
+ ICON_APPLICATION_X_FICTIONBOOK_XML,
+ ICON_APPLICATION_X_FIRMWARE,
+ ICON_APPLICATION_X_FIRMWARE_SYMBOLIC,
+ ICON_APPLICATION_X_FLASH_VIDEO,
+ ICON_APPLICATION_X_MS_DOS_EXECUTABLE,
+ ICON_APPLICATION_X_PARTIAL_DOWNLOAD,
+ ICON_APPLICATION_X_PHP,
+ ICON_APPLICATION_X_RUBY,
+ ICON_AUDIO_X_GENERIC,
+ ICON_AUDIO_X_GENERIC_SYMBOLIC,
+ ICON_AUDIO_X_PLAYLIST,
+ ICON_EXTENSION,
+ ICON_FONT_X_GENERIC,
+ ICON_FONT_X_GENERIC_SYMBOLIC,
+ ICON_IMAGE_VND,
+ ICON_IMAGE_X_GENERIC,
+ ICON_IMAGE_X_GENERIC_SYMBOLIC,
+ ICON_IMAGE_X_XCF,
+ ICON_INTERNET_FEED,
+ ICON_MODEL,
+ ICON_OFFICE_CONTACT,
+ ICON_OFFICE_DATABASE,
+ ICON_PACKAGE_X_GENERIC,
+ ICON_PACKAGE_X_GENERIC_SYMBOLIC,
+ ICON_PAYMENT_CARD,
+ ICON_PAYMENT_CARD_AMEX,
+ ICON_PAYMENT_CARD_DINERS_CLUB,
+ ICON_PAYMENT_CARD_DISCOVER,
+ ICON_PAYMENT_CARD_JCB,
+ ICON_PAYMENT_CARD_MASTERCARD,
+ ICON_PAYMENT_CARD_SYMBOLIC,
+ ICON_PAYMENT_CARD_UNIONPAY,
+ ICON_PAYMENT_CARD_VISA,
+ ICON_TEXT,
+ ICON_TEXT_CSS,
+ ICON_TEXT_HTML,
+ ICON_TEXT_HTML_SYMBOLIC,
+ ICON_TEXT_MARKDOWN,
+ ICON_TEXT_X_BIBTEX,
+ ICON_TEXT_X_CHANGELOG,
+ ICON_TEXT_X_CHDR,
+ ICON_TEXT_X_COPYING,
+ ICON_TEXT_X_COPYING_SYMBOLIC,
+ ICON_TEXT_X_CSRC,
+ ICON_TEXT_X_GENERIC_SYMBOLIC,
+ ICON_TEXT_X_GENERIC_TEMPLATE,
+ ICON_TEXT_X_GETTEXT_TRANSLATION,
+ ICON_TEXT_X_GETTEXT_TRANSLATION_TEMPLATE,
+ ICON_TEXT_X_GO,
+ ICON_TEXT_X_INSTALL,
+ ICON_TEXT_X_MAKEFILE,
+ ICON_TEXT_X_PREVIEW,
+ ICON_TEXT_X_PYTHON,
+ ICON_TEXT_X_README,
+ ICON_TEXT_X_SASS,
+ ICON_TEXT_X_SCRIPT,
+ ICON_TEXT_X_SSA,
+ ICON_TEXT_X_TEX,
+ ICON_TEXT_X_VALA,
+ ICON_UNKNOWN,
+ ICON_VIDEO_X_GENERIC,
+ ICON_VIDEO_X_GENERIC_SYMBOLIC,
+ ICON_X_OFFICE_ADDRESS_BOOK_SYMBOLIC,
+ ICON_X_OFFICE_DOCUMENT,
+ ICON_X_OFFICE_DOCUMENT_SYMBOLIC,
+ ICON_X_OFFICE_DOCUMENT_TEMPLATE,
+ ICON_X_OFFICE_DRAWING,
+ ICON_X_OFFICE_DRAWING_SYMBOLIC,
+ ICON_X_OFFICE_DRAWING_TEMPLATE,
+ ICON_X_OFFICE_PRESENTATION,
+ ICON_X_OFFICE_PRESENTATION_SYMBOLIC,
+ ICON_X_OFFICE_PRESENTATION_TEMPLATE,
+ ICON_X_OFFICE_SPREADSHEET,
+ ICON_X_OFFICE_SPREADSHEET_SYMBOLIC,
+ ICON_X_OFFICE_SPREADSHEET_TEMPLATE,
+ ICON_BOOKMARK_MISSING,
+ ICON_DISTRIBUTOR_LOGO,
+ ICON_DISTRIBUTOR_LOGO_SYMBOLIC,
+ ICON_FOLDER,
+ ICON_FOLDER_DOCUMENTS,
+ ICON_FOLDER_DOCUMENTS_OPEN,
+ ICON_FOLDER_DOCUMENTS_SYMBOLIC,
+ ICON_FOLDER_DOWNLOAD,
+ ICON_FOLDER_DOWNLOAD_OPEN,
+ ICON_FOLDER_DOWNLOAD_SYMBOLIC,
+ ICON_FOLDER_MUSIC,
+ ICON_FOLDER_MUSIC_OPEN,
+ ICON_FOLDER_MUSIC_SYMBOLIC,
+ ICON_FOLDER_OPEN,
+ ICON_FOLDER_PICTURES,
+ ICON_FOLDER_PICTURES_OPEN,
+ ICON_FOLDER_PICTURES_SYMBOLIC,
+ ICON_FOLDER_PUBLICSHARE,
+ ICON_FOLDER_PUBLICSHARE_OPEN,
+ ICON_FOLDER_PUBLICSHARE_SYMBOLIC,
+ ICON_FOLDER_RECENT,
+ ICON_FOLDER_RECENT_SYMBOLIC,
+ ICON_FOLDER_REMOTE,
+ ICON_FOLDER_REMOTE_OPEN,
+ ICON_FOLDER_SAVED_SEARCH,
+ ICON_FOLDER_SYMBOLIC,
+ ICON_FOLDER_TAG,
+ ICON_FOLDER_TEMPLATES,
+ ICON_FOLDER_TEMPLATES_OPEN,
+ ICON_FOLDER_TEMPLATES_SYMBOLIC,
+ ICON_FOLDER_VIDEOS,
+ ICON_FOLDER_VIDEOS_OPEN,
+ ICON_FOLDER_VIDEOS_SYMBOLIC,
+ ICON_INTERNET_RADIO,
+ ICON_INTERNET_RADIO_SYMBOLIC,
+ ICON_LIBRARY_AUDIOBOOK,
+ ICON_LIBRARY_PLACES,
+ ICON_LIBRARY_PODCAST,
+ ICON_MAIL_INBOX,
+ ICON_MAIL_INBOX_SYMBOLIC,
+ ICON_MAIL_MAILBOX,
+ ICON_MAIL_MAILBOX_SYMBOLIC,
+ ICON_MAIL_OUTBOX,
+ ICON_MAIL_OUTBOX_SYMBOLIC,
+ ICON_NETWORK_SERVER_SYMBOLIC,
+ ICON_PLAYLIST,
+ ICON_PLAYLIST_AUTOMATIC,
+ ICON_PLAYLIST_QUEUE,
+ ICON_PLAYLIST_QUEUE_SYMBOLIC,
+ ICON_PLAYLIST_SIMILAR,
+ ICON_PLAYLIST_SYMBOLIC,
+ ICON_TAG_SYMBOLIC,
+ ICON_USER_BOOKMARKS_SYMBOLIC,
+ ICON_USER_HOME,
+ ICON_USER_HOME_OPEN,
+ ICON_USER_HOME_SYMBOLIC,
+ ICON_USER_TRASH,
+ ICON_USER_TRASH_FULL,
+ ICON_USER_TRASH_SYMBOLIC,
+ ICON_AIRPLANE_MODE,
+ ICON_AIRPLANE_MODE_SYMBOLIC,
+ ICON_ALARM_SYMBOLIC,
+ ICON_APPOINTMENT_MISSED,
+ ICON_APPOINTMENT_MISSED_SYMBOLIC,
+ ICON_APPOINTMENT_SOON,
+ ICON_APPOINTMENT_SOON_SYMBOLIC,
+ ICON_AUDIO_VOLUME_HIGH_SYMBOLIC,
+ ICON_AUDIO_VOLUME_LOW_SYMBOLIC,
+ ICON_AUDIO_VOLUME_MEDIUM_SYMBOLIC,
+ ICON_AUDIO_VOLUME_MUTED_BLOCKING_SYMBOLIC,
+ ICON_AUDIO_VOLUME_MUTED_SYMBOLIC,
+ ICON_AVATAR_DEFAULT,
+ ICON_AVATAR_DEFAULT_SYMBOLIC,
+ ICON_BATTERY_AC_ADAPTER,
+ ICON_BATTERY_AC_ADAPTER_SYMBOLIC,
+ ICON_BATTERY_CAUTION,
+ ICON_BATTERY_CAUTION_CHARGING,
+ ICON_BATTERY_CAUTION_CHARGING_SYMBOLIC,
+ ICON_BATTERY_CAUTION_SYMBOLIC,
+ ICON_BATTERY_EMPTY,
+ ICON_BATTERY_EMPTY_CHARGING,
+ ICON_BATTERY_EMPTY_CHARGING_SYMBOLIC,
+ ICON_BATTERY_EMPTY_SYMBOLIC,
+ ICON_BATTERY_FULL,
+ ICON_BATTERY_FULL_CHARGED,
+ ICON_BATTERY_FULL_CHARGED_SYMBOLIC,
+ ICON_BATTERY_FULL_CHARGING,
+ ICON_BATTERY_FULL_CHARGING_SYMBOLIC,
+ ICON_BATTERY_FULL_SYMBOLIC,
+ ICON_BATTERY_GOOD,
+ ICON_BATTERY_GOOD_CHARGING,
+ ICON_BATTERY_GOOD_CHARGING_SYMBOLIC,
+ ICON_BATTERY_GOOD_SYMBOLIC,
+ ICON_BATTERY_LOW,
+ ICON_BATTERY_LOW_CHARGING,
+ ICON_BATTERY_LOW_CHARGING_SYMBOLIC,
+ ICON_BATTERY_LOW_SYMBOLIC,
+ ICON_BATTERY_MISSING,
+ ICON_BATTERY_MISSING_SYMBOLIC,
+ ICON_BLUETOOTH_ACTIVE_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED,
+ ICON_BLUETOOTH_DISABLED_10_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_20_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_30_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_40_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_50_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_60_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_70_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_80_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_90_SYMBOLIC,
+ ICON_BLUETOOTH_DISABLED_SYMBOLIC,
+ ICON_BLUETOOTH_PAIRED_SYMBOLIC,
+ ICON_CALL_MISSED_SYMBOLIC,
+ ICON_CHANGES_ALLOW,
+ ICON_CHANGES_ALLOW_SYMBOLIC,
+ ICON_CHANGES_PREVENT_SYMBOLIC,
+ ICON_CHANNEL_INSECURE_SYMBOLIC,
+ ICON_CHANNEL_SECURE_SYMBOLIC,
+ ICON_CHECK_ACTIVE_SYMBOLIC,
+ ICON_CHECK_MIXED_SYMBOLIC,
+ ICON_CHECKBOX_CHECKED_SYMBOLIC,
+ ICON_CHECKBOX_MIXED_SYMBOLIC,
+ ICON_CHECKBOX_SYMBOLIC,
+ ICON_COMPUTER_FAIL_SYMBOLIC,
+ ICON_CONTENT_LOADING_SYMBOLIC,
+ ICON_DAYTIME_SUNRISE_SYMBOLIC,
+ ICON_DAYTIME_SUNSET_SYMBOLIC,
+ ICON_DIALOG_ERROR,
+ ICON_DIALOG_ERROR_SYMBOLIC,
+ ICON_DIALOG_INFORMATION,
+ ICON_DIALOG_INFORMATION_SYMBOLIC,
+ ICON_DIALOG_PASSWORD,
+ ICON_DIALOG_PASSWORD_SYMBOLIC,
+ ICON_DIALOG_WARNING,
+ ICON_DIALOG_WARNING_SYMBOLIC,
+ ICON_DISPLAY_BRIGHTNESS_SYMBOLIC,
+ ICON_FOLDER_OPEN_SYMBOLIC,
+ ICON_FOLDER_VISITING_SYMBOLIC,
+ ICON_IMAGE_LOADING,
+ ICON_IMAGE_MISSING,
+ ICON_INPUT_KEYBOARD_CAPSLOCK_SYMBOLIC,
+ ICON_INPUT_KEYBOARD_NUMLOCK_SYMBOLIC,
+ ICON_KEYBOARD_BRIGHTNESS_SYMBOLIC,
+ ICON_LOCATION_ACTIVE_SYMBOLIC,
+ ICON_LOCATION_DISABLED_SYMBOLIC,
+ ICON_LOCATION_INACTIVE_SYMBOLIC,
+ ICON_LOCKED,
+ ICON_MAIL_ATTACHMENT_SYMBOLIC,
+ ICON_MAIL_FORWARDED_SYMBOLIC,
+ ICON_MAIL_IMPORTANT_SYMBOLIC,
+ ICON_MAIL_READ_SYMBOLIC,
+ ICON_MAIL_REPLIED_SYMBOLIC,
+ ICON_MAIL_UNREAD,
+ ICON_MAIL_UNREAD_SYMBOLIC,
+ ICON_MEDIA_PLAYLIST_CONSECUTIVE_SYMBOLIC,
+ ICON_MEDIA_PLAYLIST_NO_REPEAT_SYMBOLIC,
+ ICON_MEDIA_PLAYLIST_REPEAT,
+ ICON_MEDIA_PLAYLIST_REPEAT_SONG_SYMBOLIC,
+ ICON_MEDIA_PLAYLIST_REPEAT_SYMBOLIC,
+ ICON_MEDIA_PLAYLIST_SHUFFLE_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_HIGH_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_LOW_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MEDIUM_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_10_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_20_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_30_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_40_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_50_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_60_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_70_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_80_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_90_SYMBOLIC,
+ ICON_MICROPHONE_SENSITIVITY_MUTED_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_ACQUIRING_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_CONNECTED_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_NO_ROUTE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_OFFLINE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_EXCELLENT_SECURE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_EXCELLENT_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_GOOD_SECURE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_GOOD_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_NONE_SECURE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_NONE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_OK_SECURE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_OK_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_WEAK_SECURE_SYMBOLIC,
+ ICON_NETWORK_CELLULAR_SIGNAL_WEAK_SYMBOLIC,
+ ICON_NETWORK_ERROR,
+ ICON_NETWORK_ERROR_SYMBOLIC,
+ ICON_NETWORK_IDLE,
+ ICON_NETWORK_OFFLINE_SYMBOLIC,
+ ICON_NETWORK_VPN_ACQUIRING_SYMBOLIC,
+ ICON_NETWORK_VPN_LOCK_SYMBOLIC,
+ ICON_NETWORK_VPN_SYMBOLIC,
+ ICON_NETWORK_WIRED_ACQUIRING_SYMBOLIC,
+ ICON_NETWORK_WIRED_DISCONNECTED,
+ ICON_NETWORK_WIRED_NO_ROUTE_SYMBOLIC,
+ ICON_NETWORK_WIRED_OFFLINE_SYMBOLIC,
+ ICON_NETWORK_WIRED_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_ACQUIRING_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_CONNECTED_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_ENCRYPTED_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_HOTSPOT_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_NO_ROUTE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_OFFLINE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT_SECURE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_GOOD_SECURE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_GOOD_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_NONE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_OK_SECURE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_OK_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_WEAK_SECURE_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SIGNAL_WEAK_SYMBOLIC,
+ ICON_NETWORK_WIRELESS_SYMBOLIC,
+ ICON_NIGHT_LIGHT,
+ ICON_NIGHT_LIGHT_DISABLED_10_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_20_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_30_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_40_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_50_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_60_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_70_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_80_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_90_SYMBOLIC,
+ ICON_NIGHT_LIGHT_DISABLED_SYMBOLIC,
+ ICON_NIGHT_LIGHT_SYMBOLIC,
+ ICON_NM_NO_CONNECTION,
+ ICON_NM_SIGNAL_0,
+ ICON_NM_SIGNAL_0_SECURE,
+ ICON_NM_SIGNAL_100,
+ ICON_NM_SIGNAL_100_SECURE,
+ ICON_NM_SIGNAL_25,
+ ICON_NM_SIGNAL_25_SECURE,
+ ICON_NM_SIGNAL_50,
+ ICON_NM_SIGNAL_50_SECURE,
+ ICON_NM_SIGNAL_75,
+ ICON_NM_SIGNAL_75_SECURE,
+ ICON_NM_VPN_ACTIVE_LOCK,
+ ICON_NM_VPN_LOCK,
+ ICON_NON_STARRED,
+ ICON_NON_STARRED_SYMBOLIC,
+ ICON_NOTIFICATION_AUDIO_VOLUME_HIGH,
+ ICON_NOTIFICATION_AUDIO_VOLUME_LOW,
+ ICON_NOTIFICATION_AUDIO_VOLUME_MEDIUM,
+ ICON_NOTIFICATION_AUDIO_VOLUME_MUTED,
+ ICON_NOTIFICATION_DEVICE_EJECT,
+ ICON_NOTIFICATION_DISABLED,
+ ICON_NOTIFICATION_DISABLED_10_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_20_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_30_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_40_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_50_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_60_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_70_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_80_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_90_SYMBOLIC,
+ ICON_NOTIFICATION_DISABLED_SYMBOLIC,
+ ICON_NOTIFICATION_DISPLAY_BRIGHTNESS,
+ ICON_NOTIFICATION_KEYBOARD_BRIGHTNESS,
+ ICON_NOTIFICATION_NETWORK_ETHERNET_DISCONNECTED,
+ ICON_NOTIFICATION_NETWORK_WIRED,
+ ICON_NOTIFICATION_NETWORK_WIRELESS,
+ ICON_NOTIFICATION_NETWORK_WIRELESS_DISCONNECTED,
+ ICON_NOTIFICATION_NETWORK_WIRELESS_DISCONNECTED_SYMBOLIC,
+ ICON_NOTIFICATION_NETWORK_WIRELESS_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_10_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_20_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_30_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_40_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_50_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_60_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_70_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_80_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_90_SYMBOLIC,
+ ICON_NOTIFICATION_NEW_SYMBOLIC,
+ ICON_NOTIFICATION_SYMBOLIC,
+ ICON_PAGER_CHECKED_SYMBOLIC,
+ ICON_PRINTER_ERROR,
+ ICON_PRINTER_ERROR_SYMBOLIC,
+ ICON_PRINTER_PRINTING_SYMBOLIC,
+ ICON_PRINTER_WARNING_SYMBOLIC,
+ ICON_PROCESS_COMPLETED,
+ ICON_PROCESS_COMPLETED_SYMBOLIC,
+ ICON_PROCESS_ERROR_SYMBOLIC,
+ ICON_PROCESS_WORKING_SYMBOLIC,
+ ICON_RADIO_CHECKED_SYMBOLIC,
+ ICON_RADIO_MIXED_SYMBOLIC,
+ ICON_RADIO_SYMBOLIC,
+ ICON_ROTATION_ALLOWED_SYMBOLIC,
+ ICON_ROTATION_LOCKED_SYMBOLIC,
+ ICON_SECURITY_HIGH,
+ ICON_SECURITY_HIGH_SYMBOLIC,
+ ICON_SECURITY_LOW,
+ ICON_SECURITY_LOW_SYMBOLIC,
+ ICON_SECURITY_MEDIUM,
+ ICON_SECURITY_MEDIUM_SYMBOLIC,
+ ICON_SEMI_STARRED,
+ ICON_SEMI_STARRED_SYMBOLIC,
+ ICON_SOFTWARE_UPDATE_AVAILABLE_SYMBOLIC,
+ ICON_SOFTWARE_UPDATE_URGENT_SYMBOLIC,
+ ICON_STARRED,
+ ICON_STARRED_SYMBOLIC,
+ ICON_TASK_DUE_SYMBOLIC,
+ ICON_TASK_PAST_DUE_SYMBOLIC,
+ ICON_TOUCHPAD_DISABLED_SYMBOLIC,
+ ICON_USER_AVAILABLE,
+ ICON_USER_AVAILABLE_SYMBOLIC,
+ ICON_USER_AWAY,
+ ICON_USER_AWAY_SYMBOLIC,
+ ICON_USER_BUSY,
+ ICON_USER_BUSY_SYMBOLIC,
+ ICON_USER_IDLE_SYMBOLIC,
+ ICON_USER_INVISIBLE,
+ ICON_USER_INVISIBLE_SYMBOLIC,
+ ICON_USER_OFFLINE,
+ ICON_USER_OFFLINE_SYMBOLIC,
+ ICON_USER_STATUS_PENDING_SYMBOLIC,
+ ICON_USER_TRASH_FULL_SYMBOLIC,
+ ICON_USER_TYPING,
+ ICON_VIEW_PRIVATE,
+ ICON_VIEW_PRIVATE_SYMBOLIC,
+ ICON_VIEW_WRAPPED_SYMBOLIC,
+ ICON_WEATHER_CLEAR_NIGHT_SYMBOLIC,
+ ICON_WEATHER_CLEAR_SYMBOLIC,
+ ICON_WEATHER_FEW_CLOUDS_NIGHT_SYMBOLIC,
+ ICON_WEATHER_FEW_CLOUDS_SYMBOLIC,
+ ICON_WEATHER_FOG_NIGHT_SYMBOLIC,
+ ICON_WEATHER_FOG_SYMBOLIC,
+ ICON_WEATHER_OVERCAST_NIGHT_SYMBOLIC,
+ ICON_WEATHER_OVERCAST_SYMBOLIC,
+ ICON_WEATHER_SEVERE_ALERT_SYMBOLIC,
+ ICON_WEATHER_SHOWERS_NIGHT_SYMBOLIC,
+ ICON_WEATHER_SHOWERS_SCATTERED_NIGHT_SYMBOLIC,
+ ICON_WEATHER_SHOWERS_SCATTERED_SYMBOLIC,
+ ICON_WEATHER_SHOWERS_SYMBOLIC,
+ ICON_WEATHER_SNOW_NIGHT_SYMBOLIC,
+ ICON_WEATHER_SNOW_SYMBOLIC,
+ ICON_WEATHER_STORM_NIGHT_SYMBOLIC,
+ ICON_WEATHER_STORM_SYMBOLIC,
+ ICON_WEATHER_STORM_TORNADO_NIGHT_SYMBOLIC,
+ ICON_WEATHER_STORM_TORNADO_SYMBOLIC,
+ ICON_WEATHER_WINDY_SYMBOLIC,
+}
-OS :: "essence";
+FatalError :: enum {
+ FATAL_ERROR_INVALID_BUFFER,
+ FATAL_ERROR_UNKNOWN_SYSCALL,
+ FATAL_ERROR_INVALID_MEMORY_REGION,
+ FATAL_ERROR_MEMORY_REGION_LOCKED_BY_KERNEL,
+ FATAL_ERROR_PATH_LENGTH_EXCEEDS_LIMIT,
+ FATAL_ERROR_INVALID_HANDLE,
+ FATAL_ERROR_MUTEX_NOT_ACQUIRED_BY_THREAD,
+ FATAL_ERROR_MUTEX_ALREADY_ACQUIRED,
+ FATAL_ERROR_BUFFER_NOT_ACCESSIBLE,
+ FATAL_ERROR_SHARED_MEMORY_REGION_TOO_LARGE,
+ FATAL_ERROR_SHARED_MEMORY_STILL_MAPPED,
+ FATAL_ERROR_COULD_NOT_LOAD_FONT,
+ FATAL_ERROR_COULD_NOT_DRAW_FONT,
+ FATAL_ERROR_COULD_NOT_ALLOCATE_MEMORY,
+ FATAL_ERROR_INCORRECT_FILE_ACCESS,
+ FATAL_ERROR_TOO_MANY_WAIT_OBJECTS,
+ FATAL_ERROR_INCORRECT_NODE_TYPE,
+ FATAL_ERROR_PROCESSOR_EXCEPTION,
+ FATAL_ERROR_UNKNOWN,
+ FATAL_ERROR_RECURSIVE_BATCH,
+ FATAL_ERROR_CORRUPT_HEAP,
+ FATAL_ERROR_CORRUPT_LINKED_LIST,
+ FATAL_ERROR_INDEX_OUT_OF_BOUNDS,
+ FATAL_ERROR_INVALID_STRING_LENGTH,
+ FATAL_ERROR_SPINLOCK_NOT_ACQUIRED,
+ FATAL_ERROR_UNKNOWN_SNAPSHOT_TYPE,
+ FATAL_ERROR_PROCESS_ALREADY_ATTACHED,
+ FATAL_ERROR_INTERNAL,
+ FATAL_ERROR_INSUFFICIENT_PERMISSIONS,
+ FATAL_ERROR_ABORT,
+ FATAL_ERROR_COUNT,
+}
-foreign import api "system:api"
+SyscallType :: enum {
+ SYSCALL_ALLOCATE,
+ SYSCALL_FREE,
+ SYSCALL_SHARE_MEMORY,
+ SYSCALL_MAP_OBJECT,
+ SYSCALL_OPEN_SHARED_MEMORY,
+ SYSCALL_CREATE_PROCESS,
+ SYSCALL_GET_CREATION_ARGUMENT,
+ SYSCALL_TERMINATE_THREAD,
+ SYSCALL_CREATE_THREAD,
+ SYSCALL_WAIT,
+ SYSCALL_TERMINATE_PROCESS,
+ SYSCALL_CREATE_EVENT,
+ SYSCALL_SET_EVENT,
+ SYSCALL_RESET_EVENT,
+ SYSCALL_POLL_EVENT,
+ SYSCALL_PAUSE_PROCESS,
+ SYSCALL_CRASH_PROCESS,
+ SYSCALL_GET_THREAD_ID,
+ SYSCALL_GET_PROCESS_STATE,
+ SYSCALL_YIELD_SCHEDULER,
+ SYSCALL_SLEEP,
+ SYSCALL_OPEN_PROCESS,
+ SYSCALL_SET_TLS,
+ SYSCALL_TIMER_SET,
+ SYSCALL_TIMER_CREATE,
+ SYSCALL_GET_PROCESS_STATUS,
+ SYSCALL_CREATE_SURFACE,
+ SYSCALL_GET_LINEAR_BUFFER,
+ SYSCALL_INVALIDATE_RECTANGLE,
+ SYSCALL_COPY_TO_SCREEN,
+ SYSCALL_FORCE_SCREEN_UPDATE,
+ SYSCALL_FILL_RECTANGLE,
+ SYSCALL_COPY_SURFACE,
+ SYSCALL_CLEAR_MODIFIED_REGION,
+ SYSCALL_DRAW_SURFACE,
+ SYSCALL_REDRAW_ALL,
+ SYSCALL_DRAW_BOX,
+ SYSCALL_DRAW_BITMAP,
+ SYSCALL_SURFACE_RESET,
+ SYSCALL_SURFACE_SHARE,
+ SYSCALL_DRAW_STYLED_BOX,
+ SYSCALL_SURFACE_SCROLL,
+ SYSCALL_RESIZE_SURFACE,
+ SYSCALL_GET_MESSAGE,
+ SYSCALL_POST_MESSAGE,
+ SYSCALL_POST_MESSAGE_REMOTE,
+ SYSCALL_WAIT_MESSAGE,
+ SYSCALL_CREATE_WINDOW,
+ SYSCALL_UPDATE_WINDOW,
+ SYSCALL_SET_CURSOR_STYLE,
+ SYSCALL_MOVE_WINDOW,
+ SYSCALL_GET_WINDOW_BOUNDS,
+ SYSCALL_RESET_CLICK_CHAIN,
+ SYSCALL_GET_CURSOR_POSITION,
+ SYSCALL_SET_CURSOR_POSITION,
+ SYSCALL_COPY,
+ SYSCALL_GET_CLIPBOARD_HEADER,
+ SYSCALL_PASTE_TEXT,
+ SYSCALL_SET_FOCUSED_WINDOW,
+ SYSCALL_SET_WINDOW_TITLE,
+ SYSCALL_GET_SCREEN_BOUNDS,
+ SYSCALL_WINDOW_OPEN,
+ SYSCALL_WINDOW_SET_BLEND_BOUNDS,
+ SYSCALL_WINDOW_GET_BLEND_BOUNDS,
+ SYSCALL_WINDOW_GET_ID,
+ SYSCALL_SET_WINDOW_ALPHA,
+ SYSCALL_DOCKED_WINDOW_CREATE,
+ SYSCALL_WINDOW_SHARE,
+ SYSCALL_SET_EMBED_WINDOW,
+ SYSCALL_OPEN_NODE,
+ SYSCALL_READ_FILE_SYNC,
+ SYSCALL_WRITE_FILE_SYNC,
+ SYSCALL_RESIZE_FILE,
+ SYSCALL_REFRESH_NODE_INFORMATION,
+ SYSCALL_ENUMERATE_DIRECTORY_CHILDREN,
+ SYSCALL_DELETE_NODE,
+ SYSCALL_MOVE_NODE,
+ SYSCALL_READ_CONSTANT_BUFFER,
+ SYSCALL_SHARE_CONSTANT_BUFFER,
+ SYSCALL_CREATE_CONSTANT_BUFFER,
+ SYSCALL_EXECUTE,
+ SYSCALL_INSTANCE_CREATE_REMOTE,
+ SYSCALL_MAILSLOT_SEND_DATA,
+ SYSCALL_MAILSLOT_SEND_MESSAGE,
+ SYSCALL_MAILSLOT_SHARE,
+ SYSCALL_PIPE_CREATE,
+ SYSCALL_PIPE_WRITE,
+ SYSCALL_PIPE_READ,
+ SYSCALL_USER_GET_HOME_FOLDER,
+ SYSCALL_USER_LOGIN,
+ SYSCALL_GET_SYSTEM_CONSTANTS,
+ SYSCALL_TAKE_SYSTEM_SNAPSHOT,
+ SYSCALL_SET_SYSTEM_CONSTANT,
+ SYSCALL_GET_SYSTEM_INFORMATION,
+ SYSCALL_PRINT,
+ SYSCALL_CLOSE_HANDLE,
+ SYSCALL_BATCH,
+ SYSCALL_SHUTDOWN,
+ SYSCALL_POSIX,
+ SYSCALL_COUNT,
+}
-Handle :: distinct int;
-Errno :: distinct int;
+StandardFont :: enum {
+ STANDARD_FONT_REGULAR,
+ STANDARD_FONT_BOLD,
+ STANDARD_FONT_MONOSPACED,
+}
-O_RDONLY :: 0x00001;
-O_WRONLY :: 0x00002;
-O_RDWR :: 0x00003;
-O_CREATE :: 0x00040;
-O_EXCL :: 0x00080;
-O_TRUNC :: 0x00200;
-O_APPEND :: 0x00400;
+MessageType :: enum {
+ MESSAGE_WM_START = 0x1000,
+ MESSAGE_MOUSE_MOVED = 0x1001,
+ MESSAGE_WINDOW_ACTIVATED = 0x1003,
+ MESSAGE_WINDOW_DEACTIVATED = 0x1004,
+ MESSAGE_WINDOW_DESTROYED = 0x1005,
+ MESSAGE_MOUSE_EXIT = 0x1006 ,
+ MESSAGE_CLICK_REPEAT = 0x1009,
+ MESSAGE_WINDOW_RESIZED = 0x100B,
+ MESSAGE_MOUSE_LEFT_PRESSED = 0x100C ,
+ MESSAGE_MOUSE_LEFT_RELEASED = 0x100D,
+ MESSAGE_MOUSE_RIGHT_PRESSED = 0x100E,
+ MESSAGE_MOUSE_RIGHT_RELEASED = 0x100F,
+ MESSAGE_MOUSE_MIDDLE_PRESSED = 0x1010,
+ MESSAGE_MOUSE_MIDDLE_RELEASED = 0x1011 ,
+ MESSAGE_KEY_PRESSED = 0x1012,
+ MESSAGE_KEY_RELEASED = 0x1013,
+ MESSAGE_UPDATE_WINDOW = 0x1014,
+ MESSAGE_WM_END = 0x13FF,
+ MESSAGE_PAINT = 0x2000 ,
+ MESSAGE_DESTROY = 0x2001 ,
+ MESSAGE_MEASURE = 0x2002 ,
+ MESSAGE_SIZE = 0x2003 ,
+ MESSAGE_ADD_CHILD = 0x2004 ,
+ MESSAGE_REMOVE_CHILD = 0x2005 ,
+ MESSAGE_HIT_TEST = 0x2006 ,
+ MESSAGE_HOVERED_START = 0x2007 ,
+ MESSAGE_HOVERED_END = 0x2008 ,
+ MESSAGE_PRESSED_START = 0x2009 ,
+ MESSAGE_PRESSED_END = 0x200A ,
+ MESSAGE_FOCUSED_START = 0x200B ,
+ MESSAGE_FOCUSED_END = 0x200C ,
+ MESSAGE_FOCUS_WITHIN_START = 0x200D ,
+ MESSAGE_FOCUS_WITHIN_END = 0x200E ,
+ MESSAGE_Z_ORDER = 0x2010 ,
+ MESSAGE_ANIMATE = 0x2011 ,
+ MESSAGE_MOUSE_DRAGGED = 0x2012 ,
+ MESSAGE_KEY_TYPED = 0x2013 ,
+ MESSAGE_PAINT_BACKGROUND = 0x2014 ,
+ MESSAGE_PAINT_FOREGROUND = 0x2015 ,
+ MESSAGE_ENSURE_VISIBLE = 0x2016 ,
+ MESSAGE_GET_CURSOR = 0x2017 ,
+ MESSAGE_WINDOW_CREATED = 0x2018 ,
+ MESSAGE_CLICKED = 0x3000 ,
+ MESSAGE_SCROLLBAR_MOVED = 0x3001 ,
+ MESSAGE_RECALCULATE_CONTENT_SIZE = 0x3002 ,
+ MESSAGE_TEXTBOX_UPDATED = 0x3003 ,
+ MESSAGE_DESKTOP_EXECUTE = 0x4800,
+ MESSAGE_POWER_BUTTON_PRESSED = 0x4801,
+ MESSAGE_TASKBAR_WINDOW_ADD = 0x4804,
+ MESSAGE_TASKBAR_WINDOW_REMOVE = 0x4805,
+ MESSAGE_TASKBAR_WINDOW_ACTIVATE = 0x4806,
+ MESSAGE_TASKBAR_WINDOW_SET_TITLE = 0x4807,
+ MESSAGE_DOCKED_WINDOW_CREATE = 0x4808,
+ MESSAGE_PROGRAM_CRASH = 0x4C00,
+ MESSAGE_PROGRAM_FAILED_TO_START = 0x4C01,
+ MESSAGE_RECEIVE_DATA = 0x5100,
+ MESSAGE_MAILSLOT_CLOSED = 0x5101,
+ MESSAGE_CLIPBOARD_UPDATED = 0x5001,
+ MESSAGE_SYSTEM_CONSTANT_UPDATED = 0x5004,
+ MESSAGE_TIMER = 0x5006,
+ MESSAGE_OBJECT_DESTROY = 0x5007,
+ MESSAGE_LIST_VIEW_GET_ITEM_CONTENT = 0x6000,
+ MESSAGE_LIST_VIEW_SET_ITEM_STATE = 0x6001,
+ MESSAGE_LIST_VIEW_GET_ITEM_STATE = 0x6002,
+ MESSAGE_LIST_VIEW_PAINT_ITEM = 0x6003 ,
+ MESSAGE_LIST_VIEW_PAINT_CELL = 0x6004 ,
+ MESSAGE_LIST_VIEW_SORT_COLUMN = 0x6005,
+ MESSAGE_LIST_VIEW_CHOOSE_ITEM = 0x6006,
+ MESSAGE_LIST_VIEW_FIND_ITEM = 0x6007,
+ MESSAGE_LIST_VIEW_TOGGLE_DISCLOSURE = 0x6008,
+ MESSAGE_LIST_VIEW_MEASURE_ITEM_HEIGHT = 0x6009,
+ MESSAGE_LIST_VIEW_LAYOUT_ITEM = 0x600A,
+ MESSAGE_LIST_VIEW_SET_ITEM_VISIBILITY = 0x600B,
+ MESSAGE_LIST_VIEW_RELAY_MESSAGE = 0x600C,
+ MESSAGE_LIST_VIEW_SET_ITEM_POSITION = 0x600D,
+ MESSAGE_PROGRAM_START = 0x7000,
+ MESSAGE_PROGRAM_EXIT = 0x7001,
+ MESSAGE_USER_START = 0x8000,
+ MESSAGE_USER_END = 0xBFFF,
+}
-ERROR_NONE :: Errno(-1);
-ERROR_UNKNOWN_OPERATION_FAILURE :: Errno(-7);
-ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: Errno(-14);
-ERROR_PATH_NOT_FOUND :: Errno(-15);
-ERROR_FILE_EXISTS :: Errno(-19);
-ERROR_FILE_NOT_FOUND :: Errno(-20);
-ERROR_DRIVE_ERROR_FILE_DAMAGED :: Errno(-21);
-ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: Errno(-22);
-ERROR_ACCESS_DENIED :: Errno(-23);
-ERROR_FILE_IN_EXCLUSIVE_USE :: Errno(-24);
-ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: Errno(-25);
-ERROR_INCORRECT_NODE_TYPE :: Errno(-26);
-ERROR_EVENT_NOT_SET :: Errno(-27);
-ERROR_TIMEOUT_REACHED :: Errno(-29);
-ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: Errno(-30);
-ERROR_NO_CHARACTER_AT_COORDINATE :: Errno(-31);
-ERROR_FILE_ON_READ_ONLY_VOLUME :: Errno(-32);
-ERROR_USER_CANCELED_IO :: Errno(-33);
-ERROR_DRIVE_CONTROLLER_REPORTED :: Errno(-35);
-ERROR_COULD_NOT_ISSUE_PACKET :: Errno(-36);
-
-ERROR_NOT_IMPLEMENTED :: Errno(1);
-
-OS_Node_Type :: enum i32 {
- File = 0,
- Directory = 1,
-}
-
-OS_Node_Information :: struct {
- handle: Handle,
- id: [16]byte,
- ntype: OS_Node_Type,
- size: i64,
-
- // Our additions..
- position: i64,
-}
-
-foreign api {
- @(link_name="OSPrintDirect") OSPrintDirect :: proc(str: ^u8, length: int) ---;
- @(link_name="malloc") OSMalloc :: proc(bytes: int) -> rawptr ---;
- @(link_name="free") OSFree :: proc(address: rawptr) ---;
- @(link_name="OSOpenNode") OSOpenNode :: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
- @(link_name="OSResizeFile") OSResizeFile :: proc(handle: Handle, new_size: u64) -> Errno ---;
- @(link_name="OSCloseHandle") OSCloseHandle :: proc(handle: Handle) ---;
- @(link_name="OSWriteFileSync") OSWriteFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
- @(link_name="OSReadFileSync") OSReadFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
- @(link_name="realloc") OSRealloc :: proc(address: rawptr, size: int) -> rawptr ---;
- @(link_name="OSGetThreadID") OSGetThreadID :: proc(handle: Handle) -> int ---;
- @(link_name="OSRefreshNodeInformation") OSRefreshNodeInformation :: proc(information: ^OS_Node_Information) ---;
-}
-
-stdin := Handle(-1); // Not implemented
-stdout := Handle(0);
-stderr := Handle(0);
-
-is_path_separator :: proc(r: rune) -> bool {
- return r == '/';
+DrawMode :: enum {
+ DRAW_MODE_REPEAT_FIRST = 1 ,
+ DRAW_MODE_STRECH,
+ DRAW_MODE_REPEAT,
+ DRAW_MODE_NONE,
}
-current_thread_id :: proc "contextless" () -> int {
- return OSGetThreadID(Handle(0x1000));
+ClipboardFormat :: enum {
+ CLIPBOARD_FORMAT_EMPTY,
+ CLIPBOARD_FORMAT_TEXT,
+ CLIPBOARD_FORMAT_FILE_LIST,
}
-heap_alloc :: proc(size: int) -> rawptr {
- return OSMalloc(size);
+ColorFormat :: enum {
+ COLOR_FORMAT_32_XRGB,
}
-heap_free :: proc(address: rawptr) {
- OSFree(address);
+CursorStyle :: enum {
+ CURSOR_NORMAL,
+ CURSOR_TEXT,
+ CURSOR_RESIZE_VERTICAL,
+ CURSOR_RESIZE_HORIZONTAL,
+ CURSOR_RESIZE_DIAGONAL_1,
+ CURSOR_RESIZE_DIAGONAL_2,
+ CURSOR_SPLIT_VERTICAL,
+ CURSOR_SPLIT_HORIZONTAL,
+ CURSOR_HAND_HOVER,
+ CURSOR_HAND_DRAG,
+ CURSOR_HAND_POINT,
+ CURSOR_SCROLL_UP_LEFT,
+ CURSOR_SCROLL_UP,
+ CURSOR_SCROLL_UP_RIGHT,
+ CURSOR_SCROLL_LEFT,
+ CURSOR_SCROLL_CENTER,
+ CURSOR_SCROLL_RIGHT,
+ CURSOR_SCROLL_DOWN_LEFT,
+ CURSOR_SCROLL_DOWN,
+ CURSOR_SCROLL_DOWN_RIGHT,
+ CURSOR_SELECT_LINES,
+ CURSOR_DROP_TEXT,
+ CURSOR_CROSS_HAIR_PICK,
+ CURSOR_CROSS_HAIR_RESIZE,
+ CURSOR_MOVE_HOVER,
+ CURSOR_MOVE_DRAG,
+ CURSOR_ROTATE_HOVER,
+ CURSOR_ROTATE_DRAG,
+ CURSOR_BLANK,
}
-heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
- return OSRealloc(address, new_size);
+WindowStyle :: enum {
+ WINDOW_NORMAL,
+ WINDOW_CONTAINER,
+ WINDOW_MENU,
}
-open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
- flags : u64 = 0;
+NODE_FILE :: (0);
+NODE_DIRECTORY :: (0x4000);
+NODE_INVALID :: (0x8000);
+BatchCall :: struct {
+ index :SyscallType,
+ stopBatchIfError :bool,
+ using _ : struct #raw_union {
+ argument0 :uintptr,
+ returnValue :uintptr,
+ },
- if mode & O_CREATE == O_CREATE {
- flags = flags | 0x9000; // Fail if found and create directories leading to the file if they don't exist
- } else {
- flags = flags | 0x2000; // Fail if not found
- }
+ argument1 :uintptr,
+ argument2 :uintptr,
+ argument3 :uintptr,
+}
- if mode & O_EXCL == O_EXCL {
- flags = flags | 0x111; // Block opening the node for any reason
- }
+ThreadInformation :: struct {
+ handle :Handle,
+ tid :uintptr,
+}
- if mode & O_RDONLY == O_RDONLY {
- flags = flags | 0x2; // Read access
- }
+ProcessInformation :: struct {
+ handle :Handle,
+ pid :uintptr,
+ mainThread :ThreadInformation,
+}
- if mode & O_WRONLY == O_WRONLY {
- flags = flags | 0x220; // Write and resize access
- }
+UniqueIdentifier :: struct {
+ using _ : struct #raw_union {
+ d :[16]u8,
+ },
- if mode & O_TRUNC == O_TRUNC {
- flags = flags | 0x200; // Resize access
- }
+}
- information := new(OS_Node_Information);
- error := OSOpenNode(&path[0], len(path), flags, information);
+NodeInformation :: struct {
+ handle :Handle,
+ type :NodeType,
+ fileSize :FileOffset,
+ directoryChildren :FileOffset,
+}
- if error < ERROR_NONE {
- free(information);
- return 0, error;
- }
+DirectoryChild :: struct {
+ name :[MAX_DIRECTORY_CHILD_NAME_LENGTH]i8,
+ nameBytes :uintptr,
+ information :NodeInformation,
+}
- if mode & O_TRUNC == O_TRUNC {
- error := OSResizeFile(information.handle, 0);
- if error < ERROR_NONE do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
- }
+Point :: struct {
+ x :i32,
+ y :i32,
+}
- if mode & O_APPEND == O_APPEND {
- information.position = information.size;
- } else {
- information.position = 0;
- }
+Rectangle :: struct {
+ left :i32,
+ right :i32,
+ top :i32,
+ bottom :i32,
+}
- return Handle(uintptr(information)), ERROR_NONE;
+Rectangle16 :: struct {
+ left :i16,
+ right :i16,
+ top :i16,
+ bottom :i16,
}
-close :: proc(fd: Handle) {
- information := (^OS_Node_Information)(uintptr(fd));
- OSCloseHandle(information.handle);
- free(information);
+Color :: struct {
+ using _ : struct #raw_union {
+ using _ : struct {
+ blue :u8,
+ green :u8,
+ red :u8,
+ },
+
+ combined :u32,
+ },
+
}
-file_size :: proc(fd: Handle) -> (i64, Errno) {
- x: OS_Node_Information;
- OSRefreshNodeInformation(&x);
- return x.size, ERROR_NONE;
+LinearBuffer :: struct {
+ width :uintptr,
+ height :uintptr,
+ stride :uintptr,
+ colorFormat :ColorFormat,
+ handle :Handle,
}
-write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
- if fd == 0 {
- OSPrintDirect(&data[0], len(data));
- return len(data), ERROR_NONE;
- } else if fd == 1 {
- assert(false);
- return 0, ERROR_NOT_IMPLEMENTED;
- }
+RectangleAndColor :: struct {
+ rectangle :Rectangle,
+ color :Color,
+}
+
+StyledBoxData :: struct {
+ backgroundColor :u32,
+ borderColor :u32,
+ borders :Rectangle16,
+ cornerRadius :u8,
+ roundedCornersToExclude :u8,
+ ox :i32,
+ oy :i32,
+ width :i32,
+ height :i32,
+ clip :Rectangle,
+}
- information := (^OS_Node_Information)(uintptr(fd));
- count := OSWriteFileSync(information.handle, information.position, i64(len(data)), &data[0]);
- if count < 0 do return 0, 1;
- information.position += count;
- return int(count), 0;
+InstanceCreateRemoteArguments :: struct {
+ what :^i8,
+ argument :^i8,
+ whatBytes :uintptr,
+ argumentBytes :uintptr,
+ modalWindowParent :Handle,
+ apiInstance :^rawptr,
}
+DrawSurfaceArguments :: struct {
+ source :Rectangle,
+ destination :Rectangle,
+ border :Rectangle,
+ alpha :u16,
+}
+
+Spinlock :: struct {
+ state :u8,
+}
+
+Mutex :: struct {
+ event :Handle,
+ spinlock :Spinlock,
+ state :u8,
+ queued :u32,
+}
+
+CrashReason :: struct {
+ errorCode :Error,
+}
+
+ProcessState :: struct {
+ crashReason :CrashReason,
+ creationArgument :Generic,
+ id :uintptr,
+ executableState :uintptr,
+ flags :u8,
+}
+
+IORequestProgress :: struct {
+ accessed :FileOffset,
+ progress :FileOffset,
+ completed :bool,
+ cancelled :bool,
+ error :Error,
+}
+
+ClipboardHeader :: struct {
+ customBytes :uintptr,
+ format :ClipboardFormat,
+ textBytes :uintptr,
+ unused :uintptr,
+}
+
+Painter :: struct {
+ surface :Handle,
+ clip :Rectangle,
+ offsetX :i32,
+ offsetY :i32,
+ fullAlpha :bool,
+}
+
+Message :: struct {
+ type :MessageType,
+ _context :Generic,
+ using _ : struct #raw_union {
+ _argument :^rawptr,
+ mouseMoved : struct {
+ oldPositionX :i32,
+ newPositionX :i32,
+ oldPositionY :i32,
+ newPositionY :i32,
+ newPositionXScreen :i32,
+ newPositionYScreen :i32,
+ },
+
+ mouseDragged : struct {
+ oldPositionX :i32,
+ newPositionX :i32,
+ oldPositionY :i32,
+ newPositionY :i32,
+ originalPositionX :i32,
+ originalPositionY :i32,
+ },
+
+ mousePressed : struct {
+ positionX :i32,
+ positionY :i32,
+ positionXScreen :i32,
+ positionYScreen :i32,
+ clickChainCount :u8,
+ activationClick :u8,
+ alt :u8,
+ ctrl :u8,
+ shift :u8,
+ },
+
+ keyboard : struct {
+ scancode :u32,
+ alt :u8,
+ ctrl :u8,
+ shift :u8,
+ numpad :u8,
+ notHandledBy :Object,
+ },
+
+ crash : struct {
+ reason :CrashReason,
+ process :Handle,
+ processNameBuffer :Handle,
+ processNameBytes :uintptr,
+ pid :uintptr,
+ },
+
+ clipboard :ClipboardHeader,
+ receive : struct {
+ buffer :Handle,
+ bytes :uintptr,
+ },
+
+ animate : struct {
+ deltaMcs :i64,
+ waitMcs :i64,
+ complete :bool,
+ },
+
+ systemConstantUpdated : struct {
+ index :uintptr,
+ newValue :u64,
+ },
+
+ desktopExecute : struct {
+ whatBuffer :Handle,
+ argumentBuffer :Handle,
+ mailslot :Handle,
+ whatBytes :uintptr,
+ argumentBytes :uintptr,
+ modalWindowParent :u64,
+ },
+
+ dockedWindowCreate : struct {
+ pipe :Handle,
+ },
+
+ taskbar : struct {
+ id :u64,
+ buffer :Handle,
+ bytes :uintptr,
+ },
+
+ windowResized : struct {
+ content :Rectangle,
+ },
+
+ painter :^Painter,
+ measure : struct {
+ width :i32,
+ height :i32,
+ },
+
+ child :Object,
+ size : struct {
+ width :i32,
+ height :i32,
+ },
+
+ hitTest : struct {
+ x :i32,
+ y :i32,
+ inside :bool,
+ },
+
+ zOrder : struct {
+ index :uintptr,
+ child :^Element,
+ },
+
+ scrollbarMoved : struct {
+ scroll :i32,
+ },
+
+ ensureVisible : struct {
+ child :^Element,
+ },
+
+ cursorStyle :CursorStyle,
+ getItemContent : struct {
+ mask :u32,
+ index :ListViewIndex,
+ column :ListViewIndex,
+ group :ListViewIndex,
+ text :^i8,
+ textBytes :uintptr,
+ iconID :u16,
+ iconSize :u16,
+ indentation :u16,
+ spaceAfterIcon :u16,
+ },
+
+ accessItemState : struct {
+ mask :u32,
+ state :u32,
+ iIndexFrom :ListViewIndex,
+ eIndexTo :ListViewIndex,
+ group :ListViewIndex,
+ },
+
+ measureItemHeight : struct {
+ iIndexFrom :ListViewIndex,
+ eIndexTo :ListViewIndex,
+ group :ListViewIndex,
+ height :i32,
+ },
+
+ layoutItem : struct {
+ index :ListViewIndex,
+ group :ListViewIndex,
+ knownIndex :ListViewIndex,
+ knownGroup :ListViewIndex,
+ bounds :Rectangle,
+ },
+
+ toggleItemDisclosure : struct {
+ index :ListViewIndex,
+ group :ListViewIndex,
+ },
+
+ findItem : struct {
+ type :u8,
+ backwards :u8,
+ inclusive :bool,
+ indexFrom :ListViewIndex,
+ groupFrom :ListViewIndex,
+ foundIndex :ListViewIndex,
+ foundGroup :ListViewIndex,
+ using _ : struct #raw_union {
+ using _ : struct {
+ prefix :^i8,
+ prefixBytes :uintptr,
+ },
+
+ using _ : struct {
+ yPosition :i32,
+ yPositionOfIndexFrom :i32,
+ offsetIntoItem :i32,
+ },
+
+ },
+
+ },
+
+ listViewColumn : struct {
+ index :ListViewIndex,
+ descending :bool,
+ },
+
+ setItemVisibility : struct {
+ index :ListViewIndex,
+ group :ListViewIndex,
+ visible :bool,
+ },
+
+ setItemPosition : struct {
+ index :ListViewIndex,
+ group :ListViewIndex,
+ bounds :Rectangle,
+ },
+
+ listViewPaint : struct {
+ painter :^Painter,
+ width :i32,
+ height :i32,
+ index :ListViewIndex,
+ group :ListViewIndex,
+ column :ListViewIndex,
+ },
+
+ },
+
+}
+
+DebuggerMessage :: struct {
+ process :Handle,
+ reason :CrashReason,
+}
+
+DriveInformation :: struct {
+ name :[64]i8,
+ nameBytes :uintptr,
+ mountpoint :[256]i8,
+ mountpointBytes :uintptr,
+}
+
+SnapshotProcessesItem :: struct {
+ pid :i64,
+ memoryUsage :i64,
+ cpuTimeSlices :i64,
+ name :[SNAPSHOT_MAX_PROCESS_NAME_LENGTH]i8,
+ nameLength :uintptr,
+ internal :u64,
+}
+
+SystemInformation :: struct {
+ processCount :uintptr,
+ threadCount :uintptr,
+ handleCount :uintptr,
+ commitLimit :uintptr,
+ commit :uintptr,
+ countZeroedPages :uintptr,
+ countFreePages :uintptr,
+ countStandbyPages :uintptr,
+ countModifiedPages :uintptr,
+ countActivePages :uintptr,
+ coreHeapSize :uintptr,
+ coreHeapAllocations :uintptr,
+ fixedHeapSize :uintptr,
+ fixedHeapAllocations :uintptr,
+ coreRegions :uintptr,
+ kernelRegions :uintptr,
+}
+
+SnapshotProcesses :: struct {
+ count :uintptr,
+ processes :[]SnapshotProcessesItem,
+}
+
+POSIXSyscall :: struct {
+ index :int,
+ arguments :[7]int,
+}
+
+ProcessCreationArguments :: struct {
+ executablePath :^i8,
+ executablePathBytes :uintptr,
+ environmentBlock :^rawptr,
+ environmentBlockBytes :uintptr,
+ creationArgument :Generic,
+ permissions :u64,
+}
+
+UserLoginArguments :: struct {
+ name :^i8,
+ nameBytes :uintptr,
+ home :^i8,
+ homeBytes :uintptr,
+}
+
+Instance :: struct {
+ _private :^rawptr,
+}
+
+ListViewColumn :: struct {
+ title :^i8,
+ titleBytes :uintptr,
+ width :i32,
+ minimumWidth :i32,
+ flags :u32,
+}
+
+ListViewStyle :: struct {
+ fixedWidth :i32,
+ fixedHeight :i32,
+ groupHeaderHeight :i32,
+ gapX :i32,
+ gapY :i32,
+ margin :Rectangle16,
+ columns :^ListViewColumn,
+ columnCount :uintptr,
+ emptyMessage :^i8,
+ emptyMessageBytes :uintptr,
+}
+
+NumericEntryProperties :: struct {
+ value :i32,
+ dp :i32,
+ delta :i32,
+ speed :i32,
+ minimum :i32,
+ maximum :i32,
+ cPrefix :^i8,
+ cSuffix :^i8,
+}
+
+Batch :: inline proc (calls :^BatchCall, count :uintptr){ addr := 0x1000 + 0 * size_of(int); ((proc (^BatchCall, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(calls, count); }
+ProcessCreate :: inline proc (executablePath :^i8, executablePathLength :uintptr, information :^ProcessInformation, argument :Generic) -> Error{ addr := 0x1000 + 1 * size_of(int); return ((proc (^i8, uintptr, ^ProcessInformation, Generic) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(executablePath, executablePathLength, information, argument); }
+ThreadCreate :: inline proc (entryFunction :ThreadEntryFunction, information :^ThreadInformation, argument :Generic) -> Error{ addr := 0x1000 + 2 * size_of(int); return ((proc (ThreadEntryFunction, ^ThreadInformation, Generic) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(entryFunction, information, argument); }
+SurfaceCreate :: inline proc (width :uintptr, height :uintptr, flags :u32) -> Handle{ addr := 0x1000 + 3 * size_of(int); return ((proc (uintptr, uintptr, u32) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(width, height, flags); }
+EventCreate :: inline proc (autoReset :bool) -> Handle{ addr := 0x1000 + 4 * size_of(int); return ((proc (bool) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(autoReset); }
+ThreadLocalStorageSetAddress :: inline proc (address :^rawptr){ addr := 0x1000 + 5 * size_of(int); ((proc (^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(address); }
+ConstantBufferRead :: inline proc (constantBuffer :Handle, output :^rawptr){ addr := 0x1000 + 6 * size_of(int); ((proc (Handle, ^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(constantBuffer, output); }
+ConstantBufferShare :: inline proc (constantBuffer :Handle, targetProcess :Handle) -> Handle{ addr := 0x1000 + 7 * size_of(int); return ((proc (Handle, Handle) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(constantBuffer, targetProcess); }
+ConstantBufferCreate :: inline proc (data :^rawptr, dataBytes :uintptr, targetProcess :Handle) -> Handle{ addr := 0x1000 + 8 * size_of(int); return ((proc (^rawptr, uintptr, Handle) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(data, dataBytes, targetProcess); }
+ProcessOpen :: inline proc (pid :u64) -> Handle{ addr := 0x1000 + 9 * size_of(int); return ((proc (u64) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(pid); }
+HandleClose :: inline proc (handle :Handle) -> Error{ addr := 0x1000 + 10 * size_of(int); return ((proc (Handle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(handle); }
+TakeSystemSnapshot :: inline proc (type :i32, bufferSize :^uintptr) -> Handle{ addr := 0x1000 + 11 * size_of(int); return ((proc (i32, ^uintptr) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(type, bufferSize); }
+GetSystemInformation :: inline proc (systemInformation :^SystemInformation){ addr := 0x1000 + 12 * size_of(int); ((proc (^SystemInformation))(rawptr(((^uintptr)(uintptr(addr)))^)))(systemInformation); }
+NodeOpen :: inline proc (path :^i8, pathLength :uintptr, flags :u64, information :^NodeInformation) -> Error{ addr := 0x1000 + 13 * size_of(int); return ((proc (^i8, uintptr, u64, ^NodeInformation) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(path, pathLength, flags, information); }
+NodeFindUniqueName :: inline proc (buffer :^i8, originalBytes :uintptr, bufferBytes :uintptr) -> uintptr{ addr := 0x1000 + 14 * size_of(int); return ((proc (^i8, uintptr, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, originalBytes, bufferBytes); }
+FileReadAll :: inline proc (filePath :^i8, filePathLength :uintptr, fileSize :^uintptr){ addr := 0x1000 + 15 * size_of(int); ((proc (^i8, uintptr, ^uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(filePath, filePathLength, fileSize); }
+FileReadSync :: inline proc (file :Handle, offset :FileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ addr := 0x1000 + 16 * size_of(int); return ((proc (Handle, FileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(file, offset, size, buffer); }
+FileWriteSync :: inline proc (file :Handle, offset :FileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ addr := 0x1000 + 17 * size_of(int); return ((proc (Handle, FileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(file, offset, size, buffer); }
+FileResize :: inline proc (file :Handle, newSize :FileOffset) -> Error{ addr := 0x1000 + 18 * size_of(int); return ((proc (Handle, FileOffset) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(file, newSize); }
+NodeRefreshInformation :: inline proc (information :^NodeInformation){ addr := 0x1000 + 19 * size_of(int); ((proc (^NodeInformation))(rawptr(((^uintptr)(uintptr(addr)))^)))(information); }
+DirectoryEnumerateChildren :: inline proc (directory :Handle, buffer :^DirectoryChild, bufferCount :uintptr) -> int{ addr := 0x1000 + 20 * size_of(int); return ((proc (Handle, ^DirectoryChild, uintptr) -> int)(rawptr(((^uintptr)(uintptr(addr)))^)))(directory, buffer, bufferCount); }
+NodeDelete :: inline proc (node :Handle) -> Error{ addr := 0x1000 + 21 * size_of(int); return ((proc (Handle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(node); }
+NodeMove :: inline proc (node :Handle, newDirectory :Handle, newName :^i8, newNameLength :uintptr) -> Error{ addr := 0x1000 + 22 * size_of(int); return ((proc (Handle, Handle, ^i8, uintptr) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(node, newDirectory, newName, newNameLength); }
+ThreadTerminate :: inline proc (thread :Handle){ addr := 0x1000 + 23 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(thread); }
+ProcessTerminate :: inline proc (process :Handle, status :i32){ addr := 0x1000 + 24 * size_of(int); ((proc (Handle, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(process, status); }
+ProcessTerminateCurrent :: inline proc (){ addr := 0x1000 + 25 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+ProcessPause :: inline proc (process :Handle, resume :bool){ addr := 0x1000 + 26 * size_of(int); ((proc (Handle, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(process, resume); }
+ProcessCrash :: inline proc (error :Error, message :^i8, messageBytes :uintptr){ addr := 0x1000 + 27 * size_of(int); ((proc (Error, ^i8, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(error, message, messageBytes); }
+ThreadGetID :: inline proc (thread :Handle) -> uintptr{ addr := 0x1000 + 28 * size_of(int); return ((proc (Handle) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(thread); }
+ProcessGetID :: inline proc (process :Handle) -> uintptr{ addr := 0x1000 + 29 * size_of(int); return ((proc (Handle) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(process); }
+SpinlockRelease :: inline proc (spinlock :^Spinlock){ addr := 0x1000 + 30 * size_of(int); ((proc (^Spinlock))(rawptr(((^uintptr)(uintptr(addr)))^)))(spinlock); }
+SpinlockAcquire :: inline proc (spinlock :^Spinlock){ addr := 0x1000 + 31 * size_of(int); ((proc (^Spinlock))(rawptr(((^uintptr)(uintptr(addr)))^)))(spinlock); }
+MutexRelease :: inline proc (mutex :^Mutex){ addr := 0x1000 + 32 * size_of(int); ((proc (^Mutex))(rawptr(((^uintptr)(uintptr(addr)))^)))(mutex); }
+MutexAcquire :: inline proc (mutex :^Mutex){ addr := 0x1000 + 33 * size_of(int); ((proc (^Mutex))(rawptr(((^uintptr)(uintptr(addr)))^)))(mutex); }
+MutexDestroy :: inline proc (mutex :^Mutex){ addr := 0x1000 + 34 * size_of(int); ((proc (^Mutex))(rawptr(((^uintptr)(uintptr(addr)))^)))(mutex); }
+SchedulerYield :: inline proc (){ addr := 0x1000 + 35 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+EventSet :: inline proc (event :Handle){ addr := 0x1000 + 36 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(event); }
+EventReset :: inline proc (event :Handle){ addr := 0x1000 + 37 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(event); }
+EventPoll :: inline proc (event :Handle) -> Error{ addr := 0x1000 + 38 * size_of(int); return ((proc (Handle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(event); }
+Wait :: inline proc (objects :^Handle, objectCount :uintptr, timeoutMs :uintptr) -> uintptr{ addr := 0x1000 + 39 * size_of(int); return ((proc (^Handle, uintptr, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(objects, objectCount, timeoutMs); }
+Sleep :: inline proc (milliseconds :u64){ addr := 0x1000 + 40 * size_of(int); ((proc (u64))(rawptr(((^uintptr)(uintptr(addr)))^)))(milliseconds); }
+MemoryOpen :: inline proc (size :uintptr, name :^i8, nameLength :uintptr, flags :u32) -> Handle{ addr := 0x1000 + 41 * size_of(int); return ((proc (uintptr, ^i8, uintptr, u32) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(size, name, nameLength, flags); }
+MemoryShare :: inline proc (sharedMemoryRegion :Handle, targetProcess :Handle, readOnly :bool) -> Handle{ addr := 0x1000 + 42 * size_of(int); return ((proc (Handle, Handle, bool) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(sharedMemoryRegion, targetProcess, readOnly); }
+ObjectMap :: inline proc (object :Handle, offset :uintptr, size :uintptr, flags :u32){ addr := 0x1000 + 43 * size_of(int); ((proc (Handle, uintptr, uintptr, u32))(rawptr(((^uintptr)(uintptr(addr)))^)))(object, offset, size, flags); }
+MemoryAllocate :: inline proc (size :uintptr){ addr := 0x1000 + 44 * size_of(int); ((proc (uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(size); }
+MemoryFree :: inline proc (address :^rawptr) -> Error{ addr := 0x1000 + 45 * size_of(int); return ((proc (^rawptr) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(address); }
+GetCreationArgument :: inline proc (object :Handle) -> Generic{ addr := 0x1000 + 46 * size_of(int); return ((proc (Handle) -> Generic)(rawptr(((^uintptr)(uintptr(addr)))^)))(object); }
+ProcessGetState :: inline proc (process :Handle, state :^ProcessState){ addr := 0x1000 + 47 * size_of(int); ((proc (Handle, ^ProcessState))(rawptr(((^uintptr)(uintptr(addr)))^)))(process, state); }
+SurfaceGetLinearBuffer :: inline proc (surface :Handle, linearBuffer :^LinearBuffer){ addr := 0x1000 + 48 * size_of(int); ((proc (Handle, ^LinearBuffer))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, linearBuffer); }
+RectangleInvalidate :: inline proc (surface :Handle, rectangle :Rectangle){ addr := 0x1000 + 49 * size_of(int); ((proc (Handle, Rectangle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle); }
+CopyToScreen :: inline proc (source :Handle, point :Point, depth :u16){ addr := 0x1000 + 50 * size_of(int); ((proc (Handle, Point, u16))(rawptr(((^uintptr)(uintptr(addr)))^)))(source, point, depth); }
+ForceScreenUpdate :: inline proc (){ addr := 0x1000 + 51 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+DrawRectangle :: inline proc (surface :Handle, rectangle :Rectangle, color :Color){ addr := 0x1000 + 52 * size_of(int); ((proc (Handle, Rectangle, Color))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle, color); }
+DrawRectangleClipped :: inline proc (surface :Handle, rectangle :Rectangle, color :Color, clipRegion :Rectangle){ addr := 0x1000 + 53 * size_of(int); ((proc (Handle, Rectangle, Color, Rectangle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle, color, clipRegion); }
+DrawSurfaceBlit :: inline proc (destination :Handle, source :Handle, destinationPoint :Point){ addr := 0x1000 + 54 * size_of(int); ((proc (Handle, Handle, Point))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, destinationPoint); }
+DrawSurface :: inline proc (destination :Handle, source :Handle, destinationRegion :Rectangle, sourceRegion :Rectangle, borderRegion :Rectangle, mode :DrawMode, alpha :u16) -> Error{ addr := 0x1000 + 55 * size_of(int); return ((proc (Handle, Handle, Rectangle, Rectangle, Rectangle, DrawMode, u16) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha); }
+DrawSurfaceClipped :: inline proc (destination :Handle, source :Handle, destinationRegion :Rectangle, sourceRegion :Rectangle, borderRegion :Rectangle, mode :DrawMode, alpha :u16, clipRegion :Rectangle) -> Error{ addr := 0x1000 + 56 * size_of(int); return ((proc (Handle, Handle, Rectangle, Rectangle, Rectangle, DrawMode, u16, Rectangle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha, clipRegion); }
+DrawBitmap :: inline proc (destination :Handle, destinationPoint :Point, bitmap :^rawptr, width :uintptr, height :uintptr, stride :uintptr, colorFormat :ColorFormat){ addr := 0x1000 + 57 * size_of(int); ((proc (Handle, Point, ^rawptr, uintptr, uintptr, uintptr, ColorFormat))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, destinationPoint, bitmap, width, height, stride, colorFormat); }
+SurfaceClearInvalidatedRegion :: inline proc (surface :Handle){ addr := 0x1000 + 58 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface); }
+RectangleClip :: inline proc (parent :Rectangle, rectangle :Rectangle, output :^Rectangle) -> bool{ addr := 0x1000 + 59 * size_of(int); return ((proc (Rectangle, Rectangle, ^Rectangle) -> bool)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, rectangle, output); }
+DrawBox :: inline proc (surface :Handle, rectangle :Rectangle, style :u8, color :u32, clipRegion :Rectangle){ addr := 0x1000 + 60 * size_of(int); ((proc (Handle, Rectangle, u8, u32, Rectangle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle, style, color, clipRegion); }
+RedrawAll :: inline proc (){ addr := 0x1000 + 61 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+MessagePost :: inline proc (message :^Message) -> Error{ addr := 0x1000 + 62 * size_of(int); return ((proc (^Message) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(message); }
+MessagePostRemote :: inline proc (process :Handle, message :^Message) -> Error{ addr := 0x1000 + 63 * size_of(int); return ((proc (Handle, ^Message) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(process, message); }
+ExtractArguments :: inline proc (string :^i8, bytes :uintptr, delimiterByte :u8, replacementDelimiter :u8, argvAllocated :uintptr, argv :^^i8, argc :^uintptr) -> bool{ addr := 0x1000 + 64 * size_of(int); return ((proc (^i8, uintptr, u8, u8, uintptr, ^^i8, ^uintptr) -> bool)(rawptr(((^uintptr)(uintptr(addr)))^)))(string, bytes, delimiterByte, replacementDelimiter, argvAllocated, argv, argc); }
+CStringLength :: inline proc (string :^i8) -> uintptr{ addr := 0x1000 + 65 * size_of(int); return ((proc (^i8) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(string); }
+StringLength :: inline proc (string :^i8, end :u8) -> uintptr{ addr := 0x1000 + 66 * size_of(int); return ((proc (^i8, u8) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(string, end); }
+MemoryCopy :: inline proc (destination :^rawptr, source :^rawptr, bytes :uintptr){ addr := 0x1000 + 67 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, bytes); }
+MemoryMove :: inline proc (_start :^rawptr, _end :^rawptr, amount :int, zeroEmptySpace :bool){ addr := 0x1000 + 68 * size_of(int); ((proc (^rawptr, ^rawptr, int, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(_start, _end, amount, zeroEmptySpace); }
+MemoryCopyReverse :: inline proc (_destination :^rawptr, _source :^rawptr, bytes :uintptr){ addr := 0x1000 + 69 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(_destination, _source, bytes); }
+MemoryZero :: inline proc (destination :^rawptr, bytes :uintptr){ addr := 0x1000 + 70 * size_of(int); ((proc (^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, bytes); }
+MemoryCompare :: inline proc (a :^rawptr, b :^rawptr, bytes :uintptr) -> i32{ addr := 0x1000 + 71 * size_of(int); return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(a, b, bytes); }
+MemorySumBytes :: inline proc (data :^u8, bytes :uintptr) -> u8{ addr := 0x1000 + 72 * size_of(int); return ((proc (^u8, uintptr) -> u8)(rawptr(((^uintptr)(uintptr(addr)))^)))(data, bytes); }
+PrintDirect :: inline proc (string :^i8, stringLength :uintptr){ addr := 0x1000 + 73 * size_of(int); ((proc (^i8, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(string, stringLength); }
+StringFormat :: inline proc (buffer :^i8, bufferLength :uintptr, format :^i8, args : ..any) -> uintptr{ addr := 0x1000 + 74 * size_of(int); return ((proc (^i8, uintptr, ^i8, ..any) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, bufferLength, format, ); }
+StringFormatAppend :: inline proc (buffer :^i8, bufferLength :uintptr, bufferPosition :^uintptr, format :^i8, args : ..any){ addr := 0x1000 + 75 * size_of(int); ((proc (^i8, uintptr, ^uintptr, ^i8, ..any))(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, bufferLength, bufferPosition, format, ); }
+PrintHelloWorld :: inline proc (){ addr := 0x1000 + 76 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+GetRandomByte :: inline proc () -> u8{ addr := 0x1000 + 77 * size_of(int); return ((proc () -> u8)(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+Sort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :ComparisonCallbackFunction, argument :Generic){ addr := 0x1000 + 78 * size_of(int); ((proc (^rawptr, uintptr, uintptr, ComparisonCallbackFunction, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(_base, nmemb, size, compar, argument); }
+SortWithSwapCallback :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :ComparisonCallbackFunction, argument :Generic, swap :SwapCallbackFunction){ addr := 0x1000 + 79 * size_of(int); ((proc (^rawptr, uintptr, uintptr, ComparisonCallbackFunction, Generic, SwapCallbackFunction))(rawptr(((^uintptr)(uintptr(addr)))^)))(_base, nmemb, size, compar, argument, swap); }
+StringCompare :: inline proc (s1 :^i8, s2 :^i8, length1 :uintptr, length2 :uintptr) -> i32{ addr := 0x1000 + 80 * size_of(int); return ((proc (^i8, ^i8, uintptr, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2, length1, length2); }
+IntegerParse :: inline proc (text :^i8, bytes :uintptr) -> i64{ addr := 0x1000 + 81 * size_of(int); return ((proc (^i8, uintptr) -> i64)(rawptr(((^uintptr)(uintptr(addr)))^)))(text, bytes); }
+CRTmemset :: inline proc (s :^rawptr, c :i32, n :uintptr){ addr := 0x1000 + 82 * size_of(int); ((proc (^rawptr, i32, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(s, c, n); }
+CRTmemcpy :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ addr := 0x1000 + 83 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src, n); }
+CRTmemmove :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ addr := 0x1000 + 84 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src, n); }
+CRTstrlen :: inline proc (s :^i8) -> uintptr{ addr := 0x1000 + 85 * size_of(int); return ((proc (^i8) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(s); }
+CRTstrnlen :: inline proc (s :^i8, maxlen :uintptr) -> uintptr{ addr := 0x1000 + 86 * size_of(int); return ((proc (^i8, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(s, maxlen); }
+CRTmalloc :: inline proc (size :uintptr){ addr := 0x1000 + 87 * size_of(int); ((proc (uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(size); }
+CRTcalloc :: inline proc (num :uintptr, size :uintptr){ addr := 0x1000 + 88 * size_of(int); ((proc (uintptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(num, size); }
+CRTfree :: inline proc (ptr :^rawptr){ addr := 0x1000 + 89 * size_of(int); ((proc (^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(ptr); }
+CRTabs :: inline proc (n :i32) -> i32{ addr := 0x1000 + 90 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(n); }
+CRTrealloc :: inline proc (ptr :^rawptr, size :uintptr){ addr := 0x1000 + 91 * size_of(int); ((proc (^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(ptr, size); }
+CRTgetenv :: inline proc (name :^i8) -> ^i8{ addr := 0x1000 + 92 * size_of(int); return ((proc (^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(name); }
+CRTstrncmp :: inline proc (s1 :^i8, s2 :^i8, n :uintptr) -> i32{ addr := 0x1000 + 93 * size_of(int); return ((proc (^i8, ^i8, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2, n); }
+CRTmemcmp :: inline proc (s1 :^rawptr, s2 :^rawptr, n :uintptr) -> i32{ addr := 0x1000 + 94 * size_of(int); return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2, n); }
+CRTqsort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :CRTComparisonCallback){ addr := 0x1000 + 95 * size_of(int); ((proc (^rawptr, uintptr, uintptr, CRTComparisonCallback))(rawptr(((^uintptr)(uintptr(addr)))^)))(_base, nmemb, size, compar); }
+CRTstrcmp :: inline proc (s1 :^i8, s2 :^i8) -> i32{ addr := 0x1000 + 96 * size_of(int); return ((proc (^i8, ^i8) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2); }
+CRTstrstr :: inline proc (haystack :^i8, needle :^i8) -> ^i8{ addr := 0x1000 + 97 * size_of(int); return ((proc (^i8, ^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(haystack, needle); }
+CRTstrcpy :: inline proc (dest :^i8, src :^i8) -> ^i8{ addr := 0x1000 + 98 * size_of(int); return ((proc (^i8, ^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src); }
+CRTisalpha :: inline proc (c :i32) -> i32{ addr := 0x1000 + 99 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(c); }
+CRTmemchr :: inline proc (_s :^rawptr, _c :i32, n :uintptr){ addr := 0x1000 + 100 * size_of(int); ((proc (^rawptr, i32, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(_s, _c, n); }
+CRTisdigit :: inline proc (c :i32) -> i32{ addr := 0x1000 + 101 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(c); }
+CRTstrcat :: inline proc (dest :^i8, src :^i8) -> ^i8{ addr := 0x1000 + 102 * size_of(int); return ((proc (^i8, ^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src); }
+CRTtolower :: inline proc (c :i32) -> i32{ addr := 0x1000 + 103 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(c); }
+CRTstrncpy :: inline proc (dest :^i8, src :^i8, n :uintptr) -> ^i8{ addr := 0x1000 + 104 * size_of(int); return ((proc (^i8, ^i8, uintptr) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src, n); }
+CRTstrtoul :: inline proc (nptr :^i8, endptr :^^i8, base :i32) -> u64{ addr := 0x1000 + 105 * size_of(int); return ((proc (^i8, ^^i8, i32) -> u64)(rawptr(((^uintptr)(uintptr(addr)))^)))(nptr, endptr, base); }
+Execute :: inline proc (what :^i8, whatBytes :uintptr, argument :^i8, argumentBytes :uintptr){ addr := 0x1000 + 106 * size_of(int); ((proc (^i8, uintptr, ^i8, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(what, whatBytes, argument, argumentBytes); }
+Abort :: inline proc (){ addr := 0x1000 + 107 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+MailslotSendData :: inline proc (mailslot :Handle, data :^rawptr, bytes :uintptr) -> bool{ addr := 0x1000 + 108 * size_of(int); return ((proc (Handle, ^rawptr, uintptr) -> bool)(rawptr(((^uintptr)(uintptr(addr)))^)))(mailslot, data, bytes); }
+CRTfloorf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 109 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTceilf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 110 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTsinf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 111 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTcosf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 112 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTatan2f :: inline proc (y :f32, x :f32) -> f32{ addr := 0x1000 + 113 * size_of(int); return ((proc (f32, f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(y, x); }
+CRTfmodf :: inline proc (x :f32, y :f32) -> f32{ addr := 0x1000 + 114 * size_of(int); return ((proc (f32, f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x, y); }
+CRTacosf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 115 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTasinf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 116 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTatanf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 117 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+RandomSeed :: inline proc (x :u64){ addr := 0x1000 + 118 * size_of(int); ((proc (u64))(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTsqrtf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 119 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTsqrtl :: inline proc (x :LongDouble) -> LongDouble{ addr := 0x1000 + 120 * size_of(int); return ((proc (LongDouble) -> LongDouble)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+CRTfabsl :: inline proc (x :LongDouble) -> LongDouble{ addr := 0x1000 + 121 * size_of(int); return ((proc (LongDouble) -> LongDouble)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); }
+Syscall :: inline proc (a :uintptr, b :uintptr, c :uintptr, d :uintptr, e :uintptr, f :uintptr) -> uintptr{ addr := 0x1000 + 122 * size_of(int); return ((proc (uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(a, b, c, d, e, f); }
+ProcessorReadTimeStamp :: inline proc () -> u64{ addr := 0x1000 + 123 * size_of(int); return ((proc () -> u64)(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+HeapAllocate :: inline proc (size :uintptr, zeroMemory :bool){ addr := 0x1000 + 124 * size_of(int); ((proc (uintptr, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(size, zeroMemory); }
+HeapFree :: inline proc (address :^rawptr){ addr := 0x1000 + 125 * size_of(int); ((proc (^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(address); }
+Print :: inline proc (format :^i8, args : ..any){ addr := 0x1000 + 126 * size_of(int); ((proc (^i8, ..any))(rawptr(((^uintptr)(uintptr(addr)))^)))(format, ); }
+MemoryFill :: inline proc (from :^rawptr, to :^rawptr, byte :u8){ addr := 0x1000 + 127 * size_of(int); ((proc (^rawptr, ^rawptr, u8))(rawptr(((^uintptr)(uintptr(addr)))^)))(from, to, byte); }
+InitialiseCStandardLibrary :: inline proc (argc :^i32, argv :^^^i8){ addr := 0x1000 + 128 * size_of(int); ((proc (^i32, ^^^i8))(rawptr(((^uintptr)(uintptr(addr)))^)))(argc, argv); }
+MakeLinuxSystemCall2 :: inline proc (n :int, a1 :int, a2 :int, a3 :int, a4 :int, a5 :int, a6 :int) -> int{ addr := 0x1000 + 129 * size_of(int); return ((proc (int, int, int, int, int, int, int) -> int)(rawptr(((^uintptr)(uintptr(addr)))^)))(n, a1, a2, a3, a4, a5, a6); }
+ProcessCreate2 :: inline proc (arguments :^ProcessCreationArguments, information :^ProcessInformation) -> Error{ addr := 0x1000 + 130 * size_of(int); return ((proc (^ProcessCreationArguments, ^ProcessInformation) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(arguments, information); }
+CRTatoi :: inline proc (string :^i8) -> i32{ addr := 0x1000 + 131 * size_of(int); return ((proc (^i8) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(string); }
+ProcessGetExitStatus :: inline proc (process :Handle) -> i32{ addr := 0x1000 + 132 * size_of(int); return ((proc (Handle) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(process); }
+SurfaceReset :: inline proc (surface :Handle){ addr := 0x1000 + 133 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface); }
+TimerCreate :: inline proc () -> Handle{ addr := 0x1000 + 134 * size_of(int); return ((proc () -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(); }
+TimerSet :: inline proc (handle :Handle, afterMs :u64, object :Object, argument :Generic){ addr := 0x1000 + 135 * size_of(int); ((proc (Handle, u64, Object, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(handle, afterMs, object, argument); }
+FileWriteAll :: inline proc (filePath :^i8, filePathLength :uintptr, data :^rawptr, fileSize :uintptr) -> Error{ addr := 0x1000 + 136 * size_of(int); return ((proc (^i8, uintptr, ^rawptr, uintptr) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(filePath, filePathLength, data, fileSize); }
+UserGetHomeFolder :: inline proc (buffer :^i8, bufferBytes :uintptr) -> uintptr{ addr := 0x1000 + 137 * size_of(int); return ((proc (^i8, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, bufferBytes); }
+Assert :: inline proc (expression :bool, failureMessage :^i8){ addr := 0x1000 + 138 * size_of(int); ((proc (bool, ^i8))(rawptr(((^uintptr)(uintptr(addr)))^)))(expression, failureMessage); }
+ResizeArray :: inline proc (array :^^rawptr, allocated :^uintptr, needed :uintptr, itemSize :uintptr){ addr := 0x1000 + 139 * size_of(int); ((proc (^^rawptr, ^uintptr, uintptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(array, allocated, needed, itemSize); }
+MessageLoopEnter :: inline proc (callback :MessageCallbackFunction = nil){ addr := 0x1000 + 140 * size_of(int); ((proc (MessageCallbackFunction))(rawptr(((^uintptr)(uintptr(addr)))^)))(callback); }
+InstanceCreate :: inline proc (bytes :uintptr) -> ^Instance{ addr := 0x1000 + 141 * size_of(int); return ((proc (uintptr) -> ^Instance)(rawptr(((^uintptr)(uintptr(addr)))^)))(bytes); }
+MouseGetPosition :: inline proc (relativeWindow :^Window = nil) -> Point{ addr := 0x1000 + 142 * size_of(int); return ((proc (^Window) -> Point)(rawptr(((^uintptr)(uintptr(addr)))^)))(relativeWindow); }
+MouseSetPosition :: inline proc (relativeWindow :^Window, x :i32, y :i32){ addr := 0x1000 + 143 * size_of(int); ((proc (^Window, i32, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(relativeWindow, x, y); }
+NewPanel :: inline proc (parent :^Element, cStyle :^i8, flags :u64 = FLAGS_DEFAULT) -> ^Panel{ addr := 0x1000 + 144 * size_of(int); return ((proc (^Element, ^i8, u64) -> ^Panel)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, cStyle, flags); }
+NewCustomPanel :: inline proc (parent :^Element, style :Data, flags :u64 = FLAGS_DEFAULT) -> ^Panel{ addr := 0x1000 + 145 * size_of(int); return ((proc (^Element, Data, u64) -> ^Panel)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, style, flags); }
+NewWindow :: inline proc (instance :^Instance, style :WindowStyle = WindowStyle.WINDOW_NORMAL) -> ^Window{ addr := 0x1000 + 146 * size_of(int); return ((proc (^Instance, WindowStyle) -> ^Window)(rawptr(((^uintptr)(uintptr(addr)))^)))(instance, style); }
+NewScrollbar :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^Scrollbar{ addr := 0x1000 + 147 * size_of(int); return ((proc (^Element, u64, UICallbackFunction, Generic) -> ^Scrollbar)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); }
+NewButton :: inline proc (parent :^Element, label :^i8 = nil, labelBytes :int = -1, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^Button{ addr := 0x1000 + 148 * size_of(int); return ((proc (^Element, ^i8, int, u64, UICallbackFunction, Generic) -> ^Button)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, label, labelBytes, flags, userCallback, _context); }
+NewTextbox :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^Textbox{ addr := 0x1000 + 149 * size_of(int); return ((proc (^Element, u64, UICallbackFunction, Generic) -> ^Textbox)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); }
+NewNumericEntry :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^NumericEntry{ addr := 0x1000 + 150 * size_of(int); return ((proc (^Element, u64, UICallbackFunction, Generic) -> ^NumericEntry)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); }
+NewListView :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, style :^ListViewStyle = nil, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^ListView{ addr := 0x1000 + 151 * size_of(int); return ((proc (^Element, u64, ^ListViewStyle, UICallbackFunction, Generic) -> ^ListView)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, style, userCallback, _context); }
+NewMenu :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :MenuCallbackFunction = nil, _context :Generic = nil) -> ^Menu{ addr := 0x1000 + 152 * size_of(int); return ((proc (^Element, u64, MenuCallbackFunction, Generic) -> ^Menu)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); }
+NewMenuItem :: inline proc (parent :^Element, flags :u64, label :^i8, labelBytes :int = -1, callback :MenuCallbackFunction = nil, _context :Generic = nil){ addr := 0x1000 + 153 * size_of(int); ((proc (^Element, u64, ^i8, int, MenuCallbackFunction, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, label, labelBytes, callback, _context); }
+ElementGetInstance :: inline proc (element :^Element) -> ^INSTANCE_TYPE{ addr := 0x1000 + 154 * size_of(int); return ((proc (^Element) -> ^INSTANCE_TYPE)(rawptr(((^uintptr)(uintptr(addr)))^)))(element); }
+ElementFocus :: inline proc (element :^Element, ensureVisible :bool){ addr := 0x1000 + 155 * size_of(int); ((proc (^Element, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(element, ensureVisible); }
+ElementSetDisabled :: inline proc (element :^Element, disabled :bool){ addr := 0x1000 + 156 * size_of(int); ((proc (^Element, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(element, disabled); }
+ElementSetCallback :: inline proc (element :^Element, callback :UICallbackFunction, _context :Generic){ addr := 0x1000 + 157 * size_of(int); ((proc (^Element, UICallbackFunction, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(element, callback, _context); }
+ScrollbarSetMeasurements :: inline proc (scrollbar :^Scrollbar, viewportSize :i32, contentSize :i32){ addr := 0x1000 + 158 * size_of(int); ((proc (^Scrollbar, i32, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(scrollbar, viewportSize, contentSize); }
+ScrollbarSetPosition :: inline proc (scrollbar :^Scrollbar, position :f32, sendMovedMessage :bool, smoothScroll :bool){ addr := 0x1000 + 159 * size_of(int); ((proc (^Scrollbar, f32, bool, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(scrollbar, position, sendMovedMessage, smoothScroll); }
+WindowGetBounds :: inline proc (window :^Window) -> Rectangle{ addr := 0x1000 + 160 * size_of(int); return ((proc (^Window) -> Rectangle)(rawptr(((^uintptr)(uintptr(addr)))^)))(window); }
+WindowGetToolbar :: inline proc (window :^Window) -> ^Element{ addr := 0x1000 + 161 * size_of(int); return ((proc (^Window) -> ^Element)(rawptr(((^uintptr)(uintptr(addr)))^)))(window); }
+ListViewInsert :: inline proc (listView :^ListView, group :ListViewIndex, index :ListViewIndex, count :uintptr){ addr := 0x1000 + 162 * size_of(int); ((proc (^ListView, ListViewIndex, ListViewIndex, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group, index, count); }
+ListViewInsertGroup :: inline proc (listView :^ListView, group :ListViewIndex){ addr := 0x1000 + 163 * size_of(int); ((proc (^ListView, ListViewIndex))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group); }
+ListViewRemove :: inline proc (listView :^ListView, group :ListViewIndex, index :ListViewIndex, count :int, removedHeight :i32){ addr := 0x1000 + 164 * size_of(int); ((proc (^ListView, ListViewIndex, ListViewIndex, int, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group, index, count, removedHeight); }
+ListViewRemoveGroup :: inline proc (listView :^ListView, group :ListViewIndex){ addr := 0x1000 + 165 * size_of(int); ((proc (^ListView, ListViewIndex))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group); }
+ListViewInvalidate :: inline proc (listView :^ListView, deltaHeight :i32, recalculateHeight :bool){ addr := 0x1000 + 166 * size_of(int); ((proc (^ListView, i32, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, deltaHeight, recalculateHeight); }
+ListViewEnsureVisible :: inline proc (listView :^ListView, group :ListViewIndex, index :ListViewIndex){ addr := 0x1000 + 167 * size_of(int); ((proc (^ListView, ListViewIndex, ListViewIndex))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group, index); }
+ListViewResetSearchBuffer :: inline proc (listView :^ListView){ addr := 0x1000 + 168 * size_of(int); ((proc (^ListView))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView); }
+ButtonSetIcon :: inline proc (button :^Button, iconID :u32){ addr := 0x1000 + 169 * size_of(int); ((proc (^Button, u32))(rawptr(((^uintptr)(uintptr(addr)))^)))(button, iconID); }
+DataParse :: inline proc (cFormat :^i8, args : ..any) -> Data{ addr := 0x1000 + 170 * size_of(int); return ((proc (^i8, ..any) -> Data)(rawptr(((^uintptr)(uintptr(addr)))^)))(cFormat, ); }
+
+
+//////////////////////////////////////////////////////
+
+Errno :: distinct i32;
+
+stdin: Handle = 0;
+stdout: Handle = 1;
+stderr: Handle = 2;
+
+O_RDONLY :: 0x00000;
+O_WRONLY :: 0x00001;
+O_RDWR :: 0x00002;
+O_CREATE :: 0x00040;
+O_EXCL :: 0x00080;
+O_NOCTTY :: 0x00100;
+O_TRUNC :: 0x00200;
+O_NONBLOCK :: 0x00800;
+O_APPEND :: 0x00400;
+O_SYNC :: 0x01000;
+O_ASYNC :: 0x02000;
+O_CLOEXEC :: 0x80000;
+
+ERROR_SUCCESS :: 0;
+ERROR_UNSUPPORTED :: 1;
+
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
- if (fd == 0 || fd == 1) {
- assert(false);
- return 0, ERROR_NOT_IMPLEMENTED;
+ return -1, ERROR_UNSUPPORTED;
+}
+
+write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+ if (fd == stdout) {
+ PrintDirect((^i8)(&data[0]), (uintptr)(len(data)));
+ return len(data), ERROR_SUCCESS;
}
- information := (^OS_Node_Information)(uintptr(fd));
- count := OSReadFileSync(information.handle, information.position, i64(len(data)), &data[0]);
- if count < 0 do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
- information.position += count;
- return int(count), ERROR_NONE;
+ return -1, ERROR_UNSUPPORTED;
+}
+
+open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
+ return INVALID_HANDLE, ERROR_UNSUPPORTED;
}
+
+close :: proc(fd: Handle) -> Errno {
+ return ERROR_UNSUPPORTED;
+}
+
+file_size :: proc(fd: Handle) -> (i64, Errno) {
+ return 0, ERROR_UNSUPPORTED;
+}
+
+heap_alloc :: proc(size: int) -> rawptr {
+ return nil;
+}
+
+heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
+ return nil;
+}
+
+heap_free :: proc(ptr: rawptr) {
+}
+
+current_thread_id :: proc "contextless" () -> int {
+ // return int(EsThreadGetID(ES_CURRENT_THREAD));
+ return -1;
+}
+
+OS :: "essence";
diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin
index 1587e2ad1..13eab5def 100644
--- a/core/os/os_linux.odin
+++ b/core/os/os_linux.odin
@@ -392,9 +392,9 @@ dlerror :: proc() -> string {
_alloc_command_line_arguments :: proc() -> []string {
- args := make([]string, len(runtime.args__));
+ res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ {
- args[i] = string(arg);
+ res[i] = string(arg);
}
- return args;
+ return res;
}
diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin
index 9618f83be..e45cf9f5f 100644
--- a/core/os/os_windows.odin
+++ b/core/os/os_windows.odin
@@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool {
is_windows_10 :: proc() -> bool {
osvi := get_windows_version_ansi();
return (osvi.major_version == 10 && osvi.minor_version == 0);
-} \ No newline at end of file
+}
diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin
new file mode 100644
index 000000000..4bc9a2225
--- /dev/null
+++ b/core/reflect/reflect.odin
@@ -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;
+}
diff --git a/core/types/types.odin b/core/reflect/types.odin
index dc4db549f..d1678a1b2 100644
--- a/core/types/types.odin
+++ b/core/reflect/types.odin
@@ -1,6 +1,7 @@
-package types
+package reflect
import rt "core:runtime"
+import "core:strings"
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
if a == b do return true;
@@ -108,9 +109,11 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
for _, i in x.types {
xn, yn := x.names[i], y.names[i];
xt, yt := x.types[i], y.types[i];
+ xl, yl := x.tags[i], y.tags[i];
if xn != yn do return false;
if !are_types_identical(xt, yt) do return false;
+ if xl != yl do return false;
}
return true;
@@ -272,3 +275,216 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
return ok;
}
+
+
+
+
+
+
+write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
+ write_type(buf, type_info_of(id));
+}
+
+write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
+ using strings;
+ if ti == nil {
+ write_string(buf, "nil");
+ return;
+ }
+
+ switch info in ti.variant {
+ case rt.Type_Info_Named:
+ write_string(buf, info.name);
+ case rt.Type_Info_Integer:
+ switch ti.id {
+ case int: write_string(buf, "int");
+ case uint: write_string(buf, "uint");
+ case uintptr: write_string(buf, "uintptr");
+ case:
+ write_byte(buf, info.signed ? 'i' : 'u');
+ write_i64(buf, i64(8*ti.size), 10);
+ switch info.endianness {
+ case .Little: write_string(buf, "le");
+ case .Big: write_string(buf, "be");
+ }
+ }
+ case rt.Type_Info_Rune:
+ write_string(buf, "rune");
+ case rt.Type_Info_Float:
+ write_byte(buf, 'f');
+ write_i64(buf, i64(8*ti.size), 10);
+ case rt.Type_Info_Complex:
+ write_string(buf, "complex");
+ write_i64(buf, i64(8*ti.size), 10);
+ case rt.Type_Info_String:
+ if info.is_cstring {
+ write_string(buf, "cstring");
+ } else {
+ write_string(buf, "string");
+ }
+ case rt.Type_Info_Boolean:
+ switch ti.id {
+ case bool: write_string(buf, "bool");
+ case:
+ write_byte(buf, 'b');
+ write_i64(buf, i64(8*ti.size), 10);
+ }
+ case rt.Type_Info_Any:
+ write_string(buf, "any");
+
+ case rt.Type_Info_Type_Id:
+ write_string(buf, "typeid");
+
+ case rt.Type_Info_Pointer:
+ if info.elem == nil {
+ write_string(buf, "rawptr");
+ } else {
+ write_string(buf, "^");
+ write_type(buf, info.elem);
+ }
+ case rt.Type_Info_Procedure:
+ write_string(buf, "proc");
+ if info.params == nil {
+ write_string(buf, "()");
+ } else {
+ t := info.params.variant.(rt.Type_Info_Tuple);
+ write_string(buf, "(");
+ for t, i in t.types {
+ if i > 0 do write_string(buf, ", ");
+ write_type(buf, t);
+ }
+ write_string(buf, ")");
+ }
+ if info.results != nil {
+ write_string(buf, " -> ");
+ write_type(buf, info.results);
+ }
+ case rt.Type_Info_Tuple:
+ count := len(info.names);
+ if count != 1 do write_string(buf, "(");
+ for name, i in info.names {
+ if i > 0 do write_string(buf, ", ");
+
+ t := info.types[i];
+
+ if len(name) > 0 {
+ write_string(buf, name);
+ write_string(buf, ": ");
+ }
+ write_type(buf, t);
+ }
+ if count != 1 do write_string(buf, ")");
+
+ case rt.Type_Info_Array:
+ write_string(buf, "[");
+ write_i64(buf, i64(info.count), 10);
+ write_string(buf, "]");
+ write_type(buf, info.elem);
+ case rt.Type_Info_Dynamic_Array:
+ write_string(buf, "[dynamic]");
+ write_type(buf, info.elem);
+ case rt.Type_Info_Slice:
+ write_string(buf, "[]");
+ write_type(buf, info.elem);
+
+ case rt.Type_Info_Map:
+ write_string(buf, "map[");
+ write_type(buf, info.key);
+ write_byte(buf, ']');
+ write_type(buf, info.value);
+
+ case rt.Type_Info_Struct:
+ write_string(buf, "struct ");
+ if info.is_packed do write_string(buf, "#packed ");
+ if info.is_raw_union do write_string(buf, "#raw_union ");
+ if info.custom_align {
+ write_string(buf, "#align ");
+ write_i64(buf, i64(ti.align), 10);
+ write_byte(buf, ' ');
+ }
+ write_byte(buf, '{');
+ for name, i in info.names {
+ if i > 0 do write_string(buf, ", ");
+ write_string(buf, name);
+ write_string(buf, ": ");
+ write_type(buf, info.types[i]);
+ }
+ write_byte(buf, '}');
+
+ case rt.Type_Info_Union:
+ write_string(buf, "union ");
+ if info.custom_align {
+ write_string(buf, "#align ");
+ write_i64(buf, i64(ti.align), 10);
+ write_byte(buf, ' ');
+ }
+ write_byte(buf, '{');
+ for variant, i in info.variants {
+ if i > 0 do write_string(buf, ", ");
+ write_type(buf, variant);
+ }
+ write_byte(buf, '}');
+
+ case rt.Type_Info_Enum:
+ write_string(buf, "enum ");
+ write_type(buf, info.base);
+ write_string(buf, " {");
+ for name, i in info.names {
+ if i > 0 do write_string(buf, ", ");
+ write_string(buf, name);
+ }
+ write_byte(buf, '}');
+
+ case rt.Type_Info_Bit_Field:
+ write_string(buf, "bit_field ");
+ if ti.align != 1 {
+ write_string(buf, "#align ");
+ write_i64(buf, i64(ti.align), 10);
+ write_byte(buf, ' ');
+ }
+ write_string(buf, " {");
+ for name, i in info.names {
+ if i > 0 do write_string(buf, ", ");
+ write_string(buf, name);
+ write_string(buf, ": ");
+ write_i64(buf, i64(info.bits[i]), 10);
+ }
+ write_byte(buf, '}');
+
+ case rt.Type_Info_Bit_Set:
+ write_string(buf, "bit_set[");
+ switch {
+ case is_enum(info.elem):
+ write_type(buf, info.elem);
+ case is_rune(info.elem):
+ write_encoded_rune(buf, rune(info.lower));
+ write_string(buf, "..");
+ write_encoded_rune(buf, rune(info.upper));
+ case:
+ write_i64(buf, info.lower, 10);
+ write_string(buf, "..");
+ write_i64(buf, info.upper, 10);
+ }
+ if info.underlying != nil {
+ write_string(buf, "; ");
+ write_type(buf, info.underlying);
+ }
+ write_byte(buf, ']');
+
+ case rt.Type_Info_Opaque:
+ write_string(buf, "opaque ");
+ write_type(buf, info.elem);
+
+ case rt.Type_Info_Simd_Vector:
+ if info.is_x86_mmx {
+ write_string(buf, "intrinsics.x86_mmx");
+ } else {
+ write_string(buf, "intrinsics.vector(");
+ write_i64(buf, i64(info.count));
+ write_string(buf, ", ");
+ write_type(buf, info.elem);
+ write_byte(buf, ')');
+ }
+ }
+}
+
diff --git a/core/runtime/core.odin b/core/runtime/core.odin
index 623f3725a..7ba98ae30 100644
--- a/core/runtime/core.odin
+++ b/core/runtime/core.odin
@@ -6,6 +6,7 @@ package runtime
import "core:os"
import "core:mem"
import "core:log"
+import "intrinsics"
// Naming Conventions:
// In general, Ada_Case for types and snake_case for values
@@ -40,23 +41,24 @@ Type_Info_Enum_Value :: union {
u8, u16, u32, u64, uint, uintptr,
};
-Type_Info_Endianness :: enum u8 {
+Platform_Endianness :: enum u8 {
Platform = 0,
Little = 1,
Big = 2,
}
// Variant Types
-Type_Info_Named :: struct {name: string, base: ^Type_Info};
-Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness};
-Type_Info_Rune :: struct {};
-Type_Info_Float :: struct {};
-Type_Info_Complex :: struct {};
-Type_Info_String :: struct {is_cstring: bool};
-Type_Info_Boolean :: struct {};
-Type_Info_Any :: struct {};
-Type_Info_Type_Id :: struct {};
-Type_Info_Pointer :: struct {
+Type_Info_Named :: struct {name: string, base: ^Type_Info};
+Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
+Type_Info_Rune :: struct {};
+Type_Info_Float :: struct {};
+Type_Info_Complex :: struct {};
+Type_Info_Quaternion :: struct {};
+Type_Info_String :: struct {is_cstring: bool};
+Type_Info_Boolean :: struct {};
+Type_Info_Any :: struct {};
+Type_Info_Type_Id :: struct {};
+Type_Info_Pointer :: struct {
elem: ^Type_Info // nil -> rawptr
};
Type_Info_Procedure :: struct {
@@ -79,8 +81,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
Type_Info_Struct :: struct {
types: []^Type_Info,
names: []string,
- offsets: []uintptr, // offsets may not be used in tuples
- usings: []bool, // usings may not be used in tuples
+ offsets: []uintptr,
+ usings: []bool,
+ tags: []string,
is_packed: bool,
is_raw_union: bool,
custom_align: bool,
@@ -134,6 +137,7 @@ Type_Info :: struct {
Type_Info_Rune,
Type_Info_Float,
Type_Info_Complex,
+ Type_Info_Quaternion,
Type_Info_String,
Type_Info_Boolean,
Type_Info_Any,
@@ -162,6 +166,7 @@ Typeid_Kind :: enum u8 {
Rune,
Float,
Complex,
+ Quaternion,
String,
Boolean,
Any,
@@ -183,12 +188,13 @@ Typeid_Kind :: enum u8 {
#assert(len(Typeid_Kind) < 32);
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
- index: 8*size_of(align_of(uintptr)) - 8,
+ index: 8*size_of(uintptr) - 8,
kind: 5, // Typeid_Kind
named: 1,
special: 1, // signed, cstring, etc
reserved: 1,
}
+#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
@@ -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;
@@ -255,7 +276,7 @@ Map_Entry_Header :: struct {
}
Map_Header :: struct {
- m: ^mem.Raw_Map,
+ m: ^Raw_Map,
is_key_string: bool,
entry_size: int,
@@ -282,19 +303,21 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
}
-type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
+type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
if info == nil do return nil;
base := info;
loop: for {
switch i in base.variant {
- case Type_Info_Named: base = i.base;
- case Type_Info_Enum: base = i.base;
+ case Type_Info_Named: base = i.base;
+ case Type_Info_Enum: base = i.base;
+ case Type_Info_Opaque: base = i.elem;
case: break loop;
}
}
return base;
}
+type_info_base_without_enum :: type_info_core;
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
data := transmute(Typeid_Bit_Field)id;
@@ -310,10 +333,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
ti = type_info_base(ti);
return ti.id;
}
-typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
+typeid_core :: proc "contextless" (id: typeid) -> typeid {
ti := type_info_base_without_enum(type_info_of(id));
return ti.id;
}
+typeid_base_without_enum :: typeid_core;
@@ -385,7 +409,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
@builtin
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
n := max(0, min(len(dst), len(src)));
- if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
+ if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
return n;
}
@@ -396,7 +420,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
if array == nil do return E{};
assert(len(array) > 0);
res := array[len(array)-1];
- (^mem.Raw_Dynamic_Array)(array).len -= 1;
+ (^Raw_Dynamic_Array)(array).len -= 1;
return res;
}
@@ -460,14 +484,11 @@ make :: proc{
mem.make_map,
};
-
-
-
@builtin
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
if m == nil do return;
- raw_map := (^mem.Raw_Map)(m);
- entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
+ raw_map := (^Raw_Map)(m);
+ entries := (^Raw_Dynamic_Array)(&raw_map.entries);
entries.len = 0;
for _, i in raw_map.hashes {
raw_map.hashes[i] = -1;
@@ -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);
if arg_len > 0 {
- a := (^mem.Raw_Dynamic_Array)(array);
+ a := (^Raw_Dynamic_Array)(array);
data := (^E)(a.data);
assert(data != nil);
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;
}
}
@@ -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);
if arg_len > 0 {
- a := (^mem.Raw_Dynamic_Array)(array);
+ a := (^Raw_Dynamic_Array)(array);
data := (^E)(a.data);
assert(data != nil);
- mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
+ mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
a.len += arg_len;
}
}
@@ -540,13 +561,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@builtin
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
- if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
+ if array != nil do (^Raw_Dynamic_Array)(array).len = 0;
}
@builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
if array == nil do return false;
- a := (^mem.Raw_Dynamic_Array)(array);
+ a := (^Raw_Dynamic_Array)(array);
if capacity <= a.cap do return true;
@@ -573,7 +594,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
@builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
if array == nil do return false;
- a := (^mem.Raw_Dynamic_Array)(array);
+ a := (^Raw_Dynamic_Array)(array);
if length <= a.cap {
a.len = max(length, 0);
@@ -666,11 +687,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
@builtin
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
if !condition {
- p := context.assertion_failure_proc;
- if p == nil {
- p = default_assertion_failure_proc;
- }
- p("Runtime assertion", message, loc);
+ proc(message: string, loc: Source_Code_Location) {
+ p := context.assertion_failure_proc;
+ if p == nil {
+ p = default_assertion_failure_proc;
+ }
+ p("runtime assertion", message, loc);
+ }(message, loc);
}
return condition;
}
@@ -681,7 +704,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
if p == nil {
p = default_assertion_failure_proc;
}
- p("Panic", message, loc);
+ p("panic", message, loc);
}
@builtin
@@ -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) {
- array := (^mem.Raw_Dynamic_Array)(array_);
+ array := (^Raw_Dynamic_Array)(array_);
array.allocator = context.allocator;
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 {
- array := (^mem.Raw_Dynamic_Array)(array_);
+ array := (^Raw_Dynamic_Array)(array_);
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 {
- array := (^mem.Raw_Dynamic_Array)(array_);
+ array := (^Raw_Dynamic_Array)(array_);
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
if ok do array.len = len;
@@ -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,
items: rawptr, item_count: int, loc := #caller_location) -> int {
- array := (^mem.Raw_Dynamic_Array)(array_);
+ array := (^Raw_Dynamic_Array)(array_);
if items == nil do return 0;
if item_count <= 0 do return 0;
@@ -771,13 +794,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
assert(array.data != nil);
data := uintptr(array.data) + uintptr(elem_size*array.len);
- mem.copy(rawptr(data), items, elem_size * item_count);
+ mem_copy(rawptr(data), items, elem_size * item_count);
array.len += item_count;
return array.len;
}
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
- array := (^mem.Raw_Dynamic_Array)(array_);
+ array := (^Raw_Dynamic_Array)(array_);
ok := true;
if array.cap <= array.len+1 {
@@ -800,15 +823,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
// Map
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
- header := Map_Header{m = (^mem.Raw_Map)(m)};
+ header := Map_Header{m = (^Raw_Map)(m)};
Entry :: struct {
key: Map_Key,
next: int,
value: V,
- }
+ };
- _, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
- header.is_key_string = is_string;
+ header.is_key_string = intrinsics.type_is_string(K);
header.entry_size = int(size_of(Entry));
header.entry_align = int(align_of(Entry));
header.value_offset = uintptr(offset_of(Entry, value));
@@ -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 {
key := k;
map_key: Map_Key;
- ti := type_info_base_without_enum(type_info_of(K));
- switch _ in ti.variant {
- case Type_Info_Integer:
- switch 8*size_of(key) {
- case 8: map_key.hash = u64(( ^u8)(&key)^);
- case 16: map_key.hash = u64(( ^u16)(&key)^);
- case 32: map_key.hash = u64(( ^u32)(&key)^);
- case 64: map_key.hash = u64(( ^u64)(&key)^);
- case: panic("Unhandled integer size");
- }
- case Type_Info_Rune:
+
+ T :: intrinsics.type_core_type(K);
+
+ when intrinsics.type_is_integer(T) {
+ sz :: 8*size_of(T);
+ when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
+ else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
+ else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
+ else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
+ else do #assert(false, "Unhandled integer size");
+ } else when intrinsics.type_is_rune(T) {
map_key.hash = u64((^rune)(&key)^);
- case Type_Info_Pointer:
+ } else when intrinsics.type_is_pointer(T) {
map_key.hash = u64(uintptr((^rawptr)(&key)^));
- case Type_Info_Float:
- switch 8*size_of(key) {
- case 32: map_key.hash = u64((^u32)(&key)^);
- case 64: map_key.hash = u64((^u64)(&key)^);
- case: panic("Unhandled float size");
- }
- case Type_Info_String:
+ } else when intrinsics.type_is_float(T) {
+ sz :: 8*size_of(T);
+ when sz == 32 do map_key.hash = u64((^u32)(&key)^);
+ else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
+ else do #assert(false, "Unhandled float size");
+ } else when intrinsics.type_is_string(T) {
+ #assert(T == string);
str := (^string)(&key)^;
map_key.hash = default_hash_string(str);
map_key.str = str;
- case:
- panic("Unhandled map key type");
+ } else {
+ #assert(false, "Unhandled map key type");
}
+
return map_key;
}
@@ -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 {
- array := (^mem.Raw_Slice)(array_);
+ array := (^Raw_Slice)(array_);
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 {
new_header: Map_Header = header;
- nm := mem.Raw_Map{};
+ nm := Raw_Map{};
nm.entries.allocator = m.entries.allocator;
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.next = fr.entry_index;
ndata := uintptr(e);
- mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
+ mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
}
@@ -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.key = key;
val := (^byte)(uintptr(e) + h.value_offset);
- mem.copy(val, value, h.value_size);
+ mem_copy(val, value, h.value_size);
}
if __dynamic_map_full(h) {
@@ -1054,7 +1077,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
} else {
old := __dynamic_map_get_entry(h, fr.entry_index);
end := __dynamic_map_get_entry(h, m.entries.len-1);
- mem.copy(old, end, entry_size);
+ mem_copy(old, end, entry_size);
if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin
index d4d7ab84d..164610ae6 100644
--- a/core/runtime/internal.odin
+++ b/core/runtime/internal.odin
@@ -1,9 +1,22 @@
package runtime
-import "core:mem"
import "core:os"
-import "core:unicode/utf8"
+mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
+ if src == nil do return dst;
+ // NOTE(bill): This _must_ be implemented like C's memmove
+ foreign _ {
+ when size_of(rawptr) == 8 {
+ @(link_name="llvm.memmove.p0i8.p0i8.i64")
+ llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
+ } else {
+ @(link_name="llvm.memmove.p0i8.p0i8.i32")
+ llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
+ }
+ }
+ llvm_memmove(dst, src, len, 1, false);
+ return dst;
+}
print_u64 :: proc(fd: os.Handle, x: u64) {
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 {
switch {
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 {
- 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); }
@@ -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; }
cstring_len :: proc "contextless" (s: cstring) -> int {
- n := 0;
- for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) {
- n += 1;
+ p0 := uintptr((^byte)(s));
+ p := p0;
+ for p != 0 && (^byte)(p)^ != 0 {
+ p += 1;
}
- return n;
+ return int(p - p0);
}
cstring_to_string :: proc "contextless" (s: cstring) -> string {
+ Raw_String :: struct {
+ data: ^byte,
+ len: int,
+ };
if s == nil do return "";
ptr := (^byte)(s);
n := cstring_len(s);
- return transmute(string)mem.Raw_String{ptr, n};
+ return transmute(string)Raw_String{ptr, n};
}
@@ -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); }
+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) {
@@ -358,8 +453,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
handle_error(file, line, column, from, to);
}
+
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
- return utf8.decode_rune_in_string(s);
+ // NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
+
+ @static accept_sizes := [256]u8{
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
+
+ 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
+ 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
+ 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
+ 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
+ 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
+ 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
+ 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
+ };
+ Accept_Range :: struct {lo, hi: u8};
+
+ @static accept_ranges := [5]Accept_Range{
+ {0x80, 0xbf},
+ {0xa0, 0xbf},
+ {0x80, 0x9f},
+ {0x90, 0xbf},
+ {0x80, 0x8f},
+ };
+
+ MASKX :: 0b0011_1111;
+ MASK2 :: 0b0001_1111;
+ MASK3 :: 0b0000_1111;
+ MASK4 :: 0b0000_0111;
+
+ LOCB :: 0b1000_0000;
+ HICB :: 0b1011_1111;
+
+
+ RUNE_ERROR :: '\ufffd';
+
+ n := len(s);
+ if n < 1 {
+ return RUNE_ERROR, 0;
+ }
+ s0 := s[0];
+ x := accept_sizes[s0];
+ if x >= 0xF0 {
+ mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
+ return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
+ }
+ sz := x & 7;
+ accept := accept_ranges[x>>4];
+ if n < int(sz) {
+ return RUNE_ERROR, 1;
+ }
+ b1 := s[1];
+ if b1 < accept.lo || accept.hi < b1 {
+ return RUNE_ERROR, 1;
+ }
+ if sz == 2 {
+ return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
+ }
+ b2 := s[2];
+ if b2 < LOCB || HICB < b2 {
+ return RUNE_ERROR, 1;
+ }
+ if sz == 3 {
+ return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
+ }
+ b3 := s[3];
+ if b3 < LOCB || HICB < b3 {
+ return RUNE_ERROR, 1;
+ }
+ return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
}
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
@@ -474,9 +645,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
r, i := real(x), imag(x);
return _sqrt_f64(r*r + i*i);
}
+abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
+ r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
+ return _sqrt_f32(r*r + i*i + j*j + k*k);
+}
+abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
+ r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
+ return _sqrt_f64(r*r + i*i + j*j + k*k);
+}
-
-quo_complex64 :: proc(n, m: complex64) -> complex64 {
+quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
e, f: f32;
if abs(real(m)) >= abs(imag(m)) {
@@ -494,7 +672,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
return complex(e, f);
}
-quo_complex128 :: proc(n, m: complex128) -> complex128 {
+quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
e, f: f64;
if abs(real(m)) >= abs(imag(m)) {
@@ -511,3 +689,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
return complex(e, f);
}
+
+mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
+ q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+ r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+ t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
+ t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
+ t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
+ t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
+
+ return quaternion(t0, t1, t2, t3);
+}
+
+mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
+ q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+ r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+ t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
+ t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
+ t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
+ t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
+
+ return quaternion(t0, t1, t2, t3);
+}
+
+quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
+ q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+ r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+ invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
+
+ t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
+ t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
+ t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
+ t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
+
+ return quaternion(t0, t1, t2, t3);
+}
+
+quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
+ q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+ r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+ invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
+
+ t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
+ t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
+ t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
+ t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
+
+ return quaternion(t0, t1, t2, t3);
+}
diff --git a/core/sort/sort.odin b/core/sort/sort.odin
index 3c8366def..86953d7dd 100644
--- a/core/sort/sort.odin
+++ b/core/sort/sort.odin
@@ -1,6 +1,7 @@
package sort
import "core:mem"
+import "intrinsics"
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil);
@@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
}
}
-bubble_sort :: proc(array: $A/[]$T) {
+bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
count := len(array);
init_j, last_j := 0, count-1;
@@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
quick_sort_proc(a[i:n], f);
}
-quick_sort :: proc(array: $A/[]$T) {
+quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
a := array;
n := len(a);
if n < 2 do return;
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
if M & 1 == 0 do copy(arr2, arr1);
}
-merge_sort :: proc(array: $A/[]$T) {
+merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
merge_slices :: proc(arr1, arr2, out: A) {
N1, N2 := len(arr1), len(arr2);
i, j := 0, 0;
diff --git a/core/decimal/decimal.odin b/core/strconv/decimal/decimal.odin
index 97c586635..15853c5a7 100644
--- a/core/decimal/decimal.odin
+++ b/core/strconv/decimal/decimal.odin
@@ -1,6 +1,6 @@
// Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else
-package decimal
+package strconv_decimal
Decimal :: struct {
digits: [384]byte, // big-endian digits
diff --git a/core/strconv/generic_float.odin b/core/strconv/generic_float.odin
index f0e43bcc9..24cbf3b15 100644
--- a/core/strconv/generic_float.odin
+++ b/core/strconv/generic_float.odin
@@ -1,6 +1,6 @@
package strconv
-using import "core:decimal"
+using import "decimal"
Int_Flag :: enum {
Prefix,
@@ -105,7 +105,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
Buffer :: struct {
b: []byte,
n: int,
- }
+ };
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin
index ac78f78dc..447178bc3 100644
--- a/core/strconv/strconv.odin
+++ b/core/strconv/strconv.odin
@@ -205,7 +205,11 @@ itoa :: proc(buf: []byte, i: int) -> string {
atoi :: proc(s: string) -> int {
return parse_int(s);
}
+atof :: proc(s: string) -> f64 {
+ return parse_f64(s);
+}
+ftoa :: append_float;
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size));
}
diff --git a/core/strings/builder.odin b/core/strings/builder.odin
index 68f1a7ceb..f7dac04ba 100644
--- a/core/strings/builder.odin
+++ b/core/strings/builder.odin
@@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) {
reserve(&b.buf, cap);
}
+reset_builder :: proc(b: ^Builder) {
+ clear(&b.buf);
+}
+
builder_from_slice :: proc(backing: []byte) -> Builder {
s := transmute(mem.Raw_Slice)backing;
d := mem.Raw_Dynamic_Array{
diff --git a/core/strings/strings.odin b/core/strings/strings.odin
index 8f9db86be..921e4f009 100644
--- a/core/strings/strings.odin
+++ b/core/strings/strings.odin
@@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
return string(b);
}
+@private
+_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
+ s, n := s_, n_;
+
+ if n == 0 {
+ return nil;
+ }
+
+ if sep == "" {
+ l := utf8.rune_count_in_string(s);
+ if n < 0 || n > l {
+ n = l;
+ }
+
+ res := make([dynamic]string, n, allocator);
+ for i := 0; i < n-1; i += 1 {
+ _, w := utf8.decode_rune_in_string(s);
+ res[i] = s[:w];
+ s = s[w:];
+ }
+ if n > 0 {
+ res[n-1] = s;
+ }
+ return res[:];
+ }
+
+ if n < 0 {
+ n = count(s, sep) + 1;
+ }
+
+ res := make([dynamic]string, n, allocator);
+
+ n -= 1;
+
+ i := 0;
+ for ; i < n; i += 1 {
+ m := index(s, sep);
+ if m < 0 {
+ break;
+ }
+ res[i] = s[:m+sep_save];
+ s = s[m+len(sep):];
+ }
+ res[i] = s;
+
+ return res[:i+1];
+}
+
+split :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
+ return _split(s, sep, 0, -1, allocator);
+}
+
+split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
+ return _split(s, sep, 0, n, allocator);
+}
+
+split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
+ return _split(s, sep, len(sep), -1, allocator);
+}
+
+split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
+ return _split(s, sep, len(sep), n, allocator);
+}
+
+
+
+
index_byte :: proc(s: string, c: byte) -> int {
for i := 0; i < len(s); i += 1 {
if s[i] == c do return i;
@@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
return -1;
}
+
+
+@private PRIME_RABIN_KARP :: 16777619;
+
index :: proc(s, substr: string) -> int {
+ hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
+ for i := 0; i < len(s); i += 1 {
+ hash = hash*PRIME_RABIN_KARP + u32(s[i]);
+ }
+ sq := u32(PRIME_RABIN_KARP);
+ for i := len(s); i > 0; i >>= 1 {
+ if (i & 1) != 0 {
+ pow *= sq;
+ }
+ sq *= sq;
+ }
+ return;
+ }
+
n := len(substr);
switch {
case n == 0:
@@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int {
return -1;
}
- for i := 0; i < len(s)-n+1; i += 1 {
- x := s[i:i+n];
- if x == substr {
+ hash, pow := hash_str_rabin_karp(substr);
+ h: u32;
+ for i := 0; i < n; i += 1 {
+ h = h*PRIME_RABIN_KARP + u32(s[i]);
+ }
+ if h == hash && s[:n] == substr {
+ return 0;
+ }
+ for i := n; i < len(s); /**/ {
+ h *= PRIME_RABIN_KARP;
+ h += u32(s[i]);
+ h -= pow * u32(s[i-n]);
+ i += 1;
+ if h == hash && s[i-n:i] == substr {
+ return i - n;
+ }
+ }
+ return -1;
+}
+
+last_index :: proc(s, substr: string) -> int {
+ hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
+ for i := len(s) - 1; i >= 0; i -= 1 {
+ hash = hash*PRIME_RABIN_KARP + u32(s[i]);
+ }
+ sq := u32(PRIME_RABIN_KARP);
+ for i := len(s); i > 0; i >>= 1 {
+ if (i & 1) != 0 {
+ pow *= sq;
+ }
+ sq *= sq;
+ }
+ return;
+ }
+
+ n := len(substr);
+ switch {
+ case n == 0:
+ return len(s);
+ case n == 1:
+ return last_index_byte(s, substr[0]);
+ case n == len(s):
+ return substr == s ? 0 : -1;
+ case n > len(s):
+ return -1;
+ }
+
+ hash, pow := hash_str_rabin_karp_reverse(substr);
+ last := len(s) - n;
+ h: u32;
+ for i := len(s)-1; i >= last; i -= 1 {
+ h = h*PRIME_RABIN_KARP + u32(s[i]);
+ }
+ if h == hash && s[last:] == substr {
+ return last;
+ }
+
+ for i := last-1; i >= 0; i -= 1 {
+ h *= PRIME_RABIN_KARP;
+ h += u32(s[i]);
+ h -= pow * u32(s[i+n]);
+ if h == hash && s[i:i+n] == substr {
return i;
}
}
diff --git a/core/sys/essence_linker_userland64.ld b/core/sys/essence_linker_userland64.ld
deleted file mode 100644
index 5f6d92791..000000000
--- a/core/sys/essence_linker_userland64.ld
+++ /dev/null
@@ -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)
- }
-}
diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin
index 036fc016a..f647ab7e0 100644
--- a/core/sys/win32/kernel32.odin
+++ b/core/sys/win32/kernel32.odin
@@ -23,7 +23,7 @@ foreign kernel32 {
@(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
@(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
- @(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
+ @(link_name="Sleep") sleep :: proc(ms: u32) ---;
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---;
diff --git a/core/sys/win32/user32.odin b/core/sys/win32/user32.odin
index b8969faf3..5165d9389 100644
--- a/core/sys/win32/user32.odin
+++ b/core/sys/win32/user32.odin
@@ -182,7 +182,7 @@ foreign user32 {
@(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
- @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
+ @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---;
@(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---;
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
diff --git a/core/time/time_osx.odin b/core/time/time_darwin.odin
index fd499d1ce..fd499d1ce 100644
--- a/core/time/time_osx.odin
+++ b/core/time/time_darwin.odin
diff --git a/core/time/time_essence.odin b/core/time/time_essence.odin
new file mode 100644
index 000000000..11713d84b
--- /dev/null
+++ b/core/time/time_essence.odin
@@ -0,0 +1,2 @@
+package time
+IS_SUPPORTED :: false;
diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin
index 31fbca769..f6bfdd678 100644
--- a/core/time/time_windows.odin
+++ b/core/time/time_windows.odin
@@ -20,5 +20,5 @@ now :: proc() -> Time {
sleep :: proc(d: Duration) {
- win32.sleep(i32(d/Millisecond));
+ win32.sleep(u32(d/Millisecond));
}
diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin
index 33cb48e1c..bbf3994cd 100644
--- a/core/unicode/utf8/utf8.odin
+++ b/core/unicode/utf8/utf8.odin
@@ -41,23 +41,17 @@ accept_ranges := [5]Accept_Range{
};
accept_sizes := [256]u8{
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
-
- 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
- 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
- 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
- 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
- 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
- 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
- 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
+ 0x00..0x7f = 0xf0,
+ 0x80..0xc1 = 0xf1,
+ 0xc2..0xdf = 0x02,
+ 0xe0 = 0x13,
+ 0xe1..0xec = 0x03,
+ 0xed = 0x23,
+ 0xee..0xef = 0x03,
+ 0xf0 = 0x34,
+ 0xf1..0xf3 = 0x04,
+ 0xf4 = 0x44,
+ 0xf5..0xff = 0xf1,
};
encode_rune :: proc(c: rune) -> ([4]u8, int) {
@@ -167,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
return r, size;
}
+rune_at_pos :: proc(s: string, pos: int) -> rune {
+ if pos < 0 {
+ return RUNE_ERROR;
+ }
+ i := 0;
+ for r in s {
+ if i == pos {
+ return r;
+ }
+ i += 1;
+ }
+ return RUNE_ERROR;
+}
+rune_string_at_pos :: proc(s: string, pos: int) -> string {
+ if pos < 0 {
+ return "";
+ }
+
+ i := 0;
+ for c, offset in s {
+ if i == pos {
+ w := rune_size(c);
+ return s[offset:][:w];
+ }
+ i += 1;
+ }
+ return "";
+}
+rune_at :: proc(s: string, byte_index: int) -> rune {
+ r, _ := decode_rune_in_string(s[byte_index:]);
+ return r;
+}
+
+// Returns the byte position of rune at position pos in s with an optional start byte position.
+// Returns -1 if it runs out of the string.
+rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
+ if pos < 0 {
+ return -1;
+ }
+
+ i := 0;
+ for _, offset in s[start:] {
+ if i == pos {
+ return offset+start;
+ }
+ i += 1;
+ }
+ return -1;
+}
valid_rune :: proc(r: rune) -> bool {
if r < 0 {
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin
index 206fa4a2d..4d14973f6 100644
--- a/examples/demo/demo.odin
+++ b/examples/demo/demo.odin
@@ -3,14 +3,34 @@ package main
import "core:fmt"
import "core:mem"
import "core:os"
+import "core:reflect"
+import "intrinsics"
when os.OS == "windows" {
import "core:thread"
}
-@(link_name="general_stuff")
-general_stuff :: proc() {
- fmt.println("# general_stuff");
+/*
+ The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
+ * simplicity
+ * high performance
+ * built for modern systems
+ * joy of programming
+
+ # Installing Odin
+ Getting Started - https://odin-lang.org/docs/install/
+ Instructions for downloading and install the Odin compiler and libraries.
+
+ # Learning Odin
+ Overview of Odin - https://odin-lang.org/docs/overview/
+ An overview of the Odin programming language.
+ Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/
+ Answers to common questions about Odin.
+*/
+
+@(link_name="extra_general_stuff")
+extra_general_stuff :: proc() {
+ fmt.println("# extra_general_stuff");
{ // `do` for inline statements rather than block
foo :: proc() do fmt.println("Foo!");
if false do foo();
@@ -30,14 +50,12 @@ general_stuff :: proc() {
i := i32(137);
ptr := &i;
- _ = (^f32)(ptr);
+ _ = (^f32)(ptr); // Call-based syntax
// ^f32(ptr) == ^(f32(ptr))
- _ = cast(^f32)ptr;
+ _ = cast(^f32)ptr; // Operator-based syntax
_ = (^f32)(ptr)^;
_ = (cast(^f32)ptr)^;
-
- // Questions: Should there be two ways to do it?
}
/*
@@ -50,7 +68,7 @@ general_stuff :: proc() {
Foo :: struct {
x: int,
b: bool,
- }
+ };
f := Foo{137, true};
x, b := expand_to_tuple(f);
fmt.println(f);
@@ -191,8 +209,8 @@ union_type :: proc() {
}
}
- Vector3 :: struct {x, y, z: f32};
- Quaternion :: struct {x, y, z, w: f32};
+ Vector3 :: distinct [3]f32;
+ Quaternion :: distinct quaternion128;
// More realistic examples
{
@@ -209,18 +227,18 @@ union_type :: proc() {
orientation: Quaternion,
derived: any,
- }
+ };
Frog :: struct {
using entity: Entity,
jump_height: f32,
- }
+ };
Monster :: struct {
using entity: Entity,
is_robot: bool,
is_zombie: bool,
- }
+ };
// See `parametric_polymorphism` procedure for details
new_entity :: proc($T: typeid) -> ^Entity {
@@ -254,18 +272,18 @@ union_type :: proc() {
orientation: Quaternion,
derived: union {Frog, Monster},
- }
+ };
Frog :: struct {
using entity: ^Entity,
jump_height: f32,
- }
+ };
Monster :: struct {
using entity: ^Entity,
is_robot: bool,
is_zombie: bool,
- }
+ };
// See `parametric_polymorphism` procedure for details
new_entity :: proc($T: typeid) -> ^Entity {
@@ -302,17 +320,17 @@ union_type :: proc() {
/*
Entity :: struct {
- ..
+ ...
derived: union{^Frog, ^Monster},
}
Frog :: struct {
using entity: Entity,
- ..
+ ...
}
Monster :: struct {
using entity: Entity,
- ..
+ ...
}
new_entity :: proc(T: type) -> ^Entity {
@@ -325,7 +343,7 @@ union_type :: proc() {
}
parametric_polymorphism :: proc() {
- fmt.println("# parametric_polymorphism");
+ fmt.println("\n# parametric_polymorphism");
print_value :: proc(value: $T) {
fmt.printf("print_value: %T %v\n", value, value);
@@ -383,13 +401,13 @@ parametric_polymorphism :: proc() {
hash: u32,
key: Key,
value: Value,
- }
+ };
TABLE_SIZE_MIN :: 32;
Table :: struct(Key, Value: typeid) {
count: int,
allocator: mem.Allocator,
slots: []Table_Slot(Key, Value),
- }
+ };
// Only allow types that are specializations of a (polymorphic) slice
make_slice :: proc($T: typeid/[]$E, len: int) -> T {
@@ -513,7 +531,7 @@ parametric_polymorphism :: proc() {
Foo1,
Foo2,
Foo3,
- }
+ };
Para_Union :: union(T: typeid) {T, Error};
r: Para_Union(int);
fmt.println(typeid_of(type_of(r)));
@@ -521,7 +539,7 @@ parametric_polymorphism :: proc() {
fmt.println(r);
r = 123;
fmt.println(r);
- r = Error.Foo0;
+ r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
fmt.println(r);
}
@@ -543,6 +561,30 @@ parametric_polymorphism :: proc() {
for v, i in array {
assert(v == T(i*i));
}
+
+ // Matrix multiplication
+ mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) {
+ for i in 0..<M {
+ for j in 0..<P {
+ for k in 0..<N {
+ c[i][j] += a[i][k] * b[k][j];
+ }
+ }
+ }
+ return;
+ }
+
+ x := [2][3]f32{
+ {1, 2, 3},
+ {3, 2, 1},
+ };
+ y := [3][2]f32{
+ {0, 8},
+ {6, 2},
+ {8, 4},
+ };
+ z := mul(x, y);
+ assert(z == {{36, 24}, {20, 32}});
}
}
@@ -560,7 +602,7 @@ prefix_table := [?]string{
threading_example :: proc() {
when os.OS == "windows" {
- fmt.println("# threading_example");
+ fmt.println("\n# threading_example");
worker_proc :: proc(t: ^thread.Thread) -> int {
for iteration in 1..5 {
@@ -600,7 +642,7 @@ threading_example :: proc() {
}
array_programming :: proc() {
- fmt.println("# array_programming");
+ fmt.println("\n# array_programming");
{
a := [3]f32{1, 2, 3};
b := [3]f32{5, 6, 7};
@@ -645,7 +687,7 @@ array_programming :: proc() {
}
named_proc_return_parameters :: proc() {
- fmt.println("# named proc return parameters");
+ fmt.println("\n# named proc return parameters");
foo0 :: proc() -> int {
return 123;
@@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() {
using_enum :: proc() {
- fmt.println("# using enum");
+ fmt.println("\n# using enum");
using Foo :: enum {A, B, C};
@@ -679,25 +721,25 @@ using_enum :: proc() {
}
map_type :: proc() {
- fmt.println("# map type");
+ fmt.println("\n# map type");
// enums of type u16, u32, i16 & i32 also work
Enum_u8 :: enum u8 {
A = 0,
B = 1 << 8 - 1,
- }
+ };
Enum_u64 :: enum u64 {
A = 0,
B = 1 << 64 - 1,
- }
+ };
Enum_i8 :: enum i8 {
A = 0,
B = -(1 << 7),
- }
+ };
Enum_i64 :: enum i64 {
A = 0,
B = -(1 << 63),
- }
+ };
map_u8: map[Enum_u8]u8;
map_u8[Enum_u8.A] = u8(Enum_u8.B);
@@ -721,7 +763,7 @@ map_type :: proc() {
demo_struct :: struct {
member: Enum_i64,
- }
+ };
map_string: map[string]demo_struct;
map_string["Hellope!"] = demo_struct{Enum_i64.B};
@@ -734,7 +776,7 @@ map_type :: proc() {
}
implicit_selector_expression :: proc() {
- fmt.println("# implicit selector expression");
+ fmt.println("\n# implicit selector expression");
Foo :: enum {A, B, C};
@@ -762,7 +804,7 @@ implicit_selector_expression :: proc() {
}
explicit_procedure_overloading :: proc() {
- fmt.println("# explicit procedure overloading");
+ fmt.println("\n# explicit procedure overloading");
add_ints :: proc(a, b: int) -> int {
x := a + b;
@@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() {
}
complete_switch :: proc() {
- fmt.println("# complete_switch");
+ fmt.println("\n# complete_switch");
{ // enum
using Foo :: enum {
A,
B,
C,
D,
- }
+ };
b := Foo.B;
f := Foo.A;
@@ -829,6 +871,8 @@ complete_switch :: proc() {
}
cstring_example :: proc() {
+ fmt.println("\n# cstring_example");
+
W :: "Hellope";
X :: cstring(W);
Y :: string(X);
@@ -860,6 +904,8 @@ deprecated_attribute :: proc() {
}
bit_set_type :: proc() {
+ fmt.println("\n# bit_set_type");
+
{
using Day :: enum {
Sunday,
@@ -869,7 +915,7 @@ bit_set_type :: proc() {
Thursday,
Friday,
Saturday,
- }
+ };
Days :: distinct bit_set[Day];
WEEKEND :: Days{Sunday, Saturday};
@@ -921,6 +967,8 @@ bit_set_type :: proc() {
}
diverging_procedures :: proc() {
+ fmt.println("\n# diverging_procedures");
+
// Diverging procedures may never return
foo :: proc() -> ! {
fmt.println("I'm a diverging procedure");
@@ -930,6 +978,8 @@ diverging_procedures :: proc() {
}
deferred_procedure_associations :: proc() {
+ fmt.println("\n# deferred_procedure_associations");
+
@(deferred_out=closure)
open :: proc(s: string) -> bool {
fmt.println(s);
@@ -945,9 +995,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() {
when true {
- general_stuff();
+ extra_general_stuff();
union_type();
parametric_polymorphism();
threading_example();
@@ -963,5 +1251,11 @@ main :: proc() {
bit_set_type();
diverging_procedures();
deferred_procedure_associations();
+ reflection();
+ quaternions();
+ inline_for_statement();
+ where_clauses();
+ ranged_fields_for_array_compound_literals();
}
}
+
diff --git a/misc/logo-slim.png b/misc/logo-slim.png
index 6e33dc6b8..ed9b6061e 100644
--- a/misc/logo-slim.png
+++ b/misc/logo-slim.png
Binary files differ
diff --git a/examples/old_demos/demo001.odin b/misc/old_demos/demo001.odin
index a3aea1cb7..a3aea1cb7 100644
--- a/examples/old_demos/demo001.odin
+++ b/misc/old_demos/demo001.odin
diff --git a/examples/old_demos/demo002.odin b/misc/old_demos/demo002.odin
index a790aadf3..a790aadf3 100644
--- a/examples/old_demos/demo002.odin
+++ b/misc/old_demos/demo002.odin
diff --git a/examples/old_demos/demo004.odin b/misc/old_demos/demo004.odin
index c9acc9a15..c9acc9a15 100644
--- a/examples/old_demos/demo004.odin
+++ b/misc/old_demos/demo004.odin
diff --git a/examples/old_demos/demo005.odin b/misc/old_demos/demo005.odin
index c8273b03b..c8273b03b 100644
--- a/examples/old_demos/demo005.odin
+++ b/misc/old_demos/demo005.odin
diff --git a/examples/old_demos/demo006.odin b/misc/old_demos/demo006.odin
index c2f64151b..c2f64151b 100644
--- a/examples/old_demos/demo006.odin
+++ b/misc/old_demos/demo006.odin
diff --git a/examples/old_demos/demo007.odin b/misc/old_demos/demo007.odin
index d19446ecb..d19446ecb 100644
--- a/examples/old_demos/demo007.odin
+++ b/misc/old_demos/demo007.odin
diff --git a/examples/old_demos/demo008.odin b/misc/old_demos/demo008.odin
index 7916cd5e9..7916cd5e9 100644
--- a/examples/old_demos/demo008.odin
+++ b/misc/old_demos/demo008.odin
diff --git a/examples/old_demos/old_runtime.odin b/misc/old_demos/old_runtime.odin
index e605e7820..e605e7820 100644
--- a/examples/old_demos/old_runtime.odin
+++ b/misc/old_demos/old_runtime.odin
diff --git a/examples/old_stuff/demo_backup.odin b/misc/old_stuff/demo_backup.odin
index b8bbbb02d..b8bbbb02d 100644
--- a/examples/old_stuff/demo_backup.odin
+++ b/misc/old_stuff/demo_backup.odin
diff --git a/misc/shell.bat b/misc/shell.bat
index 36db84570..85a7949c6 100644
--- a/misc/shell.bat
+++ b/misc/shell.bat
@@ -1,8 +1,8 @@
@echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
-call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
-rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
+rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 992443f7c..5d1c07a67 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -2,7 +2,7 @@ enum TargetOsKind {
TargetOs_Invalid,
TargetOs_windows,
- TargetOs_osx,
+ TargetOs_darwin,
TargetOs_linux,
TargetOs_essence,
@@ -30,7 +30,7 @@ enum TargetEndianKind {
String target_os_names[TargetOs_COUNT] = {
str_lit(""),
str_lit("windows"),
- str_lit("osx"),
+ str_lit("darwin"),
str_lit("linux"),
str_lit("essence"),
};
@@ -55,9 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
-String const ODIN_VERSION = str_lit("0.10.1");
-String cross_compile_target = str_lit("");
-String cross_compile_lib_dir = str_lit("");
+String const ODIN_VERSION = str_lit("0.10.2");
@@ -66,6 +64,7 @@ struct TargetMetrics {
TargetArchKind arch;
isize word_size;
isize max_align;
+ String target_triplet;
};
@@ -109,6 +108,7 @@ struct BuildContext {
bool has_resource;
String opt_flags;
String llc_flags;
+ String target_triplet;
String link_flags;
bool is_dll;
bool generate_docs;
@@ -121,6 +121,7 @@ struct BuildContext {
bool no_crt;
bool use_lld;
bool vet;
+ bool cross_compiling;
QueryDataSetSettings query_data_set_settings;
@@ -135,18 +136,19 @@ struct BuildContext {
gb_global BuildContext build_context = {0};
-
gb_global TargetMetrics target_windows_386 = {
TargetOs_windows,
TargetArch_386,
4,
8,
+ str_lit("i686-pc-windows"),
};
gb_global TargetMetrics target_windows_amd64 = {
TargetOs_windows,
TargetArch_amd64,
8,
16,
+ str_lit("x86_64-pc-windows-gnu"),
};
gb_global TargetMetrics target_linux_386 = {
@@ -154,23 +156,47 @@ gb_global TargetMetrics target_linux_386 = {
TargetArch_386,
4,
8,
+ str_lit("i686-pc-linux-gnu"),
};
gb_global TargetMetrics target_linux_amd64 = {
TargetOs_linux,
TargetArch_amd64,
8,
16,
+ str_lit("x86_64-pc-linux-gnu"),
+};
+
+gb_global TargetMetrics target_darwin_amd64 = {
+ TargetOs_darwin,
+ TargetArch_amd64,
+ 8,
+ 16,
+ str_lit("x86_64-apple-darwin"),
};
-gb_global TargetMetrics target_osx_amd64 = {
- TargetOs_osx,
+gb_global TargetMetrics target_essence_amd64 = {
+ TargetOs_essence,
TargetArch_amd64,
8,
16,
+ str_lit("x86_64-pc-none-elf"),
};
+struct NamedTargetMetrics {
+ String name;
+ TargetMetrics *metrics;
+};
+gb_global NamedTargetMetrics named_targets[] = {
+ { str_lit("essence_amd64"), &target_essence_amd64 },
+ { str_lit("darwin_amd64"), &target_darwin_amd64 },
+ { str_lit("linux_386"), &target_linux_386 },
+ { str_lit("linux_amd64"), &target_linux_amd64 },
+ { str_lit("windows_386"), &target_windows_386 },
+ { str_lit("windows_amd64"), &target_windows_amd64 },
+};
+NamedTargetMetrics *selected_target_metrics;
TargetOsKind get_target_os_from_string(String str) {
for (isize i = 0; i < TargetOs_COUNT; i++) {
@@ -522,7 +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;
gb_affinity_init(&bc->affinity);
@@ -540,7 +566,7 @@ void init_build_context(void) {
#if defined(GB_SYSTEM_WINDOWS)
metrics = target_windows_amd64;
#elif defined(GB_SYSTEM_OSX)
- metrics = target_osx_amd64;
+ metrics = target_darwin_amd64;
#else
metrics = target_linux_amd64;
#endif
@@ -554,8 +580,9 @@ void init_build_context(void) {
#endif
#endif
- if (cross_compile_target.len) {
- bc->ODIN_OS = cross_compile_target;
+ if (cross_target) {
+ metrics = *cross_target;
+ bc->cross_compiling = true;
}
GB_ASSERT(metrics.os != TargetOs_Invalid);
@@ -573,6 +600,7 @@ void init_build_context(void) {
bc->max_align = metrics.max_align;
bc->link_flags = str_lit(" ");
bc->opt_flags = str_lit(" ");
+ bc->target_triplet = metrics.target_triplet;
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
@@ -590,7 +618,7 @@ void init_build_context(void) {
case TargetOs_windows:
bc->link_flags = str_lit("/machine:x64 ");
break;
- case TargetOs_osx:
+ case TargetOs_darwin:
break;
case TargetOs_linux:
bc->link_flags = str_lit("-arch x86-64 ");
@@ -603,7 +631,7 @@ void init_build_context(void) {
case TargetOs_windows:
bc->link_flags = str_lit("/machine:x86 ");
break;
- case TargetOs_osx:
+ case TargetOs_darwin:
gb_printf_err("Unsupported architecture\n");
gb_exit(1);
break;
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 1a6fad918..ebfc29899 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
}
if (operand->mode == Addressing_Type) {
- gbString t = type_to_string(operand->type);
- error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
- gb_string_free(t);
- e->type = operand->type;
- return nullptr;
+ if (e->type != nullptr && is_type_typeid(e->type)) {
+ add_type_info_type(ctx, operand->type);
+ add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
+ return e->type;
+ } else {
+ gbString t = type_to_string(operand->type);
+ defer (gb_string_free(t));
+ error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
+ if (e->type == nullptr) {
+ error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string));
+ }
+ e->type = operand->type;
+ return nullptr;
+ }
}
@@ -112,7 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands[i].mode == Addressing_Invalid) {
- rhs_count--;
+ // TODO(bill): Should I ignore invalid parameters?
+ // rhs_count--;
}
}
@@ -239,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
}
-void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
+void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
GB_ASSERT(e->type == nullptr);
DeclInfo *decl = decl_info_of_entity(e);
@@ -247,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
}
-
- bool is_distinct = is_type_distinct(type_expr);
- Ast *te = remove_type_alias_clutter(type_expr);
+ bool is_distinct = is_type_distinct(init_expr);
+ Ast *te = remove_type_alias_clutter(init_expr);
e->type = t_invalid;
String name = e->token.string;
Type *named = alloc_type_named(name, nullptr, e);
@@ -265,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
named->Named.base = base_type(bt);
if (is_distinct && is_type_typeid(e->type)) {
- error(type_expr, "'distinct' cannot be applied to 'typeid'");
+ error(init_expr, "'distinct' cannot be applied to 'typeid'");
is_distinct = false;
}
if (!is_distinct) {
@@ -274,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
e->TypeName.is_type_alias = true;
}
+
+ if (decl->type_expr != nullptr) {
+ Type *t = check_type(ctx, decl->type_expr);
+ if (t != nullptr && !is_type_typeid(t)) {
+ Operand operand = {};
+ operand.mode = Addressing_Type;
+ operand.type = e->type;
+ operand.expr = init_expr;
+ check_assignment(ctx, &operand, t, str_lit("constant declaration"));
+ }
+ }
+
+
// using decl
if (decl->is_using) {
// NOTE(bill): Must be an enum declaration
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
switch (operand.mode) {
case Addressing_Type: {
+ if (e->type != nullptr && !is_type_typeid(e->type)) {
+ check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
+ }
+
e->kind = Entity_TypeName;
e->type = nullptr;
- DeclInfo *d = ctx->decl;
- if (d->type_expr != nullptr) {
- error(e->token, "A type declaration cannot have an type parameter");
- }
- d->type_expr = d->init_expr;
- check_type_decl(ctx, e, d->type_expr, named_type);
+ check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
return;
}
@@ -654,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export;
- bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
if (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 ||
@@ -714,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
- if (pt->result_count == 0 && is_require_results) {
- error(pl->type, "'#require_results' is not needed on a procedure with no results");
+ if (pt->result_count == 0 && ac.require_results) {
+ error(pl->type, "'require_results' is not needed on a procedure with no results");
} else {
- pt->require_results = is_require_results;
+ pt->require_results = ac.require_results;
}
if (ac.link_name.len > 0) {
@@ -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->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;
DeclInfo *decl = decl_info_of_entity(e);
+ GB_ASSERT(decl == ctx->decl);
if (decl != nullptr) {
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
}
@@ -936,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
ptr_set_destroy(&entity_set);
-
for_array(j, pge->entities) {
Entity *p = pge->entities[j];
if (p->type == t_invalid) {
@@ -962,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
defer (end_error_block());
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
- switch (kind) {
+ bool both_have_where_clauses = false;
+ if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
+ GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
+ GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
+ auto pl = &p->decl_info->proc_lit->ProcLit;
+ auto ql = &q->decl_info->proc_lit->ProcLit;
+
+ // Allow collisions if the procedures both have 'where' clauses and are both polymorphic
+ bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
+ bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
+ both_have_where_clauses = pw && qw;
+ }
+
+ if (!both_have_where_clauses) switch (kind) {
case ProcOverload_Identical:
- error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
// case ProcOverload_CallingConvention:
- // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+ // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
// is_invalid = true;
// break;
case ProcOverload_ParamVariadic:
- error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
case ProcOverload_ResultCount:
case ProcOverload_ResultTypes:
- error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true;
break;
case ProcOverload_Polymorphic:
#if 0
- error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
+ error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
is_invalid = true;
#endif
break;
@@ -1051,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
switch (e->kind) {
case Entity_Variable:
- check_var_decl(&c, e, d->type_expr, d->init_expr);
+ check_global_variable_decl(&c, e, d->type_expr, d->init_expr);
break;
case Entity_Constant:
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName: {
- check_type_decl(&c, e, d->type_expr, named_type);
+ check_type_decl(&c, e, d->init_expr, named_type);
break;
}
case Entity_Procedure:
@@ -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) {
if (body == nullptr) {
@@ -1098,76 +1136,117 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
ctx->curr_proc_decl = decl;
ctx->curr_proc_sig = type;
- GB_ASSERT(type->kind == Type_Proc);
- if (type->Proc.param_count > 0) {
- TypeTuple *params = &type->Proc.params->Tuple;
- for_array(i, params->variables) {
- Entity *e = params->variables[i];
- if (e->kind != Entity_Variable) {
- continue;
- }
- if (!(e->flags & EntityFlag_Using)) {
- continue;
- }
- bool is_immutable = e->Variable.is_immutable;
- bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
- String name = e->token.string;
- Type *t = base_type(type_deref(e->type));
- if (t->kind == Type_Struct) {
- Scope *scope = t->Struct.scope;
- if (scope == nullptr) {
- scope = scope_of_node(t->Struct.node);
+ ast_node(bs, BlockStmt, body);
+
+ Array<ProcUsingVar> using_entities = {};
+ using_entities.allocator = heap_allocator();
+ defer (array_free(&using_entities));
+
+ {
+ GB_ASSERT(type->kind == Type_Proc);
+ if (type->Proc.param_count > 0) {
+ TypeTuple *params = &type->Proc.params->Tuple;
+ for_array(i, params->variables) {
+ Entity *e = params->variables[i];
+ if (e->kind != Entity_Variable) {
+ continue;
+ }
+ if (!(e->flags & EntityFlag_Using)) {
+ continue;
}
- GB_ASSERT(scope != nullptr);
- for_array(i, scope->elements.entries) {
- Entity *f = scope->elements.entries[i].value;
- if (f->kind == Entity_Variable) {
- Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
- uvar->Variable.is_immutable = is_immutable;
- if (is_value) uvar->flags |= EntityFlag_Value;
-
- Entity *prev = scope_insert(ctx->scope, uvar);
- if (prev != nullptr) {
- error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
- break;
+ bool is_immutable = e->Variable.is_immutable;
+ bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
+ String name = e->token.string;
+ Type *t = base_type(type_deref(e->type));
+ if (t->kind == Type_Struct) {
+ Scope *scope = t->Struct.scope;
+ if (scope == nullptr) {
+ scope = scope_of_node(t->Struct.node);
+ }
+ GB_ASSERT(scope != nullptr);
+ for_array(i, scope->elements.entries) {
+ Entity *f = scope->elements.entries[i].value;
+ if (f->kind == Entity_Variable) {
+ Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
+ uvar->Variable.is_immutable = is_immutable;
+ if (is_value) uvar->flags |= EntityFlag_Value;
+
+ ProcUsingVar puv = {e, uvar};
+ array_add(&using_entities, puv);
+
}
}
+ } else {
+ error(e->token, "'using' can only be applied to variables of type struct");
+ break;
}
- } else {
- error(e->token, "'using' can only be applied to variables of type struct");
- break;
}
}
}
- ast_node(bs, BlockStmt, body);
- // check_open_scope(ctx, body);
- check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
- if (type->Proc.result_count > 0) {
- if (!check_is_terminating(body)) {
- if (token.kind == Token_Ident) {
- error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
- } else {
- // NOTE(bill): Anonymous procedure (lambda)
- error(bs->close, "Missing return statement at the end of the procedure");
+
+ for_array(i, using_entities) {
+ Entity *e = using_entities[i].e;
+ Entity *uvar = using_entities[i].uvar;
+ Entity *prev = scope_insert(ctx->scope, uvar);
+ if (prev != nullptr) {
+ error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
+ break;
+ }
+ }
+
+
+ bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
+ if (!where_clause_ok) {
+ // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
+ return;
+ }
+
+ check_open_scope(ctx, body);
+ {
+ for_array(i, using_entities) {
+ Entity *e = using_entities[i].e;
+ Entity *uvar = using_entities[i].uvar;
+ Entity *prev = scope_insert(ctx->scope, uvar);
+ // NOTE(bill): Don't err here
+ }
+
+ check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
+
+ if (type->Proc.result_count > 0) {
+ if (!check_is_terminating(body)) {
+ if (token.kind == Token_Ident) {
+ error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
+ } else {
+ // NOTE(bill): Anonymous procedure (lambda)
+ error(bs->close, "Missing return statement at the end of the procedure");
+ }
}
}
}
- // check_close_scope(ctx);
+ check_close_scope(ctx);
check_scope_usage(ctx->checker, ctx->scope);
+#if 1
if (decl->parent != nullptr) {
- // NOTE(bill): Add the dependencies from the procedure literal (lambda)
- for_array(i, decl->deps.entries) {
- Entity *e = decl->deps.entries[i].ptr;
- ptr_set_add(&decl->parent->deps, e);
- }
- for_array(i, decl->type_info_deps.entries) {
- Type *t = decl->type_info_deps.entries[i].ptr;
- ptr_set_add(&decl->parent->type_info_deps, t);
+ Scope *ps = decl->parent->scope;
+ if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
+ return;
+ } else {
+ // NOTE(bill): Add the dependencies from the procedure literal (lambda)
+ // But only at the procedure level
+ for_array(i, decl->deps.entries) {
+ Entity *e = decl->deps.entries[i].ptr;
+ ptr_set_add(&decl->parent->deps, e);
+ }
+ for_array(i, decl->type_info_deps.entries) {
+ Type *t = decl->type_info_deps.entries[i].ptr;
+ ptr_set_add(&decl->parent->type_info_deps, t);
+ }
}
}
+#endif
}
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 4c5ca2348..fae38fa01 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -62,7 +62,7 @@ Type * make_optional_ok_type (Type *value);
void check_type_decl (CheckerContext *c, Entity *e, Ast *type_expr, Type *def);
Entity * check_selector (CheckerContext *c, Operand *operand, Ast *node, Type *type_hint);
Entity * check_ident (CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name);
-Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array<Operand> ordered_operands);
+Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure);
void check_not_tuple (CheckerContext *c, Operand *operand);
void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type);
gbString expr_to_string (Ast *expression);
@@ -89,8 +89,8 @@ Type * check_init_variable (CheckerContext *c, Entity *e, Operand *
Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc);
Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc);
bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type);
-void set_procedure_abi_types(CheckerContext *c, Type *type);
-
+void set_procedure_abi_types(gbAllocator a, Type *type);
+void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type);
Entity *entity_from_expr(Ast *expr) {
expr = unparen_expr(expr);
@@ -159,7 +159,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0
src = base_type(src);
if (!is_type_struct(src)) {
- return false;
+ return 0;
}
for_array(i, src->Struct.fields) {
@@ -442,6 +442,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
}
if (operand->mode == Addressing_Type) {
+ if (is_type_typeid(type)) {
+ add_type_info_type(c, operand->type);
+ return 4;
+ }
return -1;
}
@@ -497,6 +501,14 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
if (is_type_complex(dst)) {
return 1;
}
+ if (is_type_quaternion(dst)) {
+ return 2;
+ }
+ break;
+ case Basic_UntypedQuaternion:
+ if (is_type_quaternion(dst)) {
+ return 1;
+ }
break;
}
}
@@ -664,17 +676,6 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
return;
}
- #if 0
- if (operand->mode == Addressing_Type) {
- Type *t = base_type(type);
- if (t->kind == Type_Pointer &&
- t->Pointer.elem == t_type_info) {
- add_type_info_type(c, type);
- return;
- }
- }
- #endif
-
if (is_type_untyped(operand->type)) {
Type *target_type = type;
if (type == nullptr || is_type_any(type)) {
@@ -747,7 +748,12 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
return;
}
- if (!check_is_assignable_to(c, operand, type)) {
+ if (check_is_assignable_to(c, operand, type)) {
+ if (operand->mode == Addressing_Type && is_type_typeid(type)) {
+ add_type_info_type(c, operand->type);
+ add_type_and_value(c->info, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type));
+ }
+ } else {
gbString expr_str = expr_to_string(operand->expr);
gbString op_type_str = type_to_string(operand->type);
gbString type_str = type_to_string(type);
@@ -778,6 +784,7 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
op_type_str,
type_str,
LIT(context_name));
+ check_assignment_error_suggestion(c, operand, type);
break;
}
operand->mode = Addressing_Invalid;
@@ -956,7 +963,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
}
if (modify_type) {
- set_procedure_abi_types(c, source);
+ set_procedure_abi_types(c->allocator, source);
}
return true;
@@ -1438,7 +1445,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
ExactValue imag = exact_value_imag(v);
if (real.kind != ExactValue_Invalid &&
imag.kind != ExactValue_Invalid) {
- if (out_value) *out_value = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag));
+ if (out_value) *out_value = exact_value_complex(exact_value_to_f64(real), exact_value_to_f64(imag));
return true;
}
break;
@@ -1450,6 +1457,36 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
}
return false;
+ } else if (is_type_quaternion(type)) {
+ ExactValue v = exact_value_to_quaternion(in_value);
+ if (v.kind != ExactValue_Quaternion) {
+ return false;
+ }
+
+ switch (type->Basic.kind) {
+ case Basic_quaternion128:
+ case Basic_quaternion256: {
+ ExactValue real = exact_value_real(v);
+ ExactValue imag = exact_value_imag(v);
+ ExactValue jmag = exact_value_jmag(v);
+ ExactValue kmag = exact_value_kmag(v);
+ if (real.kind != ExactValue_Invalid &&
+ imag.kind != ExactValue_Invalid) {
+ if (out_value) *out_value = exact_value_quaternion(exact_value_to_f64(real), exact_value_to_f64(imag), exact_value_to_f64(jmag), exact_value_to_f64(kmag));
+ return true;
+ }
+ break;
+ }
+ case Basic_UntypedComplex:
+ if (out_value) *out_value = exact_value_to_quaternion(*out_value);
+ return true;
+ case Basic_UntypedQuaternion:
+ return true;
+
+ default: GB_PANIC("Compiler error: Unknown complex type!"); break;
+ }
+
+ return false;
} else if (is_type_pointer(type)) {
if (in_value.kind == ExactValue_Pointer) {
return true;
@@ -1471,28 +1508,97 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
return false;
}
+
+void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) {
+ gbString a = expr_to_string(o->expr);
+ gbString b = type_to_string(type);
+ defer(
+ gb_string_free(b);
+ gb_string_free(a);
+ );
+
+ Type *src = base_type(o->type);
+ Type *dst = base_type(type);
+
+ if (is_type_array(src) && is_type_slice(dst)) {
+ Type *s = src->Array.elem;
+ Type *d = dst->Slice.elem;
+ if (are_types_identical(s, d)) {
+ error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
+ }
+ } else if (are_types_identical(src, dst)) {
+ error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
+ } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
+ error_line("\tSuggestion: a string may be casted to %s\n", a, b);
+ } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) {
+ error_line("\tSuggestion: the expression may be casted to %s\n", b);
+ }
+}
+
+void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) {
+ gbString a = expr_to_string(o->expr);
+ gbString b = type_to_string(type);
+ defer(
+ gb_string_free(b);
+ gb_string_free(a);
+ );
+
+ Type *src = base_type(o->type);
+ Type *dst = base_type(type);
+
+ if (is_type_array(src) && is_type_slice(dst)) {
+ Type *s = src->Array.elem;
+ Type *d = dst->Slice.elem;
+ if (are_types_identical(s, d)) {
+ error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
+ }
+ } else if (is_type_pointer(o->type) && is_type_integer(type)) {
+ if (is_type_uintptr(type)) {
+ error_line("\tSuggestion: a pointer may be directly casted to %s\n", b);
+ } else {
+ error_line("\tSuggestion: for a pointer to be casted to an integer, it must be converted to 'uintptr' first\n");
+ i64 x = type_size_of(o->type);
+ i64 y = type_size_of(type);
+ if (x != y) {
+ error_line("\tNote: the type of expression and the type of the cast have a different size in bytes, %lld vs %lld\n", x, y);
+ }
+ }
+ } else if (is_type_integer(o->type) && is_type_pointer(type)) {
+ if (is_type_uintptr(o->type)) {
+ error_line("\tSuggestion: %a may be directly casted to %s\n", a, b);
+ } else {
+ error_line("\tSuggestion: for an integer to be casted to a pointer, it must be converted to 'uintptr' first\n");
+ }
+ } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
+ error_line("\tSuggestion: a string may be casted to %s\n", a, b);
+ } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) {
+ error_line("\tSuggestion: the expression may be casted to %s\n", b);
+ }
+}
+
+
void check_is_expressible(CheckerContext *c, Operand *o, Type *type) {
- GB_ASSERT(is_type_constant_type(type));
GB_ASSERT(o->mode == Addressing_Constant);
- if (!check_representable_as_constant(c, o->value, type, &o->value)) {
+ if (!is_type_constant_type(type) || !check_representable_as_constant(c, o->value, type, &o->value)) {
gbString a = expr_to_string(o->expr);
gbString b = type_to_string(type);
+ defer(
+ gb_string_free(b);
+ gb_string_free(a);
+ o->mode = Addressing_Invalid;
+ );
+
if (is_type_numeric(o->type) && is_type_numeric(type)) {
if (!is_type_integer(o->type) && is_type_integer(type)) {
error(o->expr, "'%s' truncated to '%s'", a, b);
} else {
- gbAllocator ha = heap_allocator();
- String str = big_int_to_string(ha, &o->value.value_integer);
- defer (gb_free(ha, str.text));
- error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b);
+ error(o->expr, "Cannot convert '%s' to '%s'", a, b);
+ check_assignment_error_suggestion(c, o, type);
}
} else {
error(o->expr, "Cannot convert '%s' to '%s'", a, b);
+ check_assignment_error_suggestion(c, o, type);
}
-
- gb_string_free(b);
- gb_string_free(a);
- o->mode = Addressing_Invalid;
}
}
@@ -1623,6 +1729,23 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
return;
}
+ if (x->mode == Addressing_Type && is_type_typeid(y->type)) {
+ add_type_info_type(c, x->type);
+ add_type_and_value(c->info, x->expr, Addressing_Value, y->type, exact_value_typeid(x->type));
+
+ x->mode = Addressing_Value;
+ x->type = t_untyped_bool;
+ return;
+ } else if (is_type_typeid(x->type) && y->mode == Addressing_Type) {
+ add_type_info_type(c, y->type);
+ add_type_and_value(c->info, y->expr, Addressing_Value, x->type, exact_value_typeid(y->type));
+
+ x->mode = Addressing_Value;
+ x->type = t_untyped_bool;
+ return;
+ }
+
+
gbString err_str = nullptr;
defer (if (err_str != nullptr) {
@@ -1759,6 +1882,21 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
}
break;
}
+ } else if (is_type_quaternion(x->type) || is_type_quaternion(y->type)) {
+ switch (op) {
+ case Token_CmpEq:
+ switch (8*size) {
+ case 128: add_package_dependency(c, "runtime", "quaternion128_eq"); break;
+ case 256: add_package_dependency(c, "runtime", "quaternion256_eq"); break;
+ }
+ break;
+ case Token_NotEq:
+ switch (8*size) {
+ case 128: add_package_dependency(c, "runtime", "quaternion128_ne"); break;
+ case 256: add_package_dependency(c, "runtime", "quaternion256_ne"); break;
+ }
+ break;
+ }
}
}
@@ -1767,7 +1905,7 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
}
-void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
+void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *type_hint) {
GB_ASSERT(node->kind == Ast_BinaryExpr);
ast_node(be, BinaryExpr, node);
@@ -1845,6 +1983,9 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
info->is_lhs = true;
}
x->mode = Addressing_Value;
+ if (type_hint && is_type_integer(type_hint)) {
+ x->type = type_hint;
+ }
// x->value = x_val;
return;
}
@@ -1975,6 +2116,14 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
return true;
}
+ if (is_type_complex(src) && is_type_quaternion(dst)) {
+ return true;
+ }
+
+ if (is_type_quaternion(src) && is_type_quaternion(dst)) {
+ return true;
+ }
+
if (is_type_bit_field_value(src) && is_type_integer(dst)) {
return true;
}
@@ -2097,6 +2246,8 @@ void check_cast(CheckerContext *c, Operand *x, Type *type) {
gb_string_free(to_type);
gb_string_free(expr_str);
+ check_cast_error_suggestion(c, x, type);
+
x->mode = Addressing_Invalid;
return;
}
@@ -2167,7 +2318,7 @@ bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y
}
-void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as_type_hint=false) {
+void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) {
GB_ASSERT(node->kind == Ast_BinaryExpr);
Operand y_ = {}, *y = &y_;
@@ -2178,15 +2329,23 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as
case Token_CmpEq:
case Token_NotEq: {
// NOTE(bill): Allow comparisons between types
- check_expr_or_type(c, x, be->left);
+ check_expr_or_type(c, x, be->left, type_hint);
check_expr_or_type(c, y, be->right, x->type);
bool xt = x->mode == Addressing_Type;
bool yt = y->mode == Addressing_Type;
// If only one is a type, this is an error
if (xt ^ yt) {
GB_ASSERT(xt != yt);
- if (xt) error_operand_not_expression(x);
- if (yt) error_operand_not_expression(y);
+ if (xt) {
+ if (!is_type_typeid(y->type)) {
+ error_operand_not_expression(x);
+ }
+ }
+ if (yt) {
+ if (!is_type_typeid(x->type)) {
+ error_operand_not_expression(y);
+ }
+ }
}
break;
@@ -2278,11 +2437,11 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as
return;
default:
- check_expr(c, x, be->left);
+ check_expr_with_type_hint(c, x, be->left, type_hint);
if (use_lhs_as_type_hint) {
check_expr_with_type_hint(c, y, be->right, x->type);
} else {
- check_expr(c, y, be->right);
+ check_expr_with_type_hint(c, y, be->right, type_hint);
}
break;
}
@@ -2307,7 +2466,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as
}
if (token_is_shift(op.kind)) {
- check_shift(c, x, y, node);
+ check_shift(c, x, y, node, type_hint);
return;
}
@@ -2554,6 +2713,8 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
v = exact_value_to_integer(v);
} else if (is_type_complex(t)) {
v = exact_value_to_complex(v);
+ } else if (is_type_quaternion(t)) {
+ v = exact_value_to_quaternion(v);
}
return v;
}
@@ -2649,6 +2810,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
case Basic_UntypedInteger:
case Basic_UntypedFloat:
case Basic_UntypedComplex:
+ case Basic_UntypedQuaternion:
case Basic_UntypedRune:
if (!is_type_numeric(target_type)) {
operand->mode = Addressing_Invalid;
@@ -2895,7 +3057,6 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
if (selector->kind != Ast_Ident) {
- // if (selector->kind != Ast_Ident) {
error(selector, "Illegal selector kind: '%.*s'", LIT(ast_strings[selector->kind]));
operand->mode = Addressing_Invalid;
operand->expr = node;
@@ -3131,8 +3292,59 @@ bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **o
return false;
}
+typedef bool (BuiltinTypeIsProc)(Type *t);
+
+BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__type_begin - 1] = {
+ nullptr, // BuiltinProc_type_base_type
+ nullptr, // BuiltinProc_type_core_type
+ nullptr, // BuiltinProc_type_elem_type
+
+ is_type_boolean,
+ is_type_integer,
+ is_type_rune,
+ is_type_float,
+ is_type_complex,
+ is_type_quaternion,
+ is_type_string,
+ is_type_typeid,
+ is_type_any,
+ is_type_endian_little,
+ is_type_endian_big,
+ is_type_numeric,
+ is_type_ordered,
+ is_type_ordered_numeric,
+ is_type_indexable,
+ is_type_sliceable,
+ is_type_simple_compare,
+ is_type_dereferenceable,
+ is_type_valid_for_keys,
+
+ is_type_named,
+ is_type_pointer,
+ is_type_opaque,
+ is_type_array,
+ is_type_slice,
+ is_type_dynamic_array,
+
+ is_type_map,
+ is_type_struct,
+ is_type_union,
+ is_type_enum,
+ is_type_proc,
+ is_type_bit_field,
+ is_type_bit_field_value,
+ is_type_bit_set,
+ is_type_simd_vector,
+
+ type_has_nil,
+
+ nullptr, // BuiltinProc_type_proc_parameter_count
+ nullptr, // BuiltinProc_type_proc_return_count
+};
+
-bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
+
+bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
ast_node(ce, CallExpr, call);
if (ce->inlining != ProcInlining_none) {
error(call, "Inlining operators are not allowed on built-in procedures");
@@ -3178,7 +3390,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
/*fallthrough*/
}
default:
- if (ce->args.count > 0) {
+ if (BuiltinProc__type_begin < id && id < BuiltinProc__type_end) {
+ check_expr_or_type(c, operand, ce->args[0]);
+ } else if (ce->args.count > 0) {
check_multi_expr(c, operand, ce->args[0]);
}
break;
@@ -3306,19 +3520,43 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (!operand->value.value_bool) {
gbString arg = expr_to_string(ce->args[0]);
error(call, "Compile time assertion: %s", arg);
+ if (c->proc_name != "") {
+ gbString str = type_to_string(c->curr_proc_sig);
+ error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
+ gb_string_free(str);
+ }
gb_string_free(arg);
}
operand->type = t_untyped_bool;
operand->mode = Addressing_Constant;
+ } else if (name == "panic") {
+ if (ce->args.count != 1) {
+ error(call, "'#panic' expects 1 argument, got %td", ce->args.count);
+ return false;
+ }
+ if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) {
+ gbString str = expr_to_string(ce->args[0]);
+ error(call, "'%s' is not a constant string", str);
+ gb_string_free(str);
+ return false;
+ }
+ error(call, "Compile time panic: %.*s", LIT(operand->value.value_string));
+ if (c->proc_name != "") {
+ gbString str = type_to_string(c->curr_proc_sig);
+ error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str);
+ gb_string_free(str);
+ }
+ operand->type = t_invalid;
+ operand->mode = Addressing_NoValue;
} else if (name == "defined") {
if (ce->args.count != 1) {
error(call, "'#defined' expects 1 argument, got %td", ce->args.count);
return false;
}
Ast *arg = unparen_expr(ce->args[0]);
- if (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr) {
- error(call, "'#defined' expects an identifier or selector expression, got %s", LIT(ast_strings[arg->kind]));
+ if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) {
+ error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind]));
return false;
}
@@ -3644,6 +3882,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
operand->mode = Addressing_Value;
+ if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) {
+ operand->type = type_hint;
+ }
+
break;
}
@@ -3690,7 +3932,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
if (x.mode == Addressing_Constant && y.mode == Addressing_Constant) {
- operand->value = exact_binary_operator_value(Token_Add, x.value, y.value);
+ f64 r = exact_value_to_float(x.value).value_float;
+ f64 i = exact_value_to_float(y.value).value_float;
+ operand->value = exact_value_complex(r, i);
operand->mode = Addressing_Constant;
} else {
operand->mode = Addressing_Value;
@@ -3705,13 +3949,109 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
default: GB_PANIC("Invalid type"); break;
}
+ if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) {
+ operand->type = type_hint;
+ }
+
+ break;
+ }
+
+ case BuiltinProc_quaternion: {
+ // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
+ Operand x = *operand;
+ Operand y = {};
+ Operand z = {};
+ Operand w = {};
+
+ // NOTE(bill): Invalid will be the default till fixed
+ operand->type = t_invalid;
+ operand->mode = Addressing_Invalid;
+
+ check_expr(c, &y, ce->args[1]);
+ if (y.mode == Addressing_Invalid) {
+ return false;
+ }
+ check_expr(c, &z, ce->args[2]);
+ if (y.mode == Addressing_Invalid) {
+ return false;
+ }
+ check_expr(c, &w, ce->args[3]);
+ if (y.mode == Addressing_Invalid) {
+ return false;
+ }
+
+ convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false;
+ convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
+ convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false;
+ convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
+ if (x.mode == Addressing_Constant &&
+ y.mode == Addressing_Constant &&
+ z.mode == Addressing_Constant &&
+ w.mode == Addressing_Constant) {
+ if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
+ x.type = t_untyped_float;
+ }
+ if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
+ y.type = t_untyped_float;
+ }
+ if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) {
+ z.type = t_untyped_float;
+ }
+ if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) {
+ w.type = t_untyped_float;
+ }
+ }
+
+ if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) {
+ gbString tx = type_to_string(x.type);
+ gbString ty = type_to_string(y.type);
+ gbString tz = type_to_string(z.type);
+ gbString tw = type_to_string(w.type);
+ error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw);
+ gb_string_free(tw);
+ gb_string_free(tz);
+ gb_string_free(ty);
+ gb_string_free(tx);
+ return false;
+ }
+
+ if (!is_type_float(x.type)) {
+ gbString s = type_to_string(x.type);
+ error(call, "Arguments have type '%s', expected a floating point", s);
+ gb_string_free(s);
+ return false;
+ }
+
+ if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) {
+ f64 r = exact_value_to_float(x.value).value_float;
+ f64 i = exact_value_to_float(y.value).value_float;
+ f64 j = exact_value_to_float(z.value).value_float;
+ f64 k = exact_value_to_float(w.value).value_float;
+ operand->value = exact_value_quaternion(r, i, j, k);
+ operand->mode = Addressing_Constant;
+ } else {
+ operand->mode = Addressing_Value;
+ }
+
+ BasicKind kind = core_type(x.type)->Basic.kind;
+ switch (kind) {
+ case Basic_f32: operand->type = t_quaternion128; break;
+ case Basic_f64: operand->type = t_quaternion256; break;
+ case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break;
+ default: GB_PANIC("Invalid type"); break;
+ }
+
+ if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) {
+ operand->type = type_hint;
+ }
+
break;
}
case BuiltinProc_real:
case BuiltinProc_imag: {
// real :: proc(x: type) -> float_type
- // proc imag(x: type) -> float_type
+ // imag :: proc(x: type) -> float_type
Operand *x = operand;
if (is_type_untyped(x->type)) {
@@ -3719,7 +4059,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (is_type_numeric(x->type)) {
x->type = t_untyped_complex;
}
- } else {
+ } else if (is_type_quaternion(x->type)) {
+ convert_to_typed(c, x, t_quaternion256);
+ if (x->mode == Addressing_Invalid) {
+ return false;
+ }
+ } else{
convert_to_typed(c, x, t_complex128);
if (x->mode == Addressing_Invalid) {
return false;
@@ -3727,9 +4072,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
}
- if (!is_type_complex(x->type)) {
+ if (!is_type_complex(x->type) && !is_type_quaternion(x->type)) {
gbString s = type_to_string(x->type);
- error(call, "Argument has type '%s', expected a complex type", s);
+ error(call, "Argument has type '%s', expected a complex or quaternion type", s);
gb_string_free(s);
return false;
}
@@ -3747,10 +4092,68 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
switch (kind) {
case Basic_complex64: x->type = t_f32; break;
case Basic_complex128: x->type = t_f64; break;
+ case Basic_quaternion128: x->type = t_f32; break;
+ case Basic_quaternion256: x->type = t_f64; break;
+ case Basic_UntypedComplex: x->type = t_untyped_float; break;
+ case Basic_UntypedQuaternion: x->type = t_untyped_float; break;
+ default: GB_PANIC("Invalid type"); break;
+ }
+
+ if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) {
+ operand->type = type_hint;
+ }
+
+ break;
+ }
+
+ case BuiltinProc_jmag:
+ case BuiltinProc_kmag: {
+ // jmag :: proc(x: type) -> float_type
+ // kmag :: proc(x: type) -> float_type
+
+ Operand *x = operand;
+ if (is_type_untyped(x->type)) {
+ if (x->mode == Addressing_Constant) {
+ if (is_type_numeric(x->type)) {
+ x->type = t_untyped_complex;
+ }
+ } else{
+ convert_to_typed(c, x, t_quaternion256);
+ if (x->mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ }
+
+ if (!is_type_quaternion(x->type)) {
+ gbString s = type_to_string(x->type);
+ error(call, "Argument has type '%s', expected a quaternion type", s);
+ gb_string_free(s);
+ return false;
+ }
+
+ if (x->mode == Addressing_Constant) {
+ switch (id) {
+ case BuiltinProc_jmag: x->value = exact_value_jmag(x->value); break;
+ case BuiltinProc_kmag: x->value = exact_value_kmag(x->value); break;
+ }
+ } else {
+ x->mode = Addressing_Value;
+ }
+
+ BasicKind kind = core_type(x->type)->Basic.kind;
+ switch (kind) {
+ case Basic_quaternion128: x->type = t_f32; break;
+ case Basic_quaternion256: x->type = t_f64; break;
case Basic_UntypedComplex: x->type = t_untyped_float; break;
+ case Basic_UntypedQuaternion: x->type = t_untyped_float; break;
default: GB_PANIC("Invalid type"); break;
}
+ if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) {
+ operand->type = type_hint;
+ }
+
break;
}
@@ -3761,12 +4164,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (x->mode == Addressing_Constant) {
ExactValue v = exact_value_to_complex(x->value);
f64 r = v.value_complex.real;
- f64 i = v.value_complex.imag;
+ f64 i = -v.value_complex.imag;
x->value = exact_value_complex(r, i);
x->mode = Addressing_Constant;
} else {
x->mode = Addressing_Value;
}
+ } else if (is_type_quaternion(x->type)) {
+ if (x->mode == Addressing_Constant) {
+ ExactValue v = exact_value_to_quaternion(x->value);
+ f64 r = v.value_quaternion.real;
+ f64 i = -v.value_quaternion.imag;
+ f64 j = -v.value_quaternion.jmag;
+ f64 k = -v.value_quaternion.kmag;
+ x->value = exact_value_quaternion(r, i, j, k);
+ x->mode = Addressing_Constant;
+ } else {
+ x->mode = Addressing_Value;
+ }
} else {
gbString s = type_to_string(x->type);
error(call, "Expected a complex or quaternion, got '%s'", s);
@@ -3959,6 +4374,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
Type *bt = base_type(operands[0].type);
if (are_types_identical(bt, t_f32)) add_package_dependency(c, "runtime", "min_f32");
if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "min_f64");
+
+ operand->type = operands[0].type;
}
}
break;
@@ -4119,6 +4536,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
Type *bt = base_type(operands[0].type);
if (are_types_identical(bt, t_f32)) add_package_dependency(c, "runtime", "max_f32");
if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "max_f64");
+
+ operand->type = operands[0].type;
}
}
break;
@@ -4161,6 +4580,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "abs_f64");
if (are_types_identical(bt, t_complex64)) add_package_dependency(c, "runtime", "abs_complex64");
if (are_types_identical(bt, t_complex128)) add_package_dependency(c, "runtime", "abs_complex128");
+ if (are_types_identical(bt, t_quaternion128)) add_package_dependency(c, "runtime", "abs_quaternion128");
+ if (are_types_identical(bt, t_quaternion256)) add_package_dependency(c, "runtime", "abs_quaternion256");
}
}
@@ -4266,6 +4687,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
add_package_dependency(c, "runtime", "min_f64");
add_package_dependency(c, "runtime", "max_f64");
}
+
+ operand->type = ops[0]->type;
}
}
@@ -4439,6 +4862,123 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
break;
}
break;
+
+ case BuiltinProc_type_base_type:
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ } else {
+ operand->type = base_type(operand->type);
+ }
+ operand->mode = Addressing_Type;
+ break;
+ case BuiltinProc_type_core_type:
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ } else {
+ operand->type = core_type(operand->type);
+ }
+ operand->mode = Addressing_Type;
+ break;
+ case BuiltinProc_type_elem_type:
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ } else {
+ Type *bt = base_type(operand->type);
+ switch (bt->kind) {
+ case Type_Basic:
+ switch (bt->Basic.kind) {
+ case Basic_complex64: operand->type = t_f32; break;
+ case Basic_complex128: operand->type = t_f64; break;
+ }
+ break;
+ case Type_Pointer: operand->type = bt->Pointer.elem; break;
+ case Type_Opaque: operand->type = bt->Opaque.elem; break;
+ case Type_Array: operand->type = bt->Array.elem; break;
+ case Type_Slice: operand->type = bt->Slice.elem; break;
+ case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break;
+ }
+ }
+ operand->mode = Addressing_Type;
+ break;
+
+
+ case BuiltinProc_type_is_boolean:
+ case BuiltinProc_type_is_integer:
+ case BuiltinProc_type_is_rune:
+ case BuiltinProc_type_is_float:
+ case BuiltinProc_type_is_complex:
+ case BuiltinProc_type_is_quaternion:
+ case BuiltinProc_type_is_string:
+ case BuiltinProc_type_is_typeid:
+ case BuiltinProc_type_is_any:
+ case BuiltinProc_type_is_endian_little:
+ case BuiltinProc_type_is_endian_big:
+ case BuiltinProc_type_is_numeric:
+ case BuiltinProc_type_is_ordered:
+ case BuiltinProc_type_is_ordered_numeric:
+ case BuiltinProc_type_is_indexable:
+ case BuiltinProc_type_is_sliceable:
+ case BuiltinProc_type_is_simple_compare:
+ case BuiltinProc_type_is_dereferenceable:
+ case BuiltinProc_type_is_valid_map_key:
+ case BuiltinProc_type_is_named:
+ case BuiltinProc_type_is_pointer:
+ case BuiltinProc_type_is_opaque:
+ case BuiltinProc_type_is_array:
+ case BuiltinProc_type_is_slice:
+ case BuiltinProc_type_is_dynamic_array:
+ case BuiltinProc_type_is_map:
+ case BuiltinProc_type_is_struct:
+ case BuiltinProc_type_is_union:
+ case BuiltinProc_type_is_enum:
+ case BuiltinProc_type_is_proc:
+ case BuiltinProc_type_is_bit_field:
+ case BuiltinProc_type_is_bit_field_value:
+ case BuiltinProc_type_is_bit_set:
+ case BuiltinProc_type_is_simd_vector:
+ case BuiltinProc_type_has_nil:
+ GB_ASSERT(BuiltinProc__type_begin < id && id < BuiltinProc__type_end);
+ operand->value = exact_value_bool(false);
+ if (operand->mode != Addressing_Type) {
+ gbString str = expr_to_string(ce->args[0]);
+ error(operand->expr, "Expected a type for '%.*s', got '%s'", LIT(builtin_name), str);
+ gb_string_free(str);
+ } else {
+ i32 i = id - (BuiltinProc__type_begin+1);
+ auto procedure = builtin_type_is_procs[i];
+ GB_ASSERT_MSG(procedure != nullptr, "%.*s", LIT(builtin_name));
+ operand->value = exact_value_bool(procedure(operand->type));
+ }
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_bool;
+ break;
+
+ case BuiltinProc_type_proc_parameter_count:
+ operand->value = exact_value_i64(0);
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name));
+ } else if (!is_type_proc(operand->type)) {
+ error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name));
+ } else {
+ Type *bt = base_type(operand->type);
+ operand->value = exact_value_i64(bt->Proc.param_count);
+ }
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_integer;
+ break;
+ case BuiltinProc_type_proc_return_count:
+ operand->value = exact_value_i64(0);
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name));
+ } else if (!is_type_proc(operand->type)) {
+ error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name));
+ } else {
+ Type *bt = base_type(operand->type);
+ operand->value = exact_value_i64(bt->Proc.result_count);
+ }
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_integer;
+ break;
}
return true;
@@ -4455,7 +4995,7 @@ isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs
c->decl = decl; // will be reset by the 'defer' any way
for_array(k, decl->deps.entries) {
Entity *dep = decl->deps.entries[k].ptr;
- add_declaration_dependency(c, dep); // TODO(bill): Should this be here?
+ add_declaration_dependency(c, dep); // TODO(bill): Should this be here?
}
}
}
@@ -4774,6 +5314,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
}
}
score += s;
+
+ if (o.mode == Addressing_Type && is_type_typeid(e->type)) {
+ add_type_info_type(c, o.type);
+ add_type_and_value(c->info, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type));
+ }
}
if (variadic) {
@@ -4816,6 +5361,10 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
if (is_type_any(elem)) {
add_type_info_type(c, o.type);
}
+ if (o.mode == Addressing_Type && is_type_typeid(t)) {
+ add_type_info_type(c, o.type);
+ add_type_and_value(c->info, o.expr, Addressing_Value, t, exact_value_typeid(o.type));
+ }
}
}
}
@@ -5016,6 +5565,11 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
}
score += s;
}
+
+ if (o->mode == Addressing_Type && is_type_typeid(e->type)) {
+ add_type_info_type(c, o->type);
+ add_type_and_value(c->info, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type));
+ }
}
if (data) {
@@ -5061,6 +5615,69 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize
return lhs;
}
+
+bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array<Ast *> *clauses, bool print_err) {
+ if (clauses != nullptr) {
+ for_array(i, *clauses) {
+ Ast *clause = (*clauses)[i];
+ Operand o = {};
+ check_expr(ctx, &o, clause);
+ if (o.mode != Addressing_Constant) {
+ if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
+ return false;
+ } else if (o.value.kind != ExactValue_Bool) {
+ if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation");
+ return false;
+ } else if (!o.value.value_bool) {
+ if (print_err) {
+ gbString str = expr_to_string(clause);
+ error(clause, "'where' clause evaluated to false:\n\t%s", str);
+ gb_string_free(str);
+
+ if (scope != nullptr) {
+ isize print_count = 0;
+ for_array(j, scope->elements.entries) {
+ Entity *e = scope->elements.entries[j].value;
+ switch (e->kind) {
+ case Entity_TypeName: {
+ if (print_count == 0) error_line("\n\tWith the following definitions:\n");
+
+ gbString str = type_to_string(e->type);
+ error_line("\t\t%.*s :: %s;\n", LIT(e->token.string), str);
+ gb_string_free(str);
+ print_count += 1;
+ break;
+ }
+ case Entity_Constant: {
+ if (print_count == 0) error_line("\n\tWith the following definitions:\n");
+
+ gbString str = exact_value_to_string(e->Constant.value);
+ if (is_type_untyped(e->type)) {
+ error_line("\t\t%.*s :: %s;\n", LIT(e->token.string), str);
+ } else {
+ gbString t = type_to_string(e->type);
+ error_line("\t\t%.*s : %s : %s;\n", LIT(e->token.string), t, str);
+ gb_string_free(t);
+ }
+ gb_string_free(str);
+
+ print_count += 1;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call) {
ast_node(ce, CallExpr, call);
@@ -5238,6 +5855,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
}
+
if (proc_arg_count >= 0 && proc_arg_count_all_equal) {
lhs_count = proc_arg_count;
if (lhs_count > 0) {
@@ -5281,9 +5899,8 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
gb_free(heap_allocator(), lhs);
}
- ValidIndexAndScore *valids = gb_alloc_array(heap_allocator(), ValidIndexAndScore, procs.count);
- isize valid_count = 0;
- defer (gb_free(heap_allocator(), valids));
+ auto valids = array_make<ValidIndexAndScore>(heap_allocator(), 0, procs.count);
+ defer (array_free(&valids));
gbString expr_name = expr_to_string(operand->expr);
defer (gb_string_free(expr_name));
@@ -5298,36 +5915,54 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
ctx.no_polymorphic_errors = true;
ctx.allow_polymorphic_types = is_type_polymorphic(pt);
+ ctx.hide_polymorphic_errors = true;
err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
- if (err == CallArgumentError_None) {
- valids[valid_count].index = i;
- valids[valid_count].score = data.score;
- valid_count++;
+ if (err != CallArgumentError_None) {
+ continue;
+ }
+
+ if (data.gen_entity != nullptr) {
+ Entity *e = data.gen_entity;
+ DeclInfo *decl = data.gen_entity->decl_info;
+ ctx.scope = decl->scope;
+ ctx.decl = decl;
+ ctx.proc_name = e->token.string;
+ ctx.curr_proc_decl = decl;
+ ctx.curr_proc_sig = e->type;
+
+ GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
+ if (!evaluate_where_clauses(&ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) {
+ continue;
+ }
}
+
+ ValidIndexAndScore item = {};
+ item.index = i;
+ item.score = data.score;
+ array_add(&valids, item);
}
}
- if (valid_count > 1) {
- gb_sort_array(valids, valid_count, valid_index_and_score_cmp);
+ if (valids.count > 1) {
+ gb_sort_array(valids.data, valids.count, valid_index_and_score_cmp);
i64 best_score = valids[0].score;
Entity *best_entity = procs[valids[0].index];
- for (isize i = 1; i < valid_count; i++) {
+ for (isize i = 1; i < valids.count; i++) {
if (best_score > valids[i].score) {
- valid_count = i;
+ valids.count = i;
break;
}
if (best_entity == procs[valids[i].index]) {
- valid_count = i;
+ valids.count = i;
break;
}
- best_score = valids[i].score;
}
}
- if (valid_count == 0) {
+ if (valids.count == 0) {
begin_error_block();
defer (end_error_block());
@@ -5382,7 +6017,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
}
result_type = t_invalid;
- } else if (valid_count > 1) {
+ } else if (valids.count > 1) {
begin_error_block();
defer (end_error_block());
@@ -5397,11 +6032,11 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
}
error_line(")\n");
- for (isize i = 0; i < valid_count; i++) {
+ for (isize i = 0; i < valids.count; i++) {
Entity *proc = procs[valids[i].index];
TokenPos pos = proc->token.pos;
Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc);
- gbString pt;
+ gbString pt = nullptr;
defer (gb_string_free(pt));
if (t->Proc.node != nullptr) {
pt = expr_to_string(t->Proc.node);
@@ -5413,7 +6048,29 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
if (proc->kind == Entity_Variable) {
sep = ":=";
}
- error_line("\t%.*s %s %s at %.*s(%td:%td)\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column);
+ error_line("\t%.*s %s %s ", LIT(name), sep, pt);
+ if (proc->decl_info->proc_lit != nullptr) {
+ GB_ASSERT(proc->decl_info->proc_lit->kind == Ast_ProcLit);
+ auto *pl = &proc->decl_info->proc_lit->ProcLit;
+ if (pl->where_token.kind != Token_Invalid) {
+ error_line("\n\t\twhere ");
+ for_array(j, pl->where_clauses) {
+ Ast *clause = pl->where_clauses[j];
+ if (j != 0) {
+ error_line("\t\t ");
+ }
+ gbString str = expr_to_string(clause);
+ error_line("%s", str);
+ gb_string_free(str);
+
+ if (j != pl->where_clauses.count-1) {
+ error_line(",");
+ }
+ }
+ error_line("\n\t");
+ }
+ }
+ error_line("at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
// error_line("\t%.*s %s %s at %.*s(%td:%td) %lld\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column, valids[i].score);
}
result_type = t_invalid;
@@ -5492,24 +6149,57 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
defer (array_free(&operands));
bool named_fields = false;
+ {
+ // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves
+ auto prev_type_path = c->type_path;
+ c->type_path = new_checker_type_path();
+ defer ({
+ destroy_checker_type_path(c->type_path);
+ c->type_path = prev_type_path;
+ });
+
+ if (is_call_expr_field_value(ce)) {
+ named_fields = true;
+ operands = array_make<Operand>(heap_allocator(), ce->args.count);
+ for_array(i, ce->args) {
+ Ast *arg = ce->args[i];
+ ast_node(fv, FieldValue, arg);
+
+ if (fv->field->kind == Ast_Ident) {
+ String name = fv->field->Ident.token.string;
+ isize index = lookup_polymorphic_record_parameter(original_type, name);
+ if (index >= 0) {
+ TypeTuple *params = get_record_polymorphic_params(original_type);
+ Entity *e = params->variables[i];
+ if (e->kind == Entity_Constant) {
+ check_expr_with_type_hint(c, &operands[i], fv->value, e->type);
+ }
+ }
- if (is_call_expr_field_value(ce)) {
- named_fields = true;
- operands = array_make<Operand>(heap_allocator(), ce->args.count);
- for_array(i, ce->args) {
- Ast *arg = ce->args[i];
- ast_node(fv, FieldValue, arg);
- check_expr_or_type(c, &operands[i], fv->value);
- }
+ }
+ check_expr_or_type(c, &operands[i], fv->value);
+ }
+
+ bool vari_expand = (ce->ellipsis.pos.line != 0);
+ if (vari_expand) {
+ error(ce->ellipsis, "Invalid use of '..' in a polymorphic type call'");
+ }
- bool vari_expand = (ce->ellipsis.pos.line != 0);
- if (vari_expand) {
- error(ce->ellipsis, "Invalid use of '..' in a polymorphic type call'");
+ } else {
+ operands = array_make<Operand>(heap_allocator(), 0, 2*ce->args.count);
+
+ Entity **lhs = nullptr;
+ isize lhs_count = -1;
+
+ TypeTuple *params = get_record_polymorphic_params(original_type);
+ if (params != nullptr) {
+ lhs = params->variables.data;
+ lhs_count = params->variables.count;
+ }
+
+ check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false);
}
- } else {
- operands = array_make<Operand>(heap_allocator(), 0, 2*ce->args.count);
- check_unpack_arguments(c, nullptr, -1, &operands, ce->args, false, false);
}
CallArgumentError err = CallArgumentError_None;
@@ -5638,12 +6328,16 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
}
score += s;
}
+
+ // NOTE(bill): Add type info the parameters
+ add_type_info_type(c, o->type);
}
{
gbAllocator a = c->allocator;
- Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands);
+ bool failure = false;
+ Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands, &failure);
if (found_entity) {
operand->mode = Addressing_Type;
operand->type = found_entity->type;
@@ -5692,13 +6386,13 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
-ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
+ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
ast_node(ce, CallExpr, call);
if (ce->proc != nullptr &&
ce->proc->kind == Ast_BasicDirective) {
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name;
- if (name == "location" || name == "assert" || name == "defined" || name == "load") {
+ if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "load") {
operand->mode = Addressing_Builtin;
operand->builtin_id = BuiltinProc_DIRECTIVE;
operand->expr = ce->proc;
@@ -5761,7 +6455,8 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
Ast *s = ident->SelectorExpr.selector;
ident = s;
}
- Type *ot = operand->type; GB_ASSERT(ot->kind == Type_Named);
+ Type *ot = operand->type;
+ GB_ASSERT(ot->kind == Type_Named);
Entity *e = ot->Named.type_name;
add_entity_use(c, ident, e);
add_type_and_value(&c->checker->info, call, Addressing_Type, ot, empty_exact_value);
@@ -5799,7 +6494,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
if (operand->mode == Addressing_Builtin) {
i32 id = operand->builtin_id;
- if (!check_builtin_procedure(c, operand, call, id)) {
+ if (!check_builtin_procedure(c, operand, call, id, type_hint)) {
operand->mode = Addressing_Invalid;
}
operand->expr = call;
@@ -5825,17 +6520,6 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
}
}
- // NOTE(bill): Should this be here or on the `add_entity_use`?
- // if (ce->proc != nullptr) {
- // Entity *e = entity_of_node(&c->info, ce->proc);
- // if (e != nullptr && e->kind == Entity_Procedure) {
- // String msg = e->Procedure.deprecated_message;
- // if (msg.len > 0) {
- // warning(call, "%.*s is deprecated: %.*s", LIT(e->token.string), LIT(msg));
- // }
- // }
- // }
-
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
Type *result_type = data.result_type;
gb_zero_item(operand);
@@ -5975,6 +6659,98 @@ bool ternary_compare_types(Type *x, Type *y) {
}
+bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_) {
+ if (!is_ast_range(node)) {
+ return false;
+ }
+
+ ast_node(ie, BinaryExpr, node);
+
+ check_expr(c, x, ie->left);
+ if (x->mode == Addressing_Invalid) {
+ return false;
+ }
+ check_expr(c, y, ie->right);
+ if (y->mode == Addressing_Invalid) {
+ return false;
+ }
+
+ convert_to_typed(c, x, y->type);
+ if (x->mode == Addressing_Invalid) {
+ return false;
+ }
+ convert_to_typed(c, y, x->type);
+ if (y->mode == Addressing_Invalid) {
+ return false;
+ }
+
+ convert_to_typed(c, x, default_type(y->type));
+ if (x->mode == Addressing_Invalid) {
+ return false;
+ }
+ convert_to_typed(c, y, default_type(x->type));
+ if (y->mode == Addressing_Invalid) {
+ return false;
+ }
+
+ if (!are_types_identical(x->type, y->type)) {
+ if (x->type != t_invalid &&
+ y->type != t_invalid) {
+ gbString xt = type_to_string(x->type);
+ gbString yt = type_to_string(y->type);
+ gbString expr_str = expr_to_string(x->expr);
+ error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
+ gb_string_free(expr_str);
+ gb_string_free(yt);
+ gb_string_free(xt);
+ }
+ return false;
+ }
+
+ Type *type = x->type;
+ if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
+ error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
+ return false;
+ }
+
+ if (x->mode == Addressing_Constant &&
+ y->mode == Addressing_Constant) {
+ ExactValue a = x->value;
+ ExactValue b = y->value;
+
+ GB_ASSERT(are_types_identical(x->type, y->type));
+
+ TokenKind op = Token_Lt;
+ switch (ie->op.kind) {
+ case Token_Ellipsis: op = Token_LtEq; break;
+ case Token_RangeHalf: op = Token_Lt; break;
+ default: error(ie->op, "Invalid range operator"); break;
+ }
+ bool ok = compare_exact_values(op, a, b);
+ if (!ok) {
+ // TODO(bill): Better error message
+ error(ie->op, "Invalid interval range");
+ return false;
+ }
+
+ ExactValue inline_for_depth = exact_value_sub(b, a);
+ if (ie->op.kind == Token_Ellipsis) {
+ inline_for_depth = exact_value_increment_one(inline_for_depth);
+ }
+
+ if (inline_for_depth_) *inline_for_depth_ = inline_for_depth;
+ } else {
+ error(ie->op, "Interval expressions must be constant");
+ return false;
+ }
+
+ add_type_and_value(&c->checker->info, ie->left, x->mode, x->type, x->value);
+ add_type_and_value(&c->checker->info, ie->right, y->mode, y->type, y->value);
+
+ return true;
+}
+
+
ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
ExprKind kind = Expr_Stmt;
@@ -6037,32 +6813,26 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case_ast_node(bl, BasicLit, node);
- // NOTE(bill, 2018-06-17): Placing this in the parser is slower than
- // placing it here for some reason. So don't move it to the parsing
- // stage if you _think_ it will be faster, only do it if you _know_ it
- // will be faster.
Type *t = t_invalid;
- switch (bl->token.kind) {
- case Token_Integer: t = t_untyped_integer; break;
- case Token_Float: t = t_untyped_float; break;
- case Token_String: t = t_untyped_string; break;
- case Token_Rune: t = t_untyped_rune; break;
- case Token_Imag: {
- String s = bl->token.string;
- Rune r = s[s.len-1];
- switch (r) {
- case 'i': t = t_untyped_complex; break;
+ switch (bl->value.kind) {
+ case ExactValue_String: t = t_untyped_string; break;
+ case ExactValue_Float: t = t_untyped_float; break;
+ case ExactValue_Complex: t = t_untyped_complex; break;
+ case ExactValue_Quaternion: t = t_untyped_quaternion; break;
+ case ExactValue_Integer:
+ t = t_untyped_integer;
+ if (bl->token.kind == Token_Rune) {
+ t = t_untyped_rune;
}
-
break;
- }
default:
- GB_PANIC("Unknown literal");
+ GB_PANIC("Unhandled value type for basic literal");
break;
}
+
o->mode = Addressing_Constant;
o->type = t;
- o->value = exact_value_from_basic_literal(bl->token);
+ o->value = bl->value;
case_end;
case_ast_node(bd, BasicDirective, node);
@@ -6107,6 +6877,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
decl = make_decl_info(ctx.allocator, ctx.scope, ctx.decl);
decl->proc_lit = node;
ctx.decl = decl;
+ defer (ctx.decl = ctx.decl->parent);
if (pl->tags != 0) {
error(node, "A procedure literal cannot have tags");
@@ -6412,7 +7183,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
i64 max = 0;
- isize index = 0;
Type *bet = base_type(elem_type);
if (!elem_type_can_be_constant(bet)) {
@@ -6423,40 +7193,152 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
break;
}
- for (; index < cl->elems.count; index++) {
- Ast *e = cl->elems[index];
- if (e == nullptr) {
- error(node, "Invalid literal element");
- continue;
- }
+ if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) {
+ if (is_type_simd_vector(t)) {
+ error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals");
+ } else {
+ RangeCache rc = range_cache_make(heap_allocator());
+ defer (range_cache_destroy(&rc));
- if (e->kind == Ast_FieldValue) {
- error(e, "'field = value' is only allowed in struct literals");
- continue;
- }
+ for_array(i, cl->elems) {
+ Ast *elem = cl->elems[i];
+ if (elem->kind != Ast_FieldValue) {
+ error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
+ continue;
+ }
+ ast_node(fv, FieldValue, elem);
+
+ if (is_ast_range(fv->field)) {
+ Token op = fv->field->BinaryExpr.op;
+
+ Operand x = {};
+ Operand y = {};
+ bool ok = check_range(c, fv->field, &x, &y, nullptr);
+ if (!ok) {
+ continue;
+ }
+ if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) {
+ error(x.expr, "Expected a constant integer as an array field");
+ continue;
+ }
+
+ if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) {
+ error(y.expr, "Expected a constant integer as an array field");
+ continue;
+ }
+
+ i64 lo = exact_value_to_i64(x.value);
+ i64 hi = exact_value_to_i64(y.value);
+ i64 max_index = hi;
+ if (op.kind == Token_RangeHalf) {
+ hi -= 1;
+ }
+
+ bool new_range = range_cache_add_range(&rc, lo, hi);
+ if (!new_range) {
+ error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name));
+ continue;
+ }
+
+
+ if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) {
+ error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name));
+ continue;
+ }
+ if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) {
+ error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name));
+ continue;
+ }
+
+ if (max < hi) {
+ max = max_index;
+ }
+
+ Operand operand = {};
+ check_expr_with_type_hint(c, &operand, fv->value, elem_type);
+ check_assignment(c, &operand, elem_type, context_name);
+
+ is_constant = is_constant && operand.mode == Addressing_Constant;
+ } else {
+ Operand op_index = {};
+ check_expr(c, &op_index, fv->field);
+
+ if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) {
+ error(elem, "Expected a constant integer as an array field");
+ continue;
+ }
- if (0 <= max_type_count && max_type_count <= index) {
- error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name));
+ i64 index = exact_value_to_i64(op_index.value);
+
+ if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) {
+ error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name));
+ continue;
+ }
+
+ bool new_index = range_cache_add_index(&rc, index);
+ if (!new_index) {
+ error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name));
+ continue;
+ }
+
+ if (max < index+1) {
+ max = index+1;
+ }
+
+ Operand operand = {};
+ check_expr_with_type_hint(c, &operand, fv->value, elem_type);
+ check_assignment(c, &operand, elem_type, context_name);
+
+ is_constant = is_constant && operand.mode == Addressing_Constant;
+ }
+ }
+
+ cl->max_count = max;
}
- Operand operand = {};
- check_expr_with_type_hint(c, &operand, e, elem_type);
- check_assignment(c, &operand, elem_type, context_name);
- is_constant = is_constant && operand.mode == Addressing_Constant;
- }
- if (max < index) {
- max = index;
+ } else {
+ isize index = 0;
+ for (; index < cl->elems.count; index++) {
+ Ast *e = cl->elems[index];
+ if (e == nullptr) {
+ error(node, "Invalid literal element");
+ continue;
+ }
+
+ if (e->kind == Ast_FieldValue) {
+ error(e, "Mixture of 'field = value' and value elements in a literal is not allowed");
+ continue;
+ }
+
+ if (0 <= max_type_count && max_type_count <= index) {
+ error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name));
+ }
+
+ Operand operand = {};
+ check_expr_with_type_hint(c, &operand, e, elem_type);
+ check_assignment(c, &operand, elem_type, context_name);
+
+ is_constant = is_constant && operand.mode == Addressing_Constant;
+ }
+
+ if (max < index) {
+ max = index;
+ }
}
+
if (t->kind == Type_Array) {
if (is_to_be_determined_array_count) {
t->Array.count = max;
- } else if (0 < max && max < t->Array.count) {
- error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
+ } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) {
+ if (0 < max && max < t->Array.count) {
+ error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
+ }
}
}
+
if (t->kind == Type_SimdVector) {
if (!is_constant) {
error(node, "Expected all constant elements for a simd vector");
@@ -6828,7 +7710,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case_ast_node(be, BinaryExpr, node);
- check_binary_expr(c, o, node, true);
+ check_binary_expr(c, o, node, type_hint, true);
if (o->mode == Addressing_Invalid) {
o->expr = node;
return kind;
@@ -6992,7 +7874,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
if (o->mode == Addressing_Constant) {
max_count = o->value.value_string.len;
}
- o->type = t_string;
+ o->type = type_deref(o->type);
}
break;
@@ -7072,7 +7954,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case_ast_node(ce, CallExpr, node);
- return check_call_expr(c, o, node);
+ return check_call_expr(c, o, node, type_hint);
case_end;
case_ast_node(de, DerefExpr, node);
@@ -7111,6 +7993,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
case Ast_UnionType:
case Ast_EnumType:
case Ast_MapType:
+ case Ast_OpaqueType:
+ case Ast_BitSetType:
+ case Ast_BitFieldType:
o->mode = Addressing_Type;
o->type = check_type(c, node);
break;
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index e2090688f..d4398664b 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) {
}
case_end;
+ case_ast_node(rs, InlineRangeStmt, node);
+ return false;
+ case_end;
+
case_ast_node(rs, RangeStmt, node);
return false;
case_end;
@@ -492,8 +496,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
for_array(i, found->elements.entries) {
Entity *f = found->elements.entries[i].value;
if (f->kind == Entity_Variable) {
- Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
- uvar->using_expr = expr;
+ Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
gbString expr_str = expr_to_string(expr);
@@ -587,6 +590,162 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
multi_map_insert(seen, key, tap);
}
+void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
+ ast_node(irs, InlineRangeStmt, node);
+ check_open_scope(ctx, node);
+
+ Type *val0 = nullptr;
+ Type *val1 = nullptr;
+ Entity *entities[2] = {};
+ isize entity_count = 0;
+
+ Ast *expr = unparen_expr(irs->expr);
+
+ ExactValue inline_for_depth = exact_value_i64(0);
+
+ if (is_ast_range(expr)) {
+ ast_node(ie, BinaryExpr, expr);
+ Operand x = {};
+ Operand y = {};
+
+ bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
+ if (!ok) {
+ goto skip_expr;
+ }
+
+ val0 = x.type;
+ val1 = t_int;
+ } else {
+ Operand operand = {Addressing_Invalid};
+ check_expr_or_type(ctx, &operand, irs->expr);
+
+ if (operand.mode == Addressing_Type) {
+ if (!is_type_enum(operand.type)) {
+ gbString t = type_to_string(operand.type);
+ error(operand.expr, "Cannot iterate over the type '%s'", t);
+ gb_string_free(t);
+ goto skip_expr;
+ } else {
+ val0 = operand.type;
+ val1 = t_int;
+ add_type_info_type(ctx, operand.type);
+
+ Type *bt = base_type(operand.type);
+ inline_for_depth = exact_value_i64(bt->Enum.fields.count);
+ goto skip_expr;
+ }
+ } else if (operand.mode != Addressing_Invalid) {
+ Type *t = base_type(operand.type);
+ switch (t->kind) {
+ case Type_Basic:
+ if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
+ val0 = t_rune;
+ val1 = t_int;
+ inline_for_depth = exact_value_i64(operand.value.value_string.len);
+ }
+ break;
+ case Type_Array:
+ val0 = t->Array.elem;
+ val1 = t_int;
+ inline_for_depth = exact_value_i64(t->Array.count);
+ break;
+ }
+ }
+
+ if (val0 == nullptr) {
+ gbString s = expr_to_string(operand.expr);
+ gbString t = type_to_string(operand.type);
+ error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t);
+ gb_string_free(t);
+ gb_string_free(s);
+ } else if (operand.mode != Addressing_Constant) {
+ error(operand.expr, "An 'inline for' expression must be known at compile time");
+ }
+ }
+
+ skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
+
+ Ast * lhs[2] = {irs->val0, irs->val1};
+ Type *rhs[2] = {val0, val1};
+
+ for (isize i = 0; i < 2; i++) {
+ if (lhs[i] == nullptr) {
+ continue;
+ }
+ Ast * name = lhs[i];
+ Type *type = rhs[i];
+
+ Entity *entity = nullptr;
+ if (name->kind == Ast_Ident) {
+ Token token = name->Ident.token;
+ String str = token.string;
+ Entity *found = nullptr;
+
+ if (!is_blank_ident(str)) {
+ found = scope_lookup_current(ctx->scope, str);
+ }
+ if (found == nullptr) {
+ bool is_immutable = true;
+ entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved);
+ entity->flags |= EntityFlag_Value;
+ add_entity_definition(&ctx->checker->info, name, entity);
+ } else {
+ TokenPos pos = found->token.pos;
+ error(token,
+ "Redeclaration of '%.*s' in this scope\n"
+ "\tat %.*s(%td:%td)",
+ LIT(str), LIT(pos.file), pos.line, pos.column);
+ entity = found;
+ }
+ } else {
+ error(name, "A variable declaration must be an identifier");
+ }
+
+ if (entity == nullptr) {
+ entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name));
+ }
+
+ entities[entity_count++] = entity;
+
+ if (type == nullptr) {
+ entity->type = t_invalid;
+ entity->flags |= EntityFlag_Used;
+ }
+ }
+
+ for (isize i = 0; i < entity_count; i++) {
+ add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
+ }
+
+
+ // NOTE(bill): Minimize the amount of nesting of an 'inline for'
+ i64 prev_inline_for_depth = ctx->inline_for_depth;
+ defer (ctx->inline_for_depth = prev_inline_for_depth);
+ {
+ i64 v = exact_value_to_i64(inline_for_depth);
+ if (v <= 0) {
+ // Do nothing
+ } else {
+ ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v;
+ }
+
+ if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
+ if (prev_inline_for_depth > 0) {
+ error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
+ } else {
+ error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
+ }
+ error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n");
+ ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH;
+ }
+ }
+
+ check_stmt(ctx, irs->body, mod_flags);
+
+
+ check_close_scope(ctx);
+}
+
void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(ss, SwitchStmt, node);
@@ -971,7 +1130,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
GB_PANIC("Unknown type to type switch statement");
}
- if (ptr_set_exists(&seen, y.type)) {
+ if (type_ptr_set_exists(&seen, y.type)) {
TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr);
error(y.expr,
@@ -1023,7 +1182,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
for_array(i, variants) {
Type *t = variants[i];
- if (!ptr_set_exists(&seen, t)) {
+ if (!type_ptr_set_exists(&seen, t)) {
array_add(&unhandled, t);
}
}
@@ -1132,7 +1291,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
isize rhs_count = rhs_operands.count;
for_array(i, rhs_operands) {
if (rhs_operands[i].mode == Addressing_Invalid) {
- rhs_count--;
+ // TODO(bill): Should I ignore invalid parameters?
+ // rhs_count--;
}
}
@@ -1168,7 +1328,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
be->right = as->rhs[0];
check_expr(ctx, &lhs, as->lhs[0]);
- check_binary_expr(ctx, &rhs, &binary_expr, true);
+ check_binary_expr(ctx, &rhs, &binary_expr, nullptr, true);
if (rhs.mode == Addressing_Invalid) {
return;
}
@@ -1298,6 +1458,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_close_scope(ctx);
case_end;
+
case_ast_node(rs, RangeStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
@@ -1320,29 +1481,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_expr(ctx, &x, ie->left);
if (x.mode == Addressing_Invalid) {
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
check_expr(ctx, &y, ie->right);
if (y.mode == Addressing_Invalid) {
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
convert_to_typed(ctx, &x, y.type);
if (x.mode == Addressing_Invalid) {
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
convert_to_typed(ctx, &y, x.type);
if (y.mode == Addressing_Invalid) {
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
convert_to_typed(ctx, &x, default_type(y.type));
if (x.mode == Addressing_Invalid) {
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
convert_to_typed(ctx, &y, default_type(x.type));
if (y.mode == Addressing_Invalid) {
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
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(xt);
}
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
Type *type = x.type;
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
if (x.mode == Addressing_Constant &&
@@ -1382,18 +1543,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (!ok) {
// TODO(bill): Better error message
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->right, y.mode, y.type, y.value);
val0 = type;
@@ -1407,12 +1560,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over the type '%s'", t);
gb_string_free(t);
- goto skip_expr;
+ goto skip_expr_range_stmt;
} else {
val0 = operand.type;
val1 = t_int;
add_type_info_type(ctx, operand.type);
- goto skip_expr;
+ goto skip_expr_range_stmt;
}
} else if (operand.mode != Addressing_Invalid) {
bool is_ptr = is_type_pointer(operand.type);
@@ -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};
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++) {
- 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);
@@ -1515,6 +1674,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_close_scope(ctx);
case_end;
+ case_ast_node(irs, InlineRangeStmt, node);
+ check_inline_range_stmt(ctx, node, mod_flags);
+ case_end;
+
case_ast_node(ss, SwitchStmt, node);
check_switch_stmt(ctx, node, mod_flags);
case_end;
@@ -1814,7 +1977,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
// TODO(bill): Should a 'continue' happen here?
}
- for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
+ for (isize entity_index = 0; entity_index < 1; entity_index++) {
Entity *e = entities[entity_index];
if (e == nullptr) {
continue;
@@ -1833,7 +1996,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
- Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
+ Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
diff --git a/src/check_type.cpp b/src/check_type.cpp
index f4e5b49d0..9f8310e44 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
return false;
}
-void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const &params,
+void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Array<Ast *> const &params,
isize init_field_capacity, Type *struct_type, String context) {
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
+ *tags = array_make<String>(heap_allocator(), 0, init_field_capacity);
GB_ASSERT(node->kind == Ast_StructType);
GB_ASSERT(struct_type->kind == Type_Struct);
@@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
add_entity(ctx->checker, ctx->scope, name, field);
array_add(fields, field);
+ array_add(tags, p->tag.string);
field_src_index += 1;
}
@@ -246,38 +248,51 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
}
-Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
+Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
if (found_gen_types != nullptr) {
for_array(i, *found_gen_types) {
Entity *e = (*found_gen_types)[i];
Type *t = base_type(e->type);
TypeTuple *tuple = get_record_polymorphic_params(t);
- bool ok = true;
GB_ASSERT(param_count == tuple->variables.count);
+
+ bool skip = false;
+
for (isize j = 0; j < param_count; j++) {
Entity *p = tuple->variables[j];
Operand o = ordered_operands[j];
+ Entity *oe = entity_of_node(o.expr);
+ if (p == oe) {
+ // NOTE(bill): This is the same type, make sure that it will be be same thing and use that
+ // Saves on a lot of checking too below
+ continue;
+ }
+
if (p->kind == Entity_TypeName) {
if (is_type_polymorphic(o.type)) {
// NOTE(bill): Do not add polymorphic version to the gen_types
- ok = false;
+ skip = true;
+ break;
}
if (!are_types_identical(o.type, p->type)) {
- ok = false;
+ skip = true;
+ break;
}
} else if (p->kind == Entity_Constant) {
- if (!are_types_identical(o.type, p->type)) {
- ok = false;
- }
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
- ok = false;
+ skip = true;
+ break;
+ }
+ if (!are_types_identical(o.type, p->type)) {
+ skip = true;
+ break;
}
} else {
GB_PANIC("Unknown entity kind");
}
}
- if (ok) {
+ if (!skip) {
return e;
}
}
@@ -439,8 +454,6 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
if (poly_operands != nullptr) {
Operand operand = (*poly_operands)[entities.count];
if (is_type_param) {
- GB_ASSERT(operand.mode == Addressing_Type ||
- operand.mode == Addressing_Invalid);
if (is_type_polymorphic(base_type(operand.type))) {
is_polymorphic = true;
can_check_fields = false;
@@ -448,6 +461,10 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
e = alloc_entity_type_name(scope, token, operand.type);
e->TypeName.is_type_alias = true;
} else {
+ if (is_type_polymorphic(base_type(operand.type))) {
+ is_polymorphic = true;
+ can_check_fields = false;
+ }
e = alloc_entity_constant(scope, token, operand.type, operand.value);
}
} else {
@@ -502,9 +519,13 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
struct_type->Struct.polymorphic_params = polymorphic_params;
struct_type->Struct.is_poly_specialized = is_poly_specialized;
-
if (!is_polymorphic) {
- check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context);
+ if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
+ error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
+ } else {
+ bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true);
+ }
+ check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
}
if (st->align != nullptr) {
@@ -686,6 +707,13 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
union_type->Union.is_polymorphic = is_polymorphic;
union_type->Union.is_poly_specialized = is_poly_specialized;
+ if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
+ error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
+ } else {
+ bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true);
+ }
+
+
for_array(i, ut->variants) {
Ast *node = ut->variants[i];
Type *t = check_type_expr(ctx, node, nullptr);
@@ -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) {
bool modify_type = !ctx->no_polymorphic_errors;
+ bool show_error = modify_type && !ctx->hide_polymorphic_errors;
if (!is_operand_value(operand)) {
- if (modify_type) {
+ if (show_error) {
error(operand.expr, "Cannot determine polymorphic type from parameter");
}
return t_invalid;
}
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
- if (modify_type) {
- set_procedure_abi_types(ctx, poly_type);
+ if (show_error) {
+ set_procedure_abi_types(ctx->allocator, poly_type);
}
return poly_type;
}
- if (modify_type) {
+ if (show_error) {
gbString pts = type_to_string(poly_type);
gbString ots = type_to_string(operand.type);
defer (gb_string_free(pts));
@@ -1538,7 +1567,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
}
if (is_poly_name) {
- if (type != nullptr && type_expr->kind == Ast_TypeidType) {
+ if (type_expr != nullptr && type_expr->kind == Ast_TypeidType) {
is_type_param = true;
} else {
if (param_value.kind != ParameterValue_Invalid) {
@@ -1622,6 +1651,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
if (op.mode == Addressing_Constant) {
poly_const = op.value;
} else {
+ error(op.expr, "Expected a constant value for this polymorphic name parameter");
success = false;
}
}
@@ -1825,6 +1855,282 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
return tuple;
}
+Array<Type *> systemv_distribute_struct_fields(Type *t) {
+ Type *bt = core_type(t);
+
+
+ isize distributed_cap = 1;
+ if (bt->kind == Type_Struct) {
+ distributed_cap = bt->Struct.fields.count;
+ }
+ auto distributed = array_make<Type *>(heap_allocator(), 0, distributed_cap);
+
+ i64 sz = type_size_of(bt);
+ switch (bt->kind) {
+ case Type_Basic:
+ switch (bt->Basic.kind){
+ case Basic_complex64:
+ array_add(&distributed, t_f32);
+ array_add(&distributed, t_f32);
+ break;
+ case Basic_complex128:
+ array_add(&distributed, t_f64);
+ array_add(&distributed, t_f64);
+ break;
+ case Basic_quaternion128:
+ array_add(&distributed, t_f32);
+ array_add(&distributed, t_f32);
+ array_add(&distributed, t_f32);
+ array_add(&distributed, t_f32);
+ break;
+ case Basic_quaternion256:
+ goto DEFAULT;
+ case Basic_string:
+ array_add(&distributed, t_u8_ptr);
+ array_add(&distributed, t_int);
+ break;
+ case Basic_any:
+ GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid));
+ array_add(&distributed, t_rawptr);
+ array_add(&distributed, t_uintptr);
+ break;
+
+ case Basic_u128:
+ case Basic_i128:
+ if (build_context.ODIN_OS == "windows") {
+ array_add(&distributed, alloc_type_simd_vector(2, t_u64));
+ } else {
+ array_add(&distributed, bt);
+ }
+ break;
+
+ default:
+ goto DEFAULT;
+ }
+ break;
+
+ case Type_Struct:
+ if (bt->Struct.is_raw_union) {
+ goto DEFAULT;
+ } else {
+ // IMPORTANT TOOD(bill): handle #packed structs correctly
+ // IMPORTANT TODO(bill): handle #align structs correctly
+ for_array(field_index, bt->Struct.fields) {
+ Entity *f = bt->Struct.fields[field_index];
+ auto nested = systemv_distribute_struct_fields(f->type);
+ array_add_elems(&distributed, nested.data, nested.count);
+ array_free(&nested);
+ }
+ }
+ break;
+
+ case Type_Array:
+ for (i64 i = 0; i < bt->Array.count; i++) {
+ array_add(&distributed, bt->Array.elem);
+ }
+ break;
+
+ case Type_BitSet:
+ array_add(&distributed, bit_set_to_int(bt));
+ break;
+
+ case Type_Tuple:
+ GB_PANIC("Invalid struct field type");
+ break;
+
+ case Type_Slice:
+ array_add(&distributed, t_rawptr);
+ array_add(&distributed, t_int);
+ break;
+
+ case Type_Union:
+ case Type_DynamicArray:
+ case Type_Map:
+ case Type_BitField: // TODO(bill): Ignore?
+ // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet
+ goto DEFAULT;
+
+ case Type_Pointer:
+ case Type_Proc:
+ case Type_SimdVector: // TODO(bill): Is this correct logic?
+ default:
+ DEFAULT:;
+ if (sz > 0) {
+ array_add(&distributed, bt);
+ }
+ break;
+ }
+
+ return distributed;
+}
+
+Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) {
+ GB_ASSERT(is_type_tuple(abi_type));
+ Type *final_type = alloc_type_struct();
+ final_type->Struct.fields = abi_type->Tuple.variables;
+ return final_type;
+}
+
+
+Type *handle_single_distributed_type_parameter(Array<Type *> const &types, bool packed, isize *offset) {
+ GB_ASSERT(types.count > 0);
+
+ if (types.count == 1) {
+ if (offset) *offset = 1;
+
+ i64 sz = type_size_of(types[0]);
+
+ if (is_type_float(types[0])) {
+ return types[0];
+ }
+ switch (sz) {
+ case 0:
+ GB_PANIC("Zero sized type found!");
+ case 1: return t_u8;
+ case 2: return t_u16;
+ case 4: return t_u32;
+ case 8: return t_u64;
+ default:
+ return types[0];
+ }
+ } else if (types.count >= 2) {
+ if (types[0] == t_f32 && types[1] == t_f32) {
+ if (offset) *offset = 2;
+ return alloc_type_simd_vector(2, t_f32);
+ } else if (type_size_of(types[0]) == 8) {
+ if (offset) *offset = 1;
+ return types[0];
+ }
+
+ i64 total_size = 0;
+ isize i = 0;
+ if (packed) {
+ for (; i < types.count && total_size < 8; i += 1) {
+ Type *t = types[i];
+ i64 s = type_size_of(t);
+ total_size += s;
+ }
+ } else {
+ for (; i < types.count && total_size < 8; i += 1) {
+ Type *t = types[i];
+ i64 s = gb_max(type_size_of(t), 0);
+ i64 a = gb_max(type_align_of(t), 1);
+ isize ts = align_formula(total_size, a);
+ if (ts >= 8) {
+ break;
+ }
+ total_size = ts + s;
+ }
+ }
+ if (offset) *offset = i;
+ switch (total_size) {
+ case 1: return t_u8;
+ case 2: return t_u16;
+ case 4: return t_u32;
+ case 8: return t_u64;
+ }
+ return t_u64;
+ }
+
+ return nullptr;
+}
+
+Type *handle_struct_system_v_amd64_abi_type(Type *t) {
+ if (type_size_of(t) > 16) {
+ return alloc_type_pointer(t);
+ }
+ Type *original_type = t;
+ Type *bt = core_type(t);
+ t = base_type(t);
+ i64 size = type_size_of(bt);
+
+ switch (t->kind) {
+ case Type_Slice:
+ case Type_Struct:
+ break;
+
+ case Type_Basic:
+ switch (bt->Basic.kind) {
+ case Basic_string:
+ case Basic_any:
+ case Basic_complex64:
+ case Basic_complex128:
+ case Basic_quaternion128:
+ break;
+ default:
+ return original_type;
+ }
+ break;
+
+ default:
+ return original_type;
+ }
+
+ bool is_packed = false;
+ if (is_type_struct(bt)) {
+ is_packed = bt->Struct.is_packed;
+ }
+
+ if (is_type_raw_union(bt)) {
+ // TODO(bill): Handle raw union correctly for
+ return t;
+ } else {
+ auto field_types = systemv_distribute_struct_fields(bt);
+ defer (array_free(&field_types));
+
+ GB_ASSERT(field_types.count <= 16);
+
+ Type *final_type = nullptr;
+
+ if (field_types.count == 0) {
+ final_type = t;
+ } else if (field_types.count == 1) {
+ final_type = field_types[0];
+ } else {
+ if (size <= 8) {
+ isize offset = 0;
+ final_type = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
+ } else {
+ isize offset = 0;
+ isize next_offset = 0;
+ Type *two_types[2] = {};
+
+ two_types[0] = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
+ auto remaining = array_slice(field_types, offset, field_types.count);
+ two_types[1] = handle_single_distributed_type_parameter(remaining, is_packed, &next_offset);
+ GB_ASSERT(offset + next_offset == field_types.count);
+
+ auto variables = array_make<Entity *>(heap_allocator(), 2);
+ variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false);
+ variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false);
+ final_type = alloc_type_tuple();
+ final_type->Tuple.variables = variables;
+ if (t->kind == Type_Struct) {
+ // NOTE(bill): Make this packed
+ final_type->Tuple.is_packed = t->Struct.is_packed;
+ }
+ }
+ }
+
+
+ GB_ASSERT(final_type != nullptr);
+ i64 ftsz = type_size_of(final_type);
+ i64 otsz = type_size_of(original_type);
+ if (ftsz != otsz) {
+ // TODO(bill): Handle this case which will be caused by #packed most likely
+ switch (otsz) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %s %lld vs %s %lld", type_to_string(final_type), ftsz, type_to_string(original_type), otsz);
+ }
+ }
+
+ return final_type;
+ }
+}
+
Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
Type *new_type = original_type;
@@ -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 size = type_size_of(original_type);
+
switch (8*size) {
case 8: new_type = t_u8; 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" ||
- build_context.ODIN_OS == "osx") {
+ build_context.ODIN_OS == "darwin") {
Type *bt = core_type(original_type);
switch (bt->kind) {
// Okay to pass by value (usually)
@@ -1920,18 +2227,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
case Type_Pointer: break;
case Type_Proc: break; // NOTE(bill): Just a pointer
- // Odin specific
- case Type_Slice:
- case Type_Array:
- case Type_DynamicArray:
- case Type_Map:
- case Type_Union:
- // Could be in C too
- case Type_Struct: {
- i64 align = type_align_of(original_type);
- i64 size = type_size_of(original_type);
- if (8*size > 16) {
+ default: {
+ i64 size = type_size_of(original_type);
+ if (size > 16) {
new_type = alloc_type_pointer(original_type);
+ } else if (build_context.ODIN_ARCH == "amd64") {
+ // NOTE(bill): System V AMD64 ABI
+ new_type = handle_struct_system_v_amd64_abi_type(bt);
+ if (are_types_identical(core_type(original_type), new_type)) {
+ new_type = original_type;
+ }
+ return new_type;
}
break;
@@ -2004,8 +2310,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
break;
}
}
- } else if (build_context.ODIN_OS == "linux") {
+ } else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") {
+ if (build_context.ODIN_ARCH == "amd64") {
+ }
} else {
// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
// their architectures
@@ -2071,25 +2379,39 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
return false;
}
-void set_procedure_abi_types(CheckerContext *c, Type *type) {
+void set_procedure_abi_types(gbAllocator allocator, Type *type) {
type = base_type(type);
if (type->kind != Type_Proc) {
return;
}
- type->Proc.abi_compat_params = array_make<Type *>(c->allocator, cast(isize)type->Proc.param_count);
+ if (type->Proc.abi_types_set) {
+ return;
+ }
+
+ type->Proc.abi_compat_params = array_make<Type *>(allocator, cast(isize)type->Proc.param_count);
for (i32 i = 0; i < type->Proc.param_count; i++) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind == Entity_Variable) {
Type *original_type = e->type;
- Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention);
+ Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention);
type->Proc.abi_compat_params[i] = new_type;
+ switch (type->Proc.calling_convention) {
+ case ProcCC_Odin:
+ case ProcCC_Contextless:
+ if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
+ e->flags |= EntityFlag_ImplicitReference;
+ }
+ break;
+ }
}
}
// NOTE(bill): The types are the same
- type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention);
- type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
+ type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention);
+ type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
+
+ type->Proc.abi_types_set = true;
}
// NOTE(bill): 'operands' is for generating non generic procedure type
@@ -2187,8 +2509,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
}
type->Proc.is_polymorphic = is_polymorphic;
- set_procedure_abi_types(c, type);
-
return success;
}
@@ -2537,7 +2857,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
generic_type = o.type;
}
if (count < 0) {
- error(at->count, "... can only be used in conjuction with compound literals");
+ error(at->count, "? can only be used in conjuction with compound literals");
count = 0;
}
Type *elem = check_type_expr(ctx, at->elem, nullptr);
diff --git a/src/checker.cpp b/src/checker.cpp
index 9abd8c499..e7b347f1a 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -85,9 +85,13 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) {
EntityGraphNode *y = data[j];
isize a = x->entity->order_in_src;
isize b = y->entity->order_in_src;
- if (x->dep_count < y->dep_count) return -1;
- if (x->dep_count > y->dep_count) return +1;
- return a < b ? -1 : b > a;
+ if (x->dep_count < y->dep_count) {
+ return -1;
+ }
+ if (x->dep_count == y->dep_count) {
+ return a < b ? -1 : b > a;
+ }
+ return +1;
}
void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
@@ -400,6 +404,15 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
if (found) {
return *found;
}
+ if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
+ Entity **found = map_get(&s->parent->elements, key);
+ if (found) {
+ if ((*found)->flags & EntityFlag_Result) {
+ return *found;
+ }
+ }
+ }
+
map_set(&s->elements, key, entity);
if (entity->scope == nullptr) {
entity->scope = s;
@@ -1044,21 +1057,37 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) {
// NOTE(bill): Error should have been handled already
return false;
}
- error(prev->token,
- "Redeclaration of '%.*s' in this scope through 'using'\n"
- "\tat %.*s(%td:%td)",
- LIT(name),
- LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
+ if (found->flags & EntityFlag_Result) {
+ error(prev->token,
+ "Direct shadowing of the named return value '%.*s' in this scope through 'using'\n"
+ "\tat %.*s(%td:%td)",
+ LIT(name),
+ LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
+ } else {
+ error(prev->token,
+ "Redeclaration of '%.*s' in this scope through 'using'\n"
+ "\tat %.*s(%td:%td)",
+ LIT(name),
+ LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
+ }
} else {
if (pos == prev->token.pos) {
// NOTE(bill): Error should have been handled already
return false;
}
- error(prev->token,
- "Redeclaration of '%.*s' in this scope\n"
- "\tat %.*s(%td:%td)",
- LIT(name),
- LIT(pos.file), pos.line, pos.column);
+ if (found->flags & EntityFlag_Result) {
+ error(prev->token,
+ "Direct shadowing of the named return value '%.*s' in this scope\n"
+ "\tat %.*s(%td:%td)",
+ LIT(name),
+ LIT(pos.file), pos.line, pos.column);
+ } else {
+ error(prev->token,
+ "Redeclaration of '%.*s' in this scope\n"
+ "\tat %.*s(%td:%td)",
+ LIT(name),
+ LIT(pos.file), pos.line, pos.column);
+ }
}
return false;
}
@@ -1139,6 +1168,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec
add_entity_definition(&c->checker->info, identifier, e);
GB_ASSERT(e->decl_info == nullptr);
e->decl_info = d;
+ d->entity = e;
array_add(&c->checker->info.entities, e);
e->order_in_src = c->checker->info.entities.count;
e->pkg = c->pkg;
@@ -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_f64);
break;
+ case Basic_quaternion128:
+ add_min_dep_type_info(c, t_type_info_float);
+ add_min_dep_type_info(c, t_f32);
+ break;
+ case Basic_quaternion256:
+ add_min_dep_type_info(c, t_type_info_float);
+ add_min_dep_type_info(c, t_f64);
+ break;
}
break;
@@ -1577,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("args__"),
str_lit("type_table"),
+ str_lit("__type_info_of"),
str_lit("global_scratch_allocator"),
str_lit("Type_Info"),
@@ -1585,9 +1624,17 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("quo_complex64"),
str_lit("quo_complex128"),
+ str_lit("mul_quaternion128"),
+ str_lit("mul_quaternion256"),
+ str_lit("quo_quaternion128"),
+ str_lit("quo_quaternion256"),
+ str_lit("cstring_to_string"),
str_lit("umodti3"),
str_lit("udivti3"),
+
+ str_lit("memory_compare"),
+ str_lit("memory_compare_zero"),
};
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
@@ -1656,9 +1703,10 @@ bool is_entity_a_dependency(Entity *e) {
if (e == nullptr) return false;
switch (e->kind) {
case Entity_Procedure:
- case Entity_Variable:
- case Entity_Constant:
return true;
+ case Entity_Constant:
+ case Entity_Variable:
+ return e->pkg != nullptr;
}
return false;
}
@@ -1685,18 +1733,17 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
EntityGraphNode *n = M.entries[i].value;
DeclInfo *decl = decl_info_of_entity(e);
- if (decl != nullptr) {
- for_array(j, decl->deps.entries) {
- auto entry = decl->deps.entries[j];
- Entity *dep = entry.ptr;
- if (dep && is_entity_a_dependency(dep)) {
- EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
- if (m_ != nullptr) {
- EntityGraphNode *m = *m_;
- entity_graph_node_set_add(&n->succ, m);
- entity_graph_node_set_add(&m->pred, n);
- }
- }
+ GB_ASSERT(decl != nullptr);
+
+ for_array(j, decl->deps.entries) {
+ Entity *dep = decl->deps.entries[j].ptr;
+ GB_ASSERT(dep != nullptr);
+ if (is_entity_a_dependency(dep)) {
+ EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
+ GB_ASSERT(m_ != nullptr);
+ EntityGraphNode *m = *m_;
+ entity_graph_node_set_add(&n->succ, m);
+ entity_graph_node_set_add(&m->pred, n);
}
}
}
@@ -1741,6 +1788,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
EntityGraphNode *n = G[i];
n->index = i;
n->dep_count = n->succ.entries.count;
+
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_rune = find_core_type(c, str_lit("Type_Info_Rune"));
t_type_info_float = find_core_type(c, str_lit("Type_Info_Float"));
+ t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion"));
t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex"));
t_type_info_string = find_core_type(c, str_lit("Type_Info_String"));
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
@@ -1887,6 +1936,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune);
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
+ t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion);
t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex);
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
@@ -2138,6 +2188,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
+ } else if (name == "require_results") {
+ if (value != nullptr) {
+ error(elem, "Expected no value for '%.*s'", LIT(name));
+ }
+ ac->require_results = true;
+ return true;
}
return false;
}
@@ -2528,6 +2584,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
Ast *init_expr = value;
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
+ d->entity = e;
d->type_expr = vd->type;
d->init_expr = init_expr;
d->attributes = vd->attributes;
@@ -2557,14 +2614,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
Entity *e = nullptr;
d->attributes = vd->attributes;
+ d->type_expr = vd->type;
+ d->init_expr = init;
if (is_ast_type(init)) {
e = alloc_entity_type_name(d->scope, token, nullptr);
- if (vd->type != nullptr) {
- error(name, "A type declaration cannot have an type parameter");
- }
- d->type_expr = init;
- d->init_expr = init;
+ // if (vd->type != nullptr) {
+ // error(name, "A type declaration cannot have an type parameter");
+ // }
} else if (init->kind == Ast_ProcLit) {
if (c->scope->flags&ScopeFlag_Type) {
error(name, "Procedure declarations are not allowed within a struct");
@@ -2591,19 +2648,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
pl->type->ProcType.calling_convention = cc;
}
d->proc_lit = init;
- d->type_expr = vd->type;
+ d->init_expr = init;
} else if (init->kind == Ast_ProcGroup) {
ast_node(pg, ProcGroup, init);
e = alloc_entity_proc_group(d->scope, token, nullptr);
if (fl != nullptr) {
error(name, "Procedure groups are not allowed within a foreign block");
}
- d->init_expr = init;
- d->type_expr = vd->type;
} else {
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
- d->type_expr = vd->type;
- d->init_expr = init;
}
e->identifier = name;
@@ -3101,7 +3154,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
Entity *e = scope->elements.entries[elem_index].value;
if (e->scope == parent_scope) continue;
- if (is_entity_exported(e)) {
+ if (is_entity_exported(e, true)) {
Entity *found = scope_lookup_current(parent_scope, name);
if (found != nullptr) {
// NOTE(bill):
@@ -3315,8 +3368,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
if (es->expr->kind == Ast_CallExpr) {
ast_node(ce, CallExpr, es->expr);
if (ce->proc->kind == Ast_BasicDirective) {
- Operand o = {};
- check_expr(ctx, &o, es->expr);
+ if (ctx->collect_delayed_decls) {
+ array_add(&ctx->scope->delayed_directives, es->expr);
+ }
}
}
case_end;
@@ -3473,12 +3527,18 @@ void check_import_entities(Checker *c) {
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx;
-
add_curr_ast_file(&ctx, f);
+
for_array(j, f->scope->delayed_imports) {
Ast *decl = f->scope->delayed_imports[j];
check_add_import_decl(&ctx, decl);
}
+ }
+ for_array(i, pkg->files) {
+ AstFile *f = pkg->files[i];
+ CheckerContext ctx = c->init_ctx;
+ add_curr_ast_file(&ctx, f);
+
for_array(j, f->scope->delayed_directives) {
Ast *expr = f->scope->delayed_directives[j];
Operand o = {};
@@ -3542,7 +3602,6 @@ void calculate_global_init_order(Checker *c) {
#define TIME_SECTION(str)
#endif
-
CheckerInfo *info = &c->info;
TIME_SECTION("generate entity dependency graph");
@@ -3584,21 +3643,26 @@ void calculate_global_init_order(Checker *c) {
for_array(i, n->pred.entries) {
EntityGraphNode *p = n->pred.entries[i].ptr;
- p->dep_count -= gb_max(p->dep_count-1, 0);
+ p->dep_count -= 1;
+ p->dep_count = gb_max(p->dep_count, 0);
priority_queue_fix(&pq, p->index);
}
- if (e == nullptr || e->kind != Entity_Variable) {
+ DeclInfo *d = decl_info_of_entity(e);
+ if (e->kind != Entity_Variable) {
continue;
}
- DeclInfo *d = decl_info_of_entity(e);
-
+ // IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering
+ // because it does not need any initialization other than zero
+ // if (!decl_info_has_init(d)) {
+ // continue;
+ // }
if (ptr_set_exists(&emitted, d)) {
continue;
}
ptr_set_add(&emitted, d);
- d->entity = e;
+
array_add(&info->variable_init_order, d);
}
@@ -3637,6 +3701,14 @@ void check_proc_info(Checker *c, ProcInfo pi) {
return;
}
+ if (pt->is_polymorphic && pt->is_poly_specialized) {
+ Entity *e = pi.decl->entity;
+ if ((e->flags & EntityFlag_Used) == 0) {
+ // NOTE(bill, 2019-08-31): It was never used, don't check
+ return;
+ }
+ }
+
bool bounds_check = (pi.tags & ProcTag_bounds_check) != 0;
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
diff --git a/src/checker.hpp b/src/checker.hpp
index 66b68c35c..c33514511 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -59,218 +59,8 @@ struct BuiltinProc {
BuiltinProcPkg pkg;
};
-enum BuiltinProcId {
- BuiltinProc_Invalid,
-
- BuiltinProc_len,
- BuiltinProc_cap,
-
- BuiltinProc_size_of,
- BuiltinProc_align_of,
- BuiltinProc_offset_of,
- BuiltinProc_type_of,
- BuiltinProc_type_info_of,
- BuiltinProc_typeid_of,
-
- BuiltinProc_swizzle,
-
- BuiltinProc_complex,
- BuiltinProc_real,
- BuiltinProc_imag,
- BuiltinProc_conj,
-
- BuiltinProc_expand_to_tuple,
-
- BuiltinProc_min,
- BuiltinProc_max,
- BuiltinProc_abs,
- BuiltinProc_clamp,
-
- BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
-
- // "Intrinsics"
- BuiltinProc_vector,
-
- BuiltinProc_atomic_fence,
- BuiltinProc_atomic_fence_acq,
- BuiltinProc_atomic_fence_rel,
- BuiltinProc_atomic_fence_acqrel,
-
- BuiltinProc_atomic_store,
- BuiltinProc_atomic_store_rel,
- BuiltinProc_atomic_store_relaxed,
- BuiltinProc_atomic_store_unordered,
-
- BuiltinProc_atomic_load,
- BuiltinProc_atomic_load_acq,
- BuiltinProc_atomic_load_relaxed,
- BuiltinProc_atomic_load_unordered,
-
- BuiltinProc_atomic_add,
- BuiltinProc_atomic_add_acq,
- BuiltinProc_atomic_add_rel,
- BuiltinProc_atomic_add_acqrel,
- BuiltinProc_atomic_add_relaxed,
- BuiltinProc_atomic_sub,
- BuiltinProc_atomic_sub_acq,
- BuiltinProc_atomic_sub_rel,
- BuiltinProc_atomic_sub_acqrel,
- BuiltinProc_atomic_sub_relaxed,
- BuiltinProc_atomic_and,
- BuiltinProc_atomic_and_acq,
- BuiltinProc_atomic_and_rel,
- BuiltinProc_atomic_and_acqrel,
- BuiltinProc_atomic_and_relaxed,
- BuiltinProc_atomic_nand,
- BuiltinProc_atomic_nand_acq,
- BuiltinProc_atomic_nand_rel,
- BuiltinProc_atomic_nand_acqrel,
- BuiltinProc_atomic_nand_relaxed,
- BuiltinProc_atomic_or,
- BuiltinProc_atomic_or_acq,
- BuiltinProc_atomic_or_rel,
- BuiltinProc_atomic_or_acqrel,
- BuiltinProc_atomic_or_relaxed,
- BuiltinProc_atomic_xor,
- BuiltinProc_atomic_xor_acq,
- BuiltinProc_atomic_xor_rel,
- BuiltinProc_atomic_xor_acqrel,
- BuiltinProc_atomic_xor_relaxed,
-
- BuiltinProc_atomic_xchg,
- BuiltinProc_atomic_xchg_acq,
- BuiltinProc_atomic_xchg_rel,
- BuiltinProc_atomic_xchg_acqrel,
- BuiltinProc_atomic_xchg_relaxed,
-
- BuiltinProc_atomic_cxchg,
- BuiltinProc_atomic_cxchg_acq,
- BuiltinProc_atomic_cxchg_rel,
- BuiltinProc_atomic_cxchg_acqrel,
- BuiltinProc_atomic_cxchg_relaxed,
- BuiltinProc_atomic_cxchg_failrelaxed,
- BuiltinProc_atomic_cxchg_failacq,
- BuiltinProc_atomic_cxchg_acq_failrelaxed,
- BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
-
- BuiltinProc_atomic_cxchgweak,
- BuiltinProc_atomic_cxchgweak_acq,
- BuiltinProc_atomic_cxchgweak_rel,
- BuiltinProc_atomic_cxchgweak_acqrel,
- BuiltinProc_atomic_cxchgweak_relaxed,
- BuiltinProc_atomic_cxchgweak_failrelaxed,
- BuiltinProc_atomic_cxchgweak_failacq,
- BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
- BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
-
- BuiltinProc_COUNT,
-};
-gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
- {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin},
-
- {STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
-
- {STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
-
- {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
-
- {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
-
- {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
-
- {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
- {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin},
-
- {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
-
-
- // "Intrinsics"
- {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
-
-
- {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
-
- {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
-
- {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
-
- {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
-
- {STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
-
- {STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
-
- {STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
-};
+
+#include "checker_builtin_procs.hpp"
// Operand is used as an intermediate value whilst checking
@@ -307,6 +97,7 @@ struct DeferredProcedure {
struct AttributeContext {
bool is_export;
bool is_static;
+ bool require_results;
String link_name;
String link_prefix;
isize init_expr_list_count;
@@ -431,6 +222,7 @@ struct ForeignContext {
typedef Array<Entity *> CheckerTypePath;
typedef Array<Type *> CheckerPolyPath;
+
// CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo {
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
@@ -486,10 +278,14 @@ struct CheckerContext {
CheckerPolyPath *poly_path;
isize poly_level; // TODO(bill): Actually handle correctly
+#define MAX_INLINE_FOR_DEPTH 1024ll
+ i64 inline_for_depth;
+
bool in_enum_type;
bool collect_delayed_decls;
bool allow_polymorphic_types;
bool no_polymorphic_errors;
+ bool hide_polymorphic_errors;
bool in_polymorphic_specialization;
Scope * polymorphic_scope;
};
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
new file mode 100644
index 000000000..50d27d715
--- /dev/null
+++ b/src/checker_builtin_procs.hpp
@@ -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},
+};
diff --git a/src/common.cpp b/src/common.cpp
index 8085e895c..b034ad720 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -10,13 +10,11 @@
#define GB_IMPLEMENTATION
#include "gb/gb.h"
-
#include <wchar.h>
#include <stdio.h>
#include <math.h>
-
template <typename U, typename V>
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
@@ -145,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
+#include "range_cache.cpp"
+
+
u64 fnv64a(void const *data, isize len) {
u8 const *bytes = cast(u8 const *)data;
@@ -331,7 +332,7 @@ void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
#include "ptr_set.cpp"
#include "string_set.cpp"
#include "priority_queue.cpp"
-
+#include "thread_pool.cpp"
gb_global String global_module_path = {0};
@@ -873,7 +874,6 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
info.size = size;
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
array_add(fi, info);
-
} while (FindNextFileW(find_file, &file_data));
if (fi->count == 0) {
diff --git a/src/entity.cpp b/src/entity.cpp
index 3318eac24..bbea68e8b 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -48,7 +48,8 @@ enum EntityFlag {
EntityFlag_NotExported = 1<<14,
EntityFlag_Static = 1<<16,
- // EntityFlag_Reference = 1<<17,
+
+ EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++
EntityFlag_CVarArg = 1<<20,
EntityFlag_AutoCast = 1<<21,
@@ -183,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
}
String name = e->token.string;
- if (name.len == 0) {
- return false;
+ switch (name.len) {
+ case 0: return false;
+ case 1: return name[0] != '_';
}
- return name[0] != '_';
+ return true;
}
bool entity_has_deferred_procedure(Entity *e) {
@@ -219,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm
return entity;
}
-Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) {
+Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
GB_ASSERT(parent != nullptr);
token.pos = parent->token.pos;
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
entity->using_parent = parent;
entity->parent_proc_decl = parent->parent_proc_decl;
+ entity->using_expr = using_expr;
entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Used;
entity->state = EntityState_Resolved;
diff --git a/src/exact_value.cpp b/src/exact_value.cpp
index 428690291..42b22c8ef 100644
--- a/src/exact_value.cpp
+++ b/src/exact_value.cpp
@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
struct Complex128 {
f64 real, imag;
};
+struct Quaternion256 {
+ f64 imag, jmag, kmag, real;
+};
+
+Quaternion256 quaternion256_inverse(Quaternion256 x) {
+ f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
+ x.real = +x.real * invmag2;
+ x.imag = -x.imag * invmag2;
+ x.jmag = -x.jmag * invmag2;
+ x.kmag = -x.kmag * invmag2;
+ return x;
+}
+
enum ExactValueKind {
ExactValue_Invalid,
@@ -21,9 +34,11 @@ enum ExactValueKind {
ExactValue_Integer,
ExactValue_Float,
ExactValue_Complex,
+ ExactValue_Quaternion,
ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Procedure, // TODO(bill): Is this good enough?
+ ExactValue_Typeid,
ExactValue_Count,
};
@@ -37,8 +52,10 @@ struct ExactValue {
f64 value_float;
i64 value_pointer;
Complex128 value_complex;
+ Quaternion256 value_quaternion;
Ast * value_compound;
Ast * value_procedure;
+ Type * value_typeid;
};
};
@@ -53,25 +70,22 @@ HashKey hash_exact_value(ExactValue v) {
return hash_integer(u64(v.value_bool));
case ExactValue_String:
return hash_string(v.value_string);
- case ExactValue_Integer: {
- u64 *d = big_int_ptr(&v.value_integer);
- u64 x = 0;
- for (i32 i = 0; i < v.value_integer.len; i++) {
- x |= d[i];
- }
- return hash_integer(x);
- }
+ case ExactValue_Integer:
+ return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
case ExactValue_Float:
return hash_f64(v.value_float);
case ExactValue_Pointer:
return hash_integer(v.value_pointer);
case ExactValue_Complex:
return hashing_proc(&v.value_complex, gb_size_of(Complex128));
-
+ case ExactValue_Quaternion:
+ return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
case ExactValue_Compound:
return hash_pointer(v.value_compound);
case ExactValue_Procedure:
return hash_pointer(v.value_procedure);
+ case ExactValue_Typeid:
+ return hash_pointer(v.value_typeid);
}
return hashing_proc(&v, gb_size_of(ExactValue));
@@ -122,6 +136,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
return result;
}
+ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
+ ExactValue result = {ExactValue_Quaternion};
+ result.value_quaternion.real = real;
+ result.value_quaternion.imag = imag;
+ result.value_quaternion.jmag = jmag;
+ result.value_quaternion.kmag = kmag;
+ return result;
+}
+
ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
@@ -135,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) {
}
+ExactValue exact_value_typeid(Type *type) {
+ ExactValue result = {ExactValue_Typeid};
+ result.value_typeid = type;
+ return result;
+}
+
+
ExactValue exact_value_integer_from_string(String const &string) {
ExactValue result = {ExactValue_Integer};
big_int_from_string(&result.value_integer, string);
@@ -259,14 +289,16 @@ ExactValue exact_value_from_basic_literal(Token token) {
str.len--; // Ignore the 'i|j|k'
f64 imag = float_from_string(str);
- if (last_rune == 'i') {
- return exact_value_complex(0, imag);
+ switch (last_rune) {
+ case 'i': return exact_value_complex(0, imag);
+ case 'j': return exact_value_quaternion(0, 0, imag, 0);
+ case 'k': return exact_value_quaternion(0, 0, 0, imag);
+ default: GB_PANIC("Invalid imaginary basic literal");
}
}
case Token_Rune: {
Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r);
- // gb_printf("%.*s rune: %d\n", LIT(token.string), r);
return exact_value_i64(r);
}
default:
@@ -324,11 +356,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
return exact_value_complex(v.value_float, 0);
case ExactValue_Complex:
return v;
+ // case ExactValue_Quaternion:
+ // return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
+ }
+ ExactValue r = {ExactValue_Invalid};
+ return r;
+}
+ExactValue exact_value_to_quaternion(ExactValue v) {
+ switch (v.kind) {
+ case ExactValue_Integer:
+ return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
+ case ExactValue_Float:
+ return exact_value_quaternion(v.value_float, 0, 0, 0);
+ case ExactValue_Complex:
+ return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
+ case ExactValue_Quaternion:
+ return v;
}
ExactValue r = {ExactValue_Invalid};
return r;
}
-
ExactValue exact_value_real(ExactValue v) {
switch (v.kind) {
@@ -337,6 +384,8 @@ ExactValue exact_value_real(ExactValue v) {
return v;
case ExactValue_Complex:
return exact_value_float(v.value_complex.real);
+ case ExactValue_Quaternion:
+ return exact_value_float(v.value_quaternion.real);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -349,6 +398,34 @@ ExactValue exact_value_imag(ExactValue v) {
return exact_value_i64(0);
case ExactValue_Complex:
return exact_value_float(v.value_complex.imag);
+ case ExactValue_Quaternion:
+ return exact_value_float(v.value_quaternion.imag);
+ }
+ ExactValue r = {ExactValue_Invalid};
+ return r;
+}
+
+ExactValue exact_value_jmag(ExactValue v) {
+ switch (v.kind) {
+ case ExactValue_Integer:
+ case ExactValue_Float:
+ case ExactValue_Complex:
+ return exact_value_i64(0);
+ case ExactValue_Quaternion:
+ return exact_value_float(v.value_quaternion.jmag);
+ }
+ ExactValue r = {ExactValue_Invalid};
+ return r;
+}
+
+ExactValue exact_value_kmag(ExactValue v) {
+ switch (v.kind) {
+ case ExactValue_Integer:
+ case ExactValue_Float:
+ case ExactValue_Complex:
+ return exact_value_i64(0);
+ case ExactValue_Quaternion:
+ return exact_value_float(v.value_quaternion.kmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -367,6 +444,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
return r;
}
+ExactValue exact_value_make_jmag(ExactValue v) {
+ switch (v.kind) {
+ case ExactValue_Integer:
+ return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
+ case ExactValue_Float:
+ return exact_value_quaternion(0, 0, v.value_float, 0);
+ default:
+ GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
+ }
+ ExactValue r = {ExactValue_Invalid};
+ return r;
+}
+
+ExactValue exact_value_make_kmag(ExactValue v) {
+ switch (v.kind) {
+ case ExactValue_Integer:
+ return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
+ case ExactValue_Float:
+ return exact_value_quaternion(0, 0, 0, v.value_float);
+ default:
+ GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
+ }
+ ExactValue r = {ExactValue_Invalid};
+ return r;
+}
+
i64 exact_value_to_i64(ExactValue v) {
v = exact_value_to_integer(v);
if (v.kind == ExactValue_Integer) {
@@ -395,6 +498,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
+ case ExactValue_Quaternion:
return v;
}
break;
@@ -419,6 +523,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag);
}
+ case ExactValue_Quaternion: {
+ f64 real = v.value_quaternion.real;
+ f64 imag = v.value_quaternion.imag;
+ f64 jmag = v.value_quaternion.jmag;
+ f64 kmag = v.value_quaternion.kmag;
+ return exact_value_quaternion(-real, -imag, -jmag, -kmag);
+ }
}
break;
}
@@ -469,8 +580,10 @@ i32 exact_value_order(ExactValue const &v) {
return 3;
case ExactValue_Complex:
return 4;
- case ExactValue_Pointer:
+ case ExactValue_Quaternion:
return 5;
+ case ExactValue_Pointer:
+ return 6;
default:
GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -491,7 +604,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool:
case ExactValue_String:
- case ExactValue_Complex:
+ case ExactValue_Quaternion:
return;
case ExactValue_Integer:
@@ -505,6 +618,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex:
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
return;
+ case ExactValue_Quaternion:
+ *x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
+ return;
}
break;
@@ -515,6 +631,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex:
*x = exact_value_to_complex(*x);
return;
+ case ExactValue_Quaternion:
+ *x = exact_value_to_quaternion(*x);
+ return;
+ }
+ break;
+
+ case ExactValue_Complex:
+ switch (y->kind) {
+ case ExactValue_Quaternion:
+ *x = exact_value_to_quaternion(*x);
+ return;
}
break;
}
@@ -612,6 +739,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
break;
}
+ case ExactValue_Quaternion: {
+ y = exact_value_to_quaternion(y);
+ f64 xr = x.value_quaternion.real;
+ f64 xi = x.value_quaternion.imag;
+ f64 xj = x.value_quaternion.jmag;
+ f64 xk = x.value_quaternion.kmag;
+ f64 yr = y.value_quaternion.real;
+ f64 yi = y.value_quaternion.imag;
+ f64 yj = y.value_quaternion.jmag;
+ f64 yk = y.value_quaternion.kmag;
+
+
+ f64 real = 0;
+ f64 imag = 0;
+ f64 jmag = 0;
+ f64 kmag = 0;
+
+ switch (op) {
+ case Token_Add:
+ real = xr + yr;
+ imag = xi + yi;
+ jmag = xj + yj;
+ kmag = xk + yk;
+ break;
+ case Token_Sub:
+ real = xr - yr;
+ imag = xi - yi;
+ jmag = xj - yj;
+ kmag = xk - yk;
+ break;
+ case Token_Mul:
+ imag = xr * yi + xi * yr + xj * yk - xk * yj;
+ jmag = xr * yj - xi * yk + xj * yr + xk * yi;
+ kmag = xr * yk + xi * yj - xj * yi + xk * yr;
+ real = xr * yr - xi * yi - xj * yj - xk * yk;
+ break;
+ case Token_Quo: {
+ f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk);
+ imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2;
+ jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2;
+ kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2;
+ real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2;
+ break;
+ }
+ default: goto error;
+ }
+ return exact_value_quaternion(real, imag, jmag, kmag);
+ break;
+ }
+
case ExactValue_String: {
if (op != Token_Add) goto error;
@@ -647,6 +824,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV
return exact_binary_operator_value(op, x, y);
}
+gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
+ return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
+}
+
i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b);
@@ -719,8 +900,61 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
}
break;
}
+
+ case ExactValue_Typeid:
+ switch (op) {
+ case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
+ case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
+ }
+ break;
}
GB_PANIC("Invalid comparison");
return false;
}
+
+
+gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
+ switch (v.kind) {
+ case ExactValue_Invalid:
+ return str;
+ case ExactValue_Bool:
+ return gb_string_appendc(str, v.value_bool ? "true" : "false");
+ case ExactValue_String: {
+ String s = quote_to_ascii(heap_allocator(), v.value_string);
+ string_limit = gb_max(string_limit, 36);
+ if (s.len <= string_limit) {
+ str = gb_string_append_length(str, s.text, s.len);
+ } else {
+ isize n = string_limit/5;
+ str = gb_string_append_length(str, s.text, n);
+ str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n));
+ str = gb_string_append_length(str, s.text+s.len-n, n);
+ }
+ gb_free(heap_allocator(), s.text);
+ return str;
+ }
+ case ExactValue_Integer: {
+ String s = big_int_to_string(heap_allocator(), &v.value_integer);
+ str = gb_string_append_length(str, s.text, s.len);
+ gb_free(heap_allocator(), s.text);
+ return str;
+ }
+ case ExactValue_Float:
+ return gb_string_append_fmt(str, "%f", v.value_float);
+ case ExactValue_Complex:
+ return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag);
+
+ case ExactValue_Pointer:
+ return str;
+ case ExactValue_Compound:
+ return str;
+ case ExactValue_Procedure:
+ return str;
+ }
+ return str;
+};
+
+gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
+ return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
+}
diff --git a/src/gb/gb.h b/src/gb/gb.h
index adeb554b2..60303729f 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -918,7 +918,7 @@ GB_DEF void gb_lfence (void);
#if defined(GB_SYSTEM_WINDOWS)
-typedef struct gbSemaphore { void *win32_handle; } gbSemaphore;
+typedef struct gbSemaphore { void *win32_handle;} gbSemaphore;
#elif defined(GB_SYSTEM_OSX)
typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore;
#elif defined(GB_SYSTEM_UNIX)
@@ -930,7 +930,7 @@ typedef struct gbSemaphore { sem_t unix_handle; } gbSemaphore;
GB_DEF void gb_semaphore_init (gbSemaphore *s);
GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count);
-GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1)
+GB_DEF void gb_semaphore_release(gbSemaphore *s);
GB_DEF void gb_semaphore_wait (gbSemaphore *s);
@@ -975,10 +975,10 @@ typedef struct gbThread {
pthread_t posix_handle;
#endif
- gbThreadProc *proc;
- void * user_data;
- isize user_index;
- isize return_value;
+ gbThreadProc * proc;
+ void * user_data;
+ isize user_index;
+ isize volatile return_value;
gbSemaphore semaphore;
isize stack_size;
@@ -4588,10 +4588,18 @@ gb_inline void gb_lfence(void) {
gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
#if defined(GB_SYSTEM_WINDOWS)
- gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); }
- gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); }
- gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); }
- gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); }
+ gb_inline void gb_semaphore_init(gbSemaphore *s) {
+ s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
+ }
+ gb_inline void gb_semaphore_destroy(gbSemaphore *s) {
+ CloseHandle(s->win32_handle);
+ }
+ gb_inline void gb_semaphore_post(gbSemaphore *s, i32 count) {
+ ReleaseSemaphore(s->win32_handle, count, NULL);
+ }
+ gb_inline void gb_semaphore_wait(gbSemaphore *s) {
+ WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
+ }
#elif defined(GB_SYSTEM_OSX)
gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
@@ -8975,7 +8983,7 @@ gb_inline void gb_exit(u32 code) { exit(code); }
gb_inline void gb_yield(void) {
#if defined(GB_SYSTEM_WINDOWS)
- Sleep(0);
+ YieldProcessor();
#else
sched_yield();
#endif
diff --git a/src/ir.cpp b/src/ir.cpp
index 82f9fa755..e7317a960 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -147,6 +147,7 @@ struct irProcedure {
Array<irContextData> context_stack;
+ i32 parameter_count;
irValue *return_ptr_hint_value;
Ast * return_ptr_hint_ast;
@@ -174,6 +175,7 @@ gbAllocator ir_allocator(void) {
#define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data"
#define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data"
#define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data"
+#define IR_TYPE_INFO_TAGS_NAME "__$type_info_tags_data"
#define IR_INSTR_KINDS \
@@ -424,6 +426,7 @@ enum irParamPasskind {
irParamPass_Integer, // Pass as an integer of the same size
irParamPass_ConstRef, // Pass as a pointer but the value is immutable
irParamPass_BitCast, // Pass by value and bit cast to the correct type
+ irParamPass_Tuple, // Pass across multiple parameters (System V AMD64, up to 2)
};
struct irValueParam {
@@ -432,6 +435,7 @@ struct irValueParam {
Entity * entity;
Type * type;
Type * original_type;
+ i32 index;
Array<irValue *> referrers;
};
@@ -913,15 +917,18 @@ irValue *ir_value_global(Entity *e, irValue *value) {
if (value) value->uses += 1;
return v;
}
-irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) {
+irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type, i32 index) {
irValue *v = ir_alloc_value(irValue_Param);
v->Param.kind = irParamPass_Value;
v->Param.parent = parent;
- v->Param.entity = e;
- v->Param.original_type = e->type;
+ if (e != nullptr) {
+ v->Param.entity = e;
+ v->Param.original_type = e->type;
+ }
v->Param.type = abi_type;
+ v->Param.index = index;
- if (abi_type != e->type) {
+ if (e != nullptr && abi_type != e->type) {
if (is_type_pointer(abi_type)) {
GB_ASSERT(e->kind == Entity_Variable);
v->Param.kind = irParamPass_Pointer;
@@ -934,8 +941,12 @@ irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) {
v->Param.kind = irParamPass_Value;
} else if (is_type_simd_vector(abi_type)) {
v->Param.kind = irParamPass_BitCast;
+ } else if (is_type_float(abi_type)) {
+ v->Param.kind = irParamPass_BitCast;
+ } else if (is_type_tuple(abi_type)) {
+ v->Param.kind = irParamPass_Tuple;
} else {
- GB_PANIC("Invalid abi type pass kind");
+ GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
}
}
array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here
@@ -1428,7 +1439,7 @@ irValue *ir_value_procedure(irModule *m, Entity *entity, Type *type, Ast *type_e
Type *t = base_type(type);
GB_ASSERT(is_type_proc(t));
- array_init(&v->Proc.params, ir_allocator(), 0, t->Proc.param_count);
+ array_init(&v->Proc.params, heap_allocator(), 0, t->Proc.param_count);
return v;
}
@@ -1498,7 +1509,9 @@ void ir_start_block(irProcedure *proc, irBlock *block) {
}
-
+irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t);
+irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val);
+irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
@@ -1539,6 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
if (count == 0) {
return ir_value_nil(type);
}
+ count = gb_max(cl->max_count, count);
Type *elem = base_type(type)->Slice.elem;
Type *t = alloc_type_array(elem, count);
irValue *backing_array = ir_add_module_constant(m, t, value);
@@ -1712,9 +1726,12 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) {
irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i32 index) {
- irValue *v = ir_value_param(proc, e, abi_type);
+ irValue *v = ir_value_param(proc, e, abi_type, index);
+ array_add(&proc->params, v);
irValueParam *p = &v->Param;
+ irValue *res = nullptr;
+
ir_push_debug_location(proc->module, e ? e->identifier : nullptr, proc->debug_scope, e);
defer (ir_pop_debug_location(proc->module));
@@ -1749,6 +1766,24 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i
ir_emit_store(proc, l, x);
return x;
}
+ case irParamPass_Tuple: {
+ irValue *l = ir_add_local(proc, e, expr, true, index);
+ Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type);
+ irValue *ptr = ir_emit_bitcast(proc, l, alloc_type_pointer(st));
+ if (abi_type->Tuple.variables.count > 0) {
+ array_pop(&proc->params);
+ }
+ for_array(i, abi_type->Tuple.variables) {
+ Type *t = abi_type->Tuple.variables[i]->type;
+
+ irValue *elem = ir_value_param(proc, nullptr, t, index+cast(i32)i);
+ array_add(&proc->params, elem);
+
+ irValue *dst = ir_emit_struct_ep(proc, ptr, cast(i32)i);
+ ir_emit_store(proc, dst, elem);
+ }
+ return ir_emit_load(proc, l);
+ }
}
@@ -1872,10 +1907,12 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
case Basic_string:
case Basic_any:
case Basic_rawptr:
+ case Basic_quaternion128:
+ case Basic_quaternion256:
break; // not a "DIBasicType"
}
- GB_PANIC("Unreachable");
+ GB_PANIC("Unreachable %d", kind);
return irDebugBasicEncoding_Invalid;
}
@@ -2221,27 +2258,11 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) {
di->CompositeType.tag = irDebugBasicEncoding_structure_type;
di->CompositeType.size = ir_debug_size_bits(type);
- Type *field_type = nullptr;
- if (type->Basic.kind == Basic_complex64) {
- field_type = t_f32;
- } else if (type->Basic.kind == Basic_complex128) {
- field_type = t_f64;
- } else {
- GB_PANIC("Unreachable");
- }
+ Type *field_type = base_complex_elem_type(type);
- // Field "real"
- irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type,
- 0,
- nullptr,
- di);
+ irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di);
map_set(&module->debug_info, hash_pointer(real_di), real_di);
-
- // Field "imag"
- irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type,
- real_di->DerivedType.size,
- nullptr,
- di);
map_set(&module->debug_info, hash_pointer(imag_di), imag_di);
irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2);
@@ -2253,6 +2274,40 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) {
return di;
}
+irDebugInfo *ir_add_debug_info_type_quaternion(irModule *module, Type *type) {
+ GB_ASSERT(type->kind == Type_Basic && is_type_quaternion(type));
+
+ irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType);
+ map_set(&module->debug_info, hash_type(type), di);
+
+ di->CompositeType.name = type->Basic.name;
+ di->CompositeType.tag = irDebugBasicEncoding_structure_type;
+ di->CompositeType.size = ir_debug_size_bits(type);
+
+ Type *field_type = base_complex_elem_type(type);
+
+ // @QuaternionLayout
+ irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *jmag_di = ir_add_debug_info_field_internal(module, str_lit("jmag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *kmag_di = ir_add_debug_info_field_internal(module, str_lit("kmag"), field_type, 2*cast(i32)type_size_of(field_type), nullptr, di);
+ irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 3*cast(i32)type_size_of(field_type), nullptr, di);
+
+ map_set(&module->debug_info, hash_pointer(imag_di), imag_di);
+ map_set(&module->debug_info, hash_pointer(jmag_di), jmag_di);
+ map_set(&module->debug_info, hash_pointer(kmag_di), kmag_di);
+ map_set(&module->debug_info, hash_pointer(real_di), real_di);
+
+ irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 4);
+ array_add(&elements_di->DebugInfoArray.elements, imag_di);
+ array_add(&elements_di->DebugInfoArray.elements, jmag_di);
+ array_add(&elements_di->DebugInfoArray.elements, kmag_di);
+ array_add(&elements_di->DebugInfoArray.elements, real_di);
+ di->CompositeType.elements = elements_di;
+ map_set(&module->debug_info, hash_pointer(elements_di), elements_di);
+
+ return di;
+}
+
irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) {
GB_ASSERT(type->kind == Type_Proc);
@@ -2377,10 +2432,14 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
// Composite basic types
- case Basic_complex64:
- case Basic_complex128: return ir_add_debug_info_type_complex(module, type);
- case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type);
- case Basic_any: return ir_add_debug_info_type_any(module);
+ case Basic_complex64: case Basic_complex128:
+ return ir_add_debug_info_type_complex(module, type);
+ case Basic_quaternion128: case Basic_quaternion256:
+ return ir_add_debug_info_type_quaternion(module, type);
+ case Basic_string:
+ return ir_add_debug_info_type_string(module, scope, e, type);
+ case Basic_any:
+ return ir_add_debug_info_type_any(module);
// Derived basic types
case Basic_cstring:
@@ -2920,10 +2979,6 @@ void ir_emit_unreachable(irProcedure *proc) {
ir_emit(proc, ir_instr_unreachable(proc));
}
-irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t);
-irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val);
-irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index);
-
irValue *ir_get_package_value(irModule *m, String package_name, String entity_name) {
AstPackage *rt_pkg = get_core_package(m->info, package_name);
@@ -2973,7 +3028,7 @@ Array<irValue *> ir_value_to_array(irProcedure *p, irValue *value) {
}
-irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) {
+irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) {
Type *pt = base_type(ir_type(value));
GB_ASSERT(pt->kind == Type_Proc);
Type *results = pt->Proc.results;
@@ -2983,6 +3038,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
context_ptr = ir_find_or_generate_context_ptr(p);
}
+ set_procedure_abi_types(heap_allocator(), pt);
+
bool is_c_vararg = pt->Proc.c_vararg;
isize param_count = pt->Proc.param_count;
if (is_c_vararg) {
@@ -2991,9 +3048,13 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
} else {
GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count);
}
+
+ auto processed_args = array_make<irValue *>(heap_allocator(), 0, args.count);
+
for (isize i = 0; i < param_count; i++) {
Entity *e = pt->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
+ array_add(&processed_args, args[i]);
continue;
}
GB_ASSERT(e->flags & EntityFlag_Param);
@@ -3003,21 +3064,32 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
Type *arg_type = ir_type(args[i]);
if (are_types_identical(arg_type, new_type)) {
// NOTE(bill): Done
+ array_add(&processed_args, args[i]);
} else if (!are_types_identical(original_type, new_type)) {
-
if (is_type_pointer(new_type) && !is_type_pointer(original_type)) {
- if (e->flags&EntityFlag_Value) {
- args[i] = ir_address_from_load_or_generate_local(p, args[i]);
+ if (e->flags&EntityFlag_ImplicitReference) {
+ array_add(&processed_args, ir_address_from_load_or_generate_local(p, args[i]));
} else if (!is_type_pointer(arg_type)) {
- args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16);
+ array_add(&processed_args, ir_copy_value_to_ptr(p, args[i], original_type, 16));
}
} else if (is_type_integer(new_type)) {
- args[i] = ir_emit_transmute(p, args[i], new_type);
+ array_add(&processed_args, ir_emit_transmute(p, args[i], new_type));
} else if (new_type == t_llvm_bool) {
- args[i] = ir_emit_conv(p, args[i], new_type);
+ array_add(&processed_args, ir_emit_conv(p, args[i], new_type));
} else if (is_type_simd_vector(new_type)) {
- args[i] = ir_emit_bitcast(p, args[i], new_type);
+ array_add(&processed_args, ir_emit_bitcast(p, args[i], new_type));
+ } else if (is_type_tuple(new_type)) {
+ Type *abi_type = pt->Proc.abi_compat_params[i];
+ Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type);
+ irValue *x = ir_emit_transmute(p, args[i], st);
+ for (isize j = 0; j < new_type->Tuple.variables.count; j++) {
+ irValue *xx = ir_emit_struct_ev(p, x, cast(i32)j);
+ array_add(&processed_args, xx);
+ }
}
+ } else {
+ irValue *x = ir_emit_conv(p, args[i], new_type);
+ array_add(&processed_args, x);
}
}
@@ -3042,10 +3114,10 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
return_ptr = ir_add_local_generated(p, rt, true);
}
GB_ASSERT(is_type_pointer(ir_type(return_ptr)));
- ir_emit(p, ir_instr_call(p, value, return_ptr, args, nullptr, context_ptr, inlining));
+ ir_emit(p, ir_instr_call(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining));
result = ir_emit_load(p, return_ptr);
} else {
- result = ir_emit(p, ir_instr_call(p, value, nullptr, args, abi_rt, context_ptr, inlining));
+ result = ir_emit(p, ir_instr_call(p, value, nullptr, processed_args, abi_rt, context_ptr, inlining));
if (abi_rt != results) {
result = ir_emit_transmute(p, result, rt);
}
@@ -3054,7 +3126,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
if (value->kind == irValue_Proc) {
irProcedure *the_proc = &value->Proc;
Entity *e = the_proc->entity;
- if (entity_has_deferred_procedure(e)) {
+ if (e != nullptr && entity_has_deferred_procedure(e)) {
DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind;
Entity *deferred_entity = e->Procedure.deferred_procedure.entity;
irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity));
@@ -3653,12 +3725,12 @@ struct irLoopData {
irBlock *loop;
};
-irLoopData ir_loop_start(irProcedure *proc, isize count) {
+irLoopData ir_loop_start(irProcedure *proc, isize count, Type *index_type=t_int) {
irLoopData data = {};
irValue *max = ir_const_int(count);
- data.idx_addr = ir_add_local_generated(proc, t_int, true);
+ data.idx_addr = ir_add_local_generated(proc, index_type, true);
data.body = ir_new_block(proc, nullptr, "loop.body");
data.done = ir_new_block(proc, nullptr, "loop.done");
@@ -3728,7 +3800,7 @@ irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type *
ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
}
} else {
- auto loop_data = ir_loop_start(proc, count);
+ auto loop_data = ir_loop_start(proc, count, t_i32);
irValue *e = ir_emit_load(proc, ir_emit_array_ep(proc, val, loop_data.idx));
irValue *z = ir_emit_unary_arith(proc, op, e, elem_type);
@@ -3787,7 +3859,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
}
} else {
- auto loop_data = ir_loop_start(proc, count);
+ auto loop_data = ir_loop_start(proc, count, t_i32);
irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx));
irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx));
@@ -3853,6 +3925,60 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
return ir_emit_load(proc, res);
}
+ if (is_type_quaternion(t_left)) {
+ ir_emit_comment(proc, str_lit("complex.arith.begin"));
+ defer (ir_emit_comment(proc, str_lit("complex.arith.end")));
+
+ right = ir_emit_conv(proc, right, t_left);
+
+ Type *ft = base_complex_elem_type(t_left);
+
+ if (op == Token_Add || op == Token_Sub) {
+ irValue *res = ir_add_local_generated(proc, type, false); // NOTE: initialized in full later
+ irValue *x0 = ir_emit_struct_ev(proc, left, 0);
+ irValue *x1 = ir_emit_struct_ev(proc, left, 1);
+ irValue *x2 = ir_emit_struct_ev(proc, left, 2);
+ irValue *x3 = ir_emit_struct_ev(proc, left, 3);
+
+ irValue *y0 = ir_emit_struct_ev(proc, right, 0);
+ irValue *y1 = ir_emit_struct_ev(proc, right, 1);
+ irValue *y2 = ir_emit_struct_ev(proc, right, 2);
+ irValue *y3 = ir_emit_struct_ev(proc, right, 3);
+
+ irValue *z0 = ir_emit_arith(proc, op, x0, y0, ft);
+ irValue *z1 = ir_emit_arith(proc, op, x1, y1, ft);
+ irValue *z2 = ir_emit_arith(proc, op, x2, y2, ft);
+ irValue *z3 = ir_emit_arith(proc, op, x3, y3, ft);
+
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), z0);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), z1);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), z2);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), z3);
+
+ return ir_emit_load(proc, res);
+ } else if (op == Token_Mul) {
+ auto args = array_make<irValue *>(heap_allocator(), 2);
+ args[0] = left;
+ args[1] = right;
+
+ switch (8*type_size_of(ft)) {
+ case 32: return ir_emit_runtime_call(proc, "mul_quaternion128", args);
+ case 64: return ir_emit_runtime_call(proc, "mul_quaternion256", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ } else if (op == Token_Quo) {
+ auto args = array_make<irValue *>(heap_allocator(), 2);
+ args[0] = left;
+ args[1] = right;
+
+ switch (8*type_size_of(ft)) {
+ case 32: return ir_emit_runtime_call(proc, "quo_quaternion128", args);
+ case 64: return ir_emit_runtime_call(proc, "quo_quaternion256", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ }
+ }
+
#if 0
if (op == Token_Add) {
@@ -4018,6 +4144,15 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
} else if (is_type_typeid(t)) {
irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0));
return ir_emit_comp(proc, op_kind, x, invalid_typeid);
+ } else if (is_type_bit_field(t)) {
+ auto args = array_make<irValue *>(heap_allocator(), 2);
+ irValue *lhs = ir_address_from_load_or_generate_local(proc, x);
+ args[0] = ir_emit_conv(proc, lhs, t_rawptr);
+ args[1] = ir_const_int(type_size_of(t));
+ irValue *val = ir_emit_runtime_call(proc, "memory_compare_zero", args);
+ irValue *res = ir_emit_comp(proc, op_kind, val, v_zero);
+ return ir_emit_conv(proc, res, t_bool);
+
}
return nullptr;
}
@@ -4105,6 +4240,9 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
if (op_kind == Token_NotEq) {
res = v_false;
cmp_op = Token_Or;
+ } else if (op_kind == Token_CmpEq) {
+ res = v_true;
+ cmp_op = Token_And;
}
bool inline_array_arith = type_size_of(tl) <= build_context.max_align;
@@ -4112,28 +4250,43 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
if (inline_array_arith) {
// inline
+ irValue *val = ir_add_local_generated(proc, t_bool, false);
+ ir_emit_store(proc, val, res);
for (i32 i = 0; i < count; i++) {
irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i));
irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i));
irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
- res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool);
- }
-
- return ir_emit_conv(proc, res, t_bool);
- } else {
- irValue *val = ir_add_local_generated(proc, t_bool, false);
- ir_emit_store(proc, val, res);
- auto loop_data = ir_loop_start(proc, count);
- {
- irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx));
- irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx));
- irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
- irValue *new_res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool);
+ irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool);
ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool));
}
- ir_loop_end(proc, loop_data);
return ir_emit_load(proc, val);
+ } else {
+ if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) {
+ // TODO(bill): Test to see if this is actually faster!!!!
+ auto args = array_make<irValue *>(heap_allocator(), 3);
+ args[0] = ir_emit_conv(proc, lhs, t_rawptr);
+ args[1] = ir_emit_conv(proc, rhs, t_rawptr);
+ args[2] = ir_const_int(type_size_of(tl));
+ irValue *val = ir_emit_runtime_call(proc, "memory_compare", args);
+ irValue *res = ir_emit_comp(proc, op_kind, val, v_zero);
+ return ir_emit_conv(proc, res, t_bool);
+ } else {
+ irValue *val = ir_add_local_generated(proc, t_bool, false);
+ ir_emit_store(proc, val, res);
+ auto loop_data = ir_loop_start(proc, count, t_i32);
+ {
+ irValue *i = loop_data.idx;
+ irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i));
+ irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i));
+ irValue *cmp = ir_emit_comp(proc, op_kind, x, y);
+ irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool);
+ ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool));
+ }
+ ir_loop_end(proc, loop_data);
+
+ return ir_emit_load(proc, val);
+ }
}
}
@@ -4161,7 +4314,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
}
if (is_type_complex(a)) {
- char *runtime_proc = "";
+ char const *runtime_proc = "";
i64 sz = 8*type_size_of(a);
switch (sz) {
case 64:
@@ -4185,6 +4338,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
return ir_emit_runtime_call(proc, runtime_proc, args);
}
+ if (is_type_quaternion(a)) {
+ char const *runtime_proc = "";
+ i64 sz = 8*type_size_of(a);
+ switch (sz) {
+ case 128:
+ switch (op_kind) {
+ case Token_CmpEq: runtime_proc = "quaternion128_eq"; break;
+ case Token_NotEq: runtime_proc = "quaternion128_ne"; break;
+ }
+ break;
+ case 256:
+ switch (op_kind) {
+ case Token_CmpEq: runtime_proc = "quaternion256_eq"; break;
+ case Token_NotEq: runtime_proc = "quaternion256_ne"; break;
+ }
+ break;
+ }
+ GB_ASSERT(runtime_proc != nullptr);
+
+ auto args = array_make<irValue *>(ir_allocator(), 2);
+ args[0] = left;
+ args[1] = right;
+ return ir_emit_runtime_call(proc, runtime_proc, args);
+ }
+
if (is_type_bit_set(a)) {
switch (op_kind) {
case Token_Lt:
@@ -4268,11 +4446,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
case 0: result_type = alloc_type_pointer(ft); break;
case 1: result_type = alloc_type_pointer(ft); break;
}
+ } else if (is_type_quaternion(t)) {
+ Type *ft = base_complex_elem_type(t);
+ switch (index) {
+ case 0: result_type = alloc_type_pointer(ft); break;
+ case 1: result_type = alloc_type_pointer(ft); break;
+ case 2: result_type = alloc_type_pointer(ft); break;
+ case 3: result_type = alloc_type_pointer(ft); break;
+ }
} else if (is_type_slice(t)) {
switch (index) {
case 0: result_type = alloc_type_pointer(alloc_type_pointer(t->Slice.elem)); break;
case 1: result_type = alloc_type_pointer(t_int); break;
- case 2: result_type = alloc_type_pointer(t_int); break;
}
} else if (is_type_string(t)) {
switch (index) {
@@ -4343,6 +4528,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
}
break;
}
+ case Basic_quaternion128: case Basic_quaternion256:
+ {
+ Type *ft = base_complex_elem_type(t);
+ switch (index) {
+ case 0: result_type = ft; break;
+ case 1: result_type = ft; break;
+ case 2: result_type = ft; break;
+ case 3: result_type = ft; break;
+ }
+ break;
+ }
}
break;
case Type_Struct:
@@ -4401,13 +4597,14 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
if (is_type_pointer(type)) {
type = type_deref(type);
e = ir_emit_load(proc, e);
- e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies?
+ // e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies?
}
type = core_type(type);
if (is_type_raw_union(type)) {
type = type->Struct.fields[index]->type;
- e = ir_emit_conv(proc, e, alloc_type_pointer(type));
+ GB_ASSERT(is_type_pointer(ir_type(e)));
+ e = ir_emit_bitcast(proc, e, alloc_type_pointer(type));
} else if (is_type_struct(type)) {
type = type->Struct.fields[index]->type;
e = ir_emit_struct_ep(proc, e, index);
@@ -4725,6 +4922,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
ev = exact_value_to_float(ev);
} else if (is_type_complex(dst)) {
ev = exact_value_to_complex(ev);
+ } else if (is_type_quaternion(dst)) {
+ ev = exact_value_to_quaternion(ev);
} else if (is_type_string(dst)) {
// Handled elsewhere
GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind);
@@ -4848,6 +5047,49 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
return ir_emit_load(proc, gen);
}
+ if (is_type_quaternion(src) && is_type_quaternion(dst)) {
+ // @QuaternionLayout
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, false);
+ irValue *q0 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft);
+ irValue *q1 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft);
+ irValue *q2 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft);
+ irValue *q3 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), q0);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), q1);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), q2);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), q3);
+ return ir_emit_load(proc, gen);
+ }
+
+ if (is_type_float(src) && is_type_complex(dst)) {
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, true);
+ irValue *real = ir_emit_conv(proc, value, ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real);
+ return ir_emit_load(proc, gen);
+ }
+ if (is_type_float(src) && is_type_quaternion(dst)) {
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, true);
+ irValue *real = ir_emit_conv(proc, value, ft);
+ // @QuaternionLayout
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real);
+ return ir_emit_load(proc, gen);
+ }
+ if (is_type_complex(src) && is_type_quaternion(dst)) {
+ Type *ft = base_complex_elem_type(dst);
+ irValue *gen = ir_add_local_generated(proc, dst, true);
+ irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft);
+ irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft);
+ // @QuaternionLayout
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), imag);
+ return ir_emit_load(proc, gen);
+ }
+
+
+
// float <-> integer
if (is_type_float(src) && is_type_integer(dst)) {
irConvKind kind = irConv_fptosi;
@@ -5245,12 +5487,14 @@ gb_global irValue *ir_global_type_info_member_types = nullptr;
gb_global irValue *ir_global_type_info_member_names = nullptr;
gb_global irValue *ir_global_type_info_member_offsets = nullptr;
gb_global irValue *ir_global_type_info_member_usings = nullptr;
+gb_global irValue *ir_global_type_info_member_tags = nullptr;
gb_global i32 ir_global_type_info_data_index = 0;
gb_global i32 ir_global_type_info_member_types_index = 0;
gb_global i32 ir_global_type_info_member_names_index = 0;
gb_global i32 ir_global_type_info_member_offsets_index = 0;
gb_global i32 ir_global_type_info_member_usings_index = 0;
+gb_global i32 ir_global_type_info_member_tags_index = 0;
isize ir_type_info_count(CheckerInfo *info) {
return info->minimum_dependency_type_info_set.entries.count+1;
@@ -5286,6 +5530,7 @@ enum Typeid_Kind : u8 {
Typeid_Rune,
Typeid_Float,
Typeid_Complex,
+ Typeid_Quaternion,
Typeid_String,
Typeid_Boolean,
Typeid_Any,
@@ -5402,7 +5647,8 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left,
}
ir_start_block(proc, rhs);
- array_add(&edges, ir_build_expr(proc, right));
+ irValue *edge = ir_build_expr(proc, right);
+ array_add(&edges, edge);
ir_emit_jump(proc, done);
ir_start_block(proc, done);
@@ -5411,8 +5657,6 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left,
irValue *ir_emit_logical_binary_expr(irProcedure *proc, Ast *expr) {
ast_node(be, BinaryExpr, expr);
- irBlock *rhs = ir_new_block(proc, nullptr, "logical.cmp.rhs");
- irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done");
Type *type = type_of_expr(expr);
type = default_type(type);
@@ -6038,17 +6282,77 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
return ir_emit_load(proc, dst);
}
+ case BuiltinProc_quaternion: {
+ ir_emit_comment(proc, str_lit("quaternion"));
+ irValue *real = ir_build_expr(proc, ce->args[0]);
+ irValue *imag = ir_build_expr(proc, ce->args[1]);
+ irValue *jmag = ir_build_expr(proc, ce->args[2]);
+ irValue *kmag = ir_build_expr(proc, ce->args[3]);
+
+ // @QuaternionLayout
+ irValue *dst = ir_add_local_generated(proc, tv.type, false);
+ Type *ft = base_complex_elem_type(tv.type);
+ real = ir_emit_conv(proc, real, ft);
+ imag = ir_emit_conv(proc, imag, ft);
+ jmag = ir_emit_conv(proc, jmag, ft);
+ kmag = ir_emit_conv(proc, kmag, ft);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), imag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), jmag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), kmag);
+
+ return ir_emit_load(proc, dst);
+ }
+
case BuiltinProc_real: {
ir_emit_comment(proc, str_lit("real"));
irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *real = ir_emit_struct_ev(proc, val, 0);
- return ir_emit_conv(proc, real, tv.type);
+ if (is_type_complex(ir_type(val))) {
+ irValue *real = ir_emit_struct_ev(proc, val, 0);
+ return ir_emit_conv(proc, real, tv.type);
+ } else if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *real = ir_emit_struct_ev(proc, val, 3);
+ return ir_emit_conv(proc, real, tv.type);
+ }
+ GB_PANIC("invalid type for real");
+ return nullptr;
}
case BuiltinProc_imag: {
ir_emit_comment(proc, str_lit("imag"));
irValue *val = ir_build_expr(proc, ce->args[0]);
- irValue *imag = ir_emit_struct_ev(proc, val, 1);
- return ir_emit_conv(proc, imag, tv.type);
+ if (is_type_complex(ir_type(val))) {
+ irValue *imag = ir_emit_struct_ev(proc, val, 1);
+ return ir_emit_conv(proc, imag, tv.type);
+ } else if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *imag = ir_emit_struct_ev(proc, val, 0);
+ return ir_emit_conv(proc, imag, tv.type);
+ }
+ GB_PANIC("invalid type for imag");
+ return nullptr;
+ }
+ case BuiltinProc_jmag: {
+ ir_emit_comment(proc, str_lit("jmag"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *imag = ir_emit_struct_ev(proc, val, 1);
+ return ir_emit_conv(proc, imag, tv.type);
+ }
+ GB_PANIC("invalid type for jmag");
+ return nullptr;
+ }
+ case BuiltinProc_kmag: {
+ ir_emit_comment(proc, str_lit("kmag"));
+ irValue *val = ir_build_expr(proc, ce->args[0]);
+ if (is_type_quaternion(ir_type(val))) {
+ // @QuaternionLayout
+ irValue *imag = ir_emit_struct_ev(proc, val, 2);
+ return ir_emit_conv(proc, imag, tv.type);
+ }
+ GB_PANIC("invalid type for kmag");
+ return nullptr;
}
case BuiltinProc_conj: {
@@ -6063,6 +6367,20 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real);
ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag);
+ } else if (is_type_quaternion(t)) {
+ // @QuaternionLayout
+ res = ir_add_local_generated(proc, tv.type, false);
+ irValue *real = ir_emit_struct_ev(proc, val, 3);
+ irValue *imag = ir_emit_struct_ev(proc, val, 0);
+ irValue *jmag = ir_emit_struct_ev(proc, val, 1);
+ irValue *kmag = ir_emit_struct_ev(proc, val, 2);
+ imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag));
+ jmag = ir_emit_unary_arith(proc, Token_Sub, jmag, ir_type(jmag));
+ kmag = ir_emit_unary_arith(proc, Token_Sub, kmag, ir_type(kmag));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), real);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), imag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), jmag);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), kmag);
}
return ir_emit_load(proc, res);
}
@@ -6133,7 +6451,16 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
return x;
}
ir_emit_comment(proc, str_lit("abs"));
- if (is_type_complex(t)) {
+ if (is_type_quaternion(t)) {
+ i64 sz = 8*type_size_of(t);
+ auto args = array_make<irValue *>(ir_allocator(), 1);
+ args[0] = x;
+ switch (sz) {
+ case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args);
+ case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args);
+ }
+ GB_PANIC("Unknown complex type");
+ } else if (is_type_complex(t)) {
i64 sz = 8*type_size_of(t);
auto args = array_make<irValue *>(ir_allocator(), 1);
args[0] = x;
@@ -6312,6 +6639,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
return ir_emit_conv(proc, x, tv.type);
}
+ if (tv.value.kind == ExactValue_Typeid) {
+ irValue *v = ir_typeid(proc->module, tv.value.value_typeid);
+ return ir_emit_conv(proc, v, tv.type);
+ }
+
return ir_add_module_constant(proc->module, tv.type, tv.value);
}
@@ -6546,9 +6878,6 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case_end;
case_ast_node(be, BinaryExpr, expr);
- irValue *left = ir_build_expr(proc, be->left);
- Type *type = default_type(tv.type);
-
switch (be->op.kind) {
case Token_Add:
case Token_Sub:
@@ -6562,6 +6891,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case Token_AndNot:
case Token_Shl:
case Token_Shr: {
+ irValue *left = ir_build_expr(proc, be->left);
+ Type *type = default_type(tv.type);
irValue *right = ir_build_expr(proc, be->right);
return ir_emit_arith(proc, be->op.kind, left, right, type);
}
@@ -6573,10 +6904,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case Token_LtEq:
case Token_Gt:
case Token_GtEq: {
+ irValue *left = ir_build_expr(proc, be->left);
+ Type *type = default_type(tv.type);
irValue *right = ir_build_expr(proc, be->right);
irValue *cmp = ir_emit_comp(proc, be->op.kind, left, right);
return ir_emit_conv(proc, cmp, type);
- break;
}
case Token_CmpAnd:
@@ -6586,6 +6918,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
case Token_in:
case Token_notin: {
+ irValue *left = ir_build_expr(proc, be->left);
+ Type *type = default_type(tv.type);
irValue *right = ir_build_expr(proc, be->right);
Type *rt = base_type(ir_type(right));
switch (rt->kind) {
@@ -6687,7 +7021,34 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
}
// NOTE(bill): Regular call
- irValue *value = ir_build_expr(proc, ce->proc);
+ irValue *value = nullptr;
+ Ast *proc_expr = unparen_expr(ce->proc);
+ if (proc_expr->tav.mode == Addressing_Constant) {
+ ExactValue v = proc_expr->tav.value;
+ switch (v.kind) {
+ case ExactValue_Integer:
+ {
+ u64 u = big_int_to_u64(&v.value_integer);
+ irValue *x = ir_const_uintptr(u);
+ x = ir_emit_conv(proc, x, t_rawptr);
+ value = ir_emit_conv(proc, x, proc_expr->tav.type);
+ break;
+ }
+ case ExactValue_Pointer:
+ {
+ u64 u = cast(u64)v.value_pointer;
+ irValue *x = ir_const_uintptr(u);
+ x = ir_emit_conv(proc, x, t_rawptr);
+ value = ir_emit_conv(proc, x, proc_expr->tav.type);
+ break;
+ }
+ }
+ }
+
+ if (value == nullptr) {
+ value = ir_build_expr(proc, proc_expr);
+ }
+
GB_ASSERT(value != nullptr);
Type *proc_type_ = base_type(ir_type(value));
GB_ASSERT(proc_type_->kind == Type_Proc);
@@ -7501,13 +7862,55 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
// NOTE(bill): Separate value, gep, store into their own chunks
for_array(i, cl->elems) {
Ast *elem = cl->elems[i];
- if (ir_is_elem_const(proc->module, elem, et)) {
- continue;
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ if (ir_is_elem_const(proc->module, fv->value, et)) {
+ continue;
+ }
+ 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;
+ }
+
+ irValue *value = ir_build_expr(proc, fv->value);
+
+ for (i64 k = lo; k < hi; k++) {
+ irCompoundLitElemTempData data = {};
+ data.value = value;
+ data.elem_index = cast(i32)k;
+ array_add(&temp_data, data);
+ }
+
+ } else {
+ auto tav = fv->field->tav;
+ GB_ASSERT(tav.mode == Addressing_Constant);
+ i64 index = exact_value_to_i64(tav.value);
+
+ irCompoundLitElemTempData data = {};
+ data.value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+ data.expr = fv->value;
+ data.elem_index = cast(i32)index;
+ array_add(&temp_data, data);
+ }
+
+ } else {
+ if (ir_is_elem_const(proc->module, elem, et)) {
+ continue;
+ }
+ irCompoundLitElemTempData data = {};
+ data.expr = elem;
+ data.elem_index = cast(i32)i;
+ array_add(&temp_data, data);
}
- irCompoundLitElemTempData data = {};
- data.expr = elem;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
}
for_array(i, temp_data) {
@@ -7522,12 +7925,15 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
defer (proc->return_ptr_hint_value = return_ptr_hint_value);
defer (proc->return_ptr_hint_used = return_ptr_hint_used);
+ irValue *field_expr = temp_data[i].value;
Ast *expr = temp_data[i].expr;
proc->return_ptr_hint_value = temp_data[i].gep;
proc->return_ptr_hint_ast = unparen_expr(expr);
- irValue *field_expr = ir_build_expr(proc, expr);
+ if (field_expr == nullptr) {
+ field_expr = ir_build_expr(proc, expr);
+ }
Type *t = ir_type(field_expr);
GB_ASSERT(t->kind != Type_Tuple);
irValue *ev = ir_emit_conv(proc, field_expr, et);
@@ -7560,18 +7966,64 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
for_array(i, cl->elems) {
Ast *elem = cl->elems[i];
- if (ir_is_elem_const(proc->module, elem, et)) {
- continue;
- }
- irValue *field_expr = ir_build_expr(proc, elem);
- Type *t = ir_type(field_expr);
- GB_ASSERT(t->kind != Type_Tuple);
- irValue *ev = ir_emit_conv(proc, field_expr, et);
+ if (elem->kind == Ast_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+
+ if (ir_is_elem_const(proc->module, fv->value, et)) {
+ continue;
+ }
+
+ 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;
+ }
+
+ irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+
+ for (i64 k = lo; k < hi; k++) {
+ irCompoundLitElemTempData data = {};
+ data.value = value;
+ data.elem_index = cast(i32)k;
+ array_add(&temp_data, data);
+ }
+
+ } else {
+ GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+ i64 index = exact_value_to_i64(fv->field->tav.value);
- irCompoundLitElemTempData data = {};
- data.value = ev;
- data.elem_index = cast(i32)i;
- array_add(&temp_data, data);
+ irValue *field_expr = ir_build_expr(proc, fv->value);
+ GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+
+ irValue *ev = ir_emit_conv(proc, field_expr, et);
+
+ irCompoundLitElemTempData data = {};
+ data.value = ev;
+ data.elem_index = cast(i32)index;
+ array_add(&temp_data, data);
+ }
+ } else {
+ if (ir_is_elem_const(proc->module, elem, et)) {
+ continue;
+ }
+ irValue *field_expr = ir_build_expr(proc, elem);
+ GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+
+ irValue *ev = ir_emit_conv(proc, field_expr, et);
+
+ irCompoundLitElemTempData data = {};
+ data.value = ev;
+ data.elem_index = cast(i32)i;
+ array_add(&temp_data, data);
+ }
}
for_array(i, temp_data) {
@@ -7592,28 +8044,64 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- Type *elem = bt->DynamicArray.elem;
+ Type *et = bt->DynamicArray.elem;
gbAllocator a = ir_allocator();
- irValue *size = ir_const_int(type_size_of(elem));
- irValue *align = ir_const_int(type_align_of(elem));
+ irValue *size = ir_const_int(type_size_of(et));
+ irValue *align = ir_const_int(type_align_of(et));
+
+ i64 item_count = gb_max(cl->max_count, cl->elems.count);
{
+
auto args = array_make<irValue *>(a, 5);
args[0] = ir_emit_conv(proc, v, t_rawptr);
args[1] = size;
args[2] = align;
- args[3] = ir_const_int(2*cl->elems.count);
+ args[3] = ir_const_int(2*item_count); // TODO(bill): Is this too much waste?
args[4] = ir_emit_source_code_location(proc, proc_name, pos);
ir_emit_runtime_call(proc, "__dynamic_array_reserve", args);
}
- i64 item_count = cl->elems.count;
- irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
+ irValue *items = ir_generate_array(proc->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
+
+ for_array(i, cl->elems) {
+ Ast *elem = cl->elems[i];
+ if (elem->kind == Ast_FieldValue) {
+ 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;
+ }
- for_array(field_index, cl->elems) {
- Ast *f = cl->elems[field_index];
- irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem);
- irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
- ir_emit_store(proc, ep, value);
+ irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+
+ for (i64 k = lo; k < hi; k++) {
+ irValue *ep = ir_emit_array_epi(proc, items, cast(i32)k);
+ ir_emit_store(proc, ep, value);
+ }
+ } else {
+ GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+
+ i64 field_index = exact_value_to_i64(fv->field->tav.value);
+
+ irValue *ev = ir_build_expr(proc, fv->value);
+ irValue *value = ir_emit_conv(proc, ev, et);
+ irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
+ ir_emit_store(proc, ep, value);
+ }
+ } else {
+ irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
+ irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);
+ ir_emit_store(proc, ep, value);
+ }
}
{
@@ -7907,24 +8395,27 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) {
name = e->Procedure.link_name;
}
+ HashKey key = hash_string(name);
+ irValue **prev_value = map_get(&proc->module->members, key);
+ if (prev_value != nullptr) {
+ // NOTE(bill): Don't do mutliple declarations in the IR
+ return;
+ }
+
+
irValue *value = ir_value_procedure(proc->module, e, e->type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
value->Proc.inlining = pl->inlining;
- ir_module_add_value(proc->module, e, value);
- ir_build_proc(value, proc);
-
if (value->Proc.is_foreign || value->Proc.is_export) {
- HashKey key = hash_string(name);
- irValue **prev_value = map_get(&proc->module->members, key);
- if (prev_value == nullptr) {
- // NOTE(bill): Don't do mutliple declarations in the IR
- map_set(&proc->module->members, key, value);
- }
+ map_set(&proc->module->members, key, value);
} else {
array_add(&proc->children, &value->Proc);
}
+
+ ir_module_add_value(proc->module, e, value);
+ ir_build_proc(value, proc);
}
}
}
@@ -8806,6 +9297,150 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
ir_start_block(proc, done);
case_end;
+ case_ast_node(rs, InlineRangeStmt, node);
+ ir_emit_comment(proc, str_lit("InlineRangeStmt"));
+ ir_open_scope(proc); // Open scope here
+
+ Type *val0_type = nullptr;
+ Type *val1_type = nullptr;
+ if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) {
+ val0_type = type_of_expr(rs->val0);
+ }
+ if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) {
+ val1_type = type_of_expr(rs->val1);
+ }
+
+ if (val0_type != nullptr) {
+ ir_add_local_for_identifier(proc, rs->val0, true);
+ }
+ if (val1_type != nullptr) {
+ ir_add_local_for_identifier(proc, rs->val1, true);
+ }
+
+ irValue *val = nullptr;
+ irValue *key = nullptr;
+ irBlock *loop = nullptr;
+ irBlock *done = nullptr;
+ Ast *expr = unparen_expr(rs->expr);
+
+ TypeAndValue tav = type_and_value_of_expr(expr);
+
+ if (is_ast_range(expr)) {
+
+ irAddr val0_addr = {};
+ irAddr val1_addr = {};
+ if (val0_type) val0_addr = ir_build_addr(proc, rs->val0);
+ if (val1_type) val1_addr = ir_build_addr(proc, rs->val1);
+
+ TokenKind op = expr->BinaryExpr.op.kind;
+ Ast *start_expr = expr->BinaryExpr.left;
+ Ast *end_expr = expr->BinaryExpr.right;
+ GB_ASSERT(start_expr->tav.mode == Addressing_Constant);
+ GB_ASSERT(end_expr->tav.mode == Addressing_Constant);
+
+ ExactValue start = start_expr->tav.value;
+ ExactValue end = end_expr->tav.value;
+ if (op == Token_Ellipsis) { // .. [start, end]
+ ExactValue index = exact_value_i64(0);
+ for (ExactValue val = start;
+ compare_exact_values(Token_LtEq, val, end);
+ val = exact_value_increment_one(val), index = exact_value_increment_one(index)) {
+
+ if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index));
+
+ ir_build_stmt(proc, rs->body);
+ }
+ } else if (op == Token_RangeHalf) { // ..< [start, end)
+ ExactValue index = exact_value_i64(0);
+ for (ExactValue val = start;
+ compare_exact_values(Token_Lt, val, end);
+ val = exact_value_increment_one(val), index = exact_value_increment_one(index)) {
+
+ if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index));
+
+ ir_build_stmt(proc, rs->body);
+ }
+ }
+
+
+ } else if (tav.mode == Addressing_Type) {
+ GB_ASSERT(is_type_enum(type_deref(tav.type)));
+ Type *et = type_deref(tav.type);
+ Type *bet = base_type(et);
+
+ irAddr val0_addr = {};
+ irAddr val1_addr = {};
+ if (val0_type) val0_addr = ir_build_addr(proc, rs->val0);
+ if (val1_type) val1_addr = ir_build_addr(proc, rs->val1);
+
+ for_array(i, bet->Enum.fields) {
+ Entity *field = bet->Enum.fields[i];
+ GB_ASSERT(field->kind == Entity_Constant);
+ if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, field->Constant.value));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i)));
+
+ ir_build_stmt(proc, rs->body);
+ }
+ } else {
+ irAddr val0_addr = {};
+ irAddr val1_addr = {};
+ if (val0_type) val0_addr = ir_build_addr(proc, rs->val0);
+ if (val1_type) val1_addr = ir_build_addr(proc, rs->val1);
+
+ GB_ASSERT(expr->tav.mode == Addressing_Constant);
+
+ Type *t = base_type(expr->tav.type);
+
+
+ switch (t->kind) {
+ case Type_Basic:
+ GB_ASSERT(is_type_string(t));
+ {
+ ExactValue value = expr->tav.value;
+ GB_ASSERT(value.kind == ExactValue_String);
+ String str = value.value_string;
+ Rune codepoint = 0;
+ isize offset = 0;
+ do {
+ isize width = gb_utf8_decode(str.text+offset, str.len-offset, &codepoint);
+ if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, exact_value_i64(codepoint)));
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(offset)));
+ ir_build_stmt(proc, rs->body);
+
+ offset += width;
+ } while (offset < str.len);
+ }
+ break;
+ case Type_Array:
+ if (t->Array.count > 0) {
+ irValue *val = ir_build_expr(proc, expr);
+ irValue *val_addr = ir_address_from_load_or_generate_local(proc, val);
+
+ for (i64 i = 0; i < t->Array.count; i++) {
+ if (val0_type) {
+ // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32
+ irValue *elem = ir_emit_array_epi(proc, val_addr, cast(i32)i);
+ ir_addr_store(proc, val0_addr, ir_emit_load(proc, elem));
+ }
+ if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i)));
+
+ ir_build_stmt(proc, rs->body);
+ }
+
+ }
+ break;
+ default:
+ GB_PANIC("Invalid inline for type");
+ break;
+ }
+ }
+
+
+ ir_close_scope(proc, irDeferExit_Default, nullptr);
+ case_end;
+
case_ast_node(ss, SwitchStmt, node);
ir_emit_comment(proc, str_lit("SwitchStmt"));
if (ss->init != nullptr) {
@@ -9084,6 +9719,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
////////////////////////////////////////////////////////////////
void ir_number_proc_registers(irProcedure *proc) {
+ // i32 reg_index = proc->parameter_count;
i32 reg_index = 0;
for_array(i, proc->blocks) {
irBlock *b = proc->blocks[i];
@@ -9139,13 +9775,15 @@ void ir_begin_procedure_body(irProcedure *proc) {
proc->entry_block = ir_new_block(proc, proc->type_expr, "entry");
ir_start_block(proc, proc->entry_block);
+ i32 parameter_index = 0;
+
if (proc->type->Proc.return_by_pointer) {
// NOTE(bill): this must be the first parameter stored
Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(proc->type->Proc.results));
Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
e->flags |= EntityFlag_Sret | EntityFlag_NoAlias;
- irValue *param = ir_value_param(proc, e, ptr_type);
+ irValue *param = ir_value_param(proc, e, ptr_type, -1);
param->Param.kind = irParamPass_Pointer;
ir_module_add_value(proc->module, e, param);
@@ -9174,13 +9812,19 @@ void ir_begin_procedure_body(irProcedure *proc) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
+ parameter_index += 1;
continue;
}
Type *abi_type = proc->type->Proc.abi_compat_params[i];
- if (e->token.string != "" && !is_blank_ident(e->token)) {
- irValue *param = ir_add_param(proc, e, name, abi_type, cast(i32)(i+1));
- array_add(&proc->params, param);
+ if (e->token.string != "") {
+ ir_add_param(proc, e, name, abi_type, parameter_index);
+ }
+
+ if (is_type_tuple(abi_type)) {
+ parameter_index += cast(i32)abi_type->Tuple.variables.count;
+ } else {
+ parameter_index += 1;
}
}
} else {
@@ -9189,15 +9833,20 @@ void ir_begin_procedure_body(irProcedure *proc) {
for_array(i, params->variables) {
Entity *e = params->variables[i];
if (e->kind != Entity_Variable) {
+ parameter_index += 1;
continue;
}
Type *abi_type = e->type;
if (abi_types.count > 0) {
abi_type = abi_types[i];
}
- if (e->token.string != "" && !is_blank_ident(e->token)) {
- irValue *param = ir_add_param(proc, e, nullptr, abi_type, cast(i32)(i+1));
- array_add(&proc->params, param);
+ if (e->token.string != "") {
+ ir_add_param(proc, e, nullptr, abi_type, parameter_index);
+ }
+ if (is_type_tuple(abi_type)) {
+ parameter_index += cast(i32)abi_type->Tuple.variables.count;
+ } else {
+ parameter_index += 1;
}
}
}
@@ -9239,11 +9888,13 @@ void ir_begin_procedure_body(irProcedure *proc) {
if (proc->type->Proc.calling_convention == ProcCC_Odin) {
Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
e->flags |= EntityFlag_NoAlias;
- irValue *param = ir_value_param(proc, e, e->type);
+ irValue *param = ir_value_param(proc, e, e->type, -1);
ir_module_add_value(proc->module, e, param);
irContextData ctx = {param, proc->scope_index};
array_add(&proc->context_stack, ctx);
}
+
+ proc->parameter_count = parameter_index;
}
@@ -9370,6 +10021,8 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) {
void ir_build_proc(irValue *value, irProcedure *parent) {
irProcedure *proc = &value->Proc;
+ set_procedure_abi_types(heap_allocator(), proc->type);
+
proc->parent = parent;
if (proc->body != nullptr) {
@@ -9561,13 +10214,27 @@ void ir_init_module(irModule *m, Checker *c) {
map_set(&m->members, hash_string(name), g);
ir_global_type_info_member_usings = g;
}
+
+ {
+ String name = str_lit(IR_TYPE_INFO_TAGS_NAME);
+ Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
+ alloc_type_array(t_string, count), false);
+ irValue *g = ir_value_global(e, nullptr);
+ ir_module_add_value(m, e, g);
+ map_set(&m->members, hash_string(name), g);
+ ir_global_type_info_member_tags = g;
+ }
}
}
}
{
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompileUnit);
- di->CompileUnit.file = m->info->files.entries[0].value; // Zeroth is the init file
+
+ GB_ASSERT(m->info->files.entries.count > 0);
+ AstFile *file = m->info->files.entries[0].value;
+
+ di->CompileUnit.file = file; // Zeroth is the init file
di->CompileUnit.producer = str_lit("odin");
map_set(&m->debug_info, hash_pointer(m), di);
@@ -9586,6 +10253,13 @@ void ir_init_module(irModule *m, Checker *c) {
array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ??
}
+
+ {
+ for_array(i, m->info->files.entries) {
+ AstFile *file = m->info->files.entries[i].value;
+ ir_add_debug_info_file(m, file);
+ }
+ }
}
void ir_destroy_module(irModule *m) {
@@ -9694,6 +10368,11 @@ irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) {
ir_global_type_info_member_usings_index += cast(i32)count;
return offset;
}
+irValue *ir_type_info_member_tags_offset(irProcedure *proc, isize count) {
+ irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_tags, ir_global_type_info_member_tags_index);
+ ir_global_type_info_member_tags_index += cast(i32)count;
+ return offset;
+}
@@ -9832,6 +10511,11 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr);
break;
+ case Basic_quaternion128:
+ case Basic_quaternion256:
+ tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr);
+ break;
+
case Basic_rawptr:
tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr);
break;
@@ -10039,9 +10723,9 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *is_packed = ir_const_bool(t->Struct.is_packed);
irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union);
irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_raw_union);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_custom_align);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
}
isize count = t->Struct.fields.count;
@@ -10050,6 +10734,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *memory_names = ir_type_info_member_names_offset (proc, count);
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count);
irValue *memory_usings = ir_type_info_member_usings_offset (proc, count);
+ irValue *memory_tags = ir_type_info_member_tags_offset (proc, count);
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
for (isize source_index = 0; source_index < count; source_index++) {
@@ -10065,7 +10750,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *index = ir_const_int(source_index);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index);
- irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index);
+ irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
@@ -10074,6 +10759,15 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
}
ir_emit_store(proc, offset, ir_const_uintptr(foffset));
ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0));
+
+ if (t->Struct.tags.count > 0) {
+ String tag_string = t->Struct.tags[source_index];
+ if (tag_string.len > 0) {
+ irValue *tag_ptr = ir_emit_ptr_offset(proc, memory_tags, index);
+ ir_emit_store(proc, tag_ptr, ir_const_string(tag_string));
+ }
+ }
+
}
irValue *cv = ir_const_int(count);
@@ -10081,6 +10775,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv);
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv);
+ ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 4), memory_tags, cv);
}
break;
}
@@ -10482,12 +11177,14 @@ void ir_gen_tree(irGen *s) {
// main :: proc(argc: i32, argv: ^^u8) -> i32
String name = str_lit("main");
+#if 0
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
// This is a bit hacky,
// because this makes this function the first function run in the executable
// so it won't actually have the argc/argv arguments.
name = str_lit("ProgramEntry");
}
+#endif
Type *proc_params = alloc_type_tuple();
Type *proc_results = alloc_type_tuple();
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index b008fa682..d47dfc898 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
+ set_procedure_abi_types(heap_allocator(), t);
+
i64 word_bits = 8*build_context.word_size;
t = base_type(t);
GB_ASSERT(is_type_proc(t));
isize param_count = t->Proc.param_count;
isize result_count = t->Proc.result_count;
+
ir_print_proc_results(f, m, t);
ir_write_string(f, str_lit(" ("));
if (t->Proc.return_by_pointer) {
@@ -418,20 +421,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
}
return;
- // case Basic_f16: ir_write_str_lit(f, "half"); return;
- case Basic_f32: ir_write_str_lit(f, "float"); return;
- case Basic_f64: ir_write_str_lit(f, "double"); return;
+ // case Basic_f16: ir_write_str_lit(f, "half"); return;
+ case Basic_f32: ir_write_str_lit(f, "float"); return;
+ case Basic_f64: ir_write_str_lit(f, "double"); return;
+
+ // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
+ case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
+ case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
- // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return;
- case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
- case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
+ case Basic_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_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
- case Basic_string: ir_write_str_lit(f, "%..string"); return;
- case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
+ case Basic_any: ir_write_str_lit(f, "%..any"); return;
+ case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
+ case Basic_string: ir_write_str_lit(f, "%..string"); return;
+ case Basic_cstring: ir_write_str_lit(f, "i8*"); return;
- case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
+ case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return;
}
break;
@@ -767,15 +773,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
case ExactValue_Float: {
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
type = core_type(type);
- u64 u = bit_cast<u64>(value.value_float);
+ u64 u_64 = bit_cast<u64>(value.value_float);
+ u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
+ #if 0
switch (type->Basic.kind) {
case Basic_f32:
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
// a 64 bit number if bits_of(float type) <= 64.
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
- // 64 bit mantissa: 52 bits
- // 32 bit mantissa: 23 bits
- // 16 bit mantissa: 10 bits
+ // 64 bit mantissa: 52 bits ==> 52-52 == 0
+ // 32 bit mantissa: 23 bits ==> 52-23 == 29
+ // 16 bit mantissa: 10 bits ==> 52=10 == 42
// 29 == 52-23
u >>= 29;
u <<= 29;
@@ -792,9 +800,24 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_fprintf(f, "0x%016llx", u);
break;
}
+ #else
+ switch (type->Basic.kind) {
+ case Basic_f32: {
+ ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
+ break;
+ }
+ case Basic_f64:
+ ir_fprintf(f, "0x%016llx", u_64);
+ break;
+ default:
+ ir_fprintf(f, "0x%016llx", u_64);
+ break;
+ }
+ #endif
break;
}
case ExactValue_Complex: {
+ // xy/ri format
type = core_type(type);
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
@@ -807,6 +830,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_byte(f, '}');
break;
}
+
+ case ExactValue_Quaternion: {
+ // xyzw/ijkr format
+ type = core_type(type);
+ GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
+ Type *ft = base_complex_elem_type(type);
+ ir_write_byte(f, ' ');
+ ir_write_byte(f, '{');
+ ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+ ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
+ ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+ ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
+ ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+ ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
+ ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+ ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
+ ir_write_byte(f, '}');
+ break;
+ }
+
case ExactValue_Pointer:
if (value.value_pointer == 0) {
if (is_type_typeid(type)) {
@@ -836,22 +879,86 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_str_lit(f, "zeroinitializer");
break;
}
- GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
+ if (cl->elems[0]->kind == Ast_FieldValue) {
+ // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
+ ir_write_byte(f, '[');
+ for (i64 i = 0; i < type->Array.count; i++) {
+ if (i > 0) ir_write_str_lit(f, ", ");
+
+ 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;
+ }
+ }
+ }
- ir_write_byte(f, '[');
+ 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);
- for (isize i = 0; i < elem_count; i++) {
- if (i > 0) ir_write_str_lit(f, ", ");
- TypeAndValue tav = cl->elems[i]->tav;
- GB_ASSERT(tav.mode != Addressing_Invalid);
- ir_print_compound_element(f, m, tav.value, elem_type);
- }
- for (isize i = elem_count; i < type->Array.count; i++) {
- if (i >= elem_count) ir_write_str_lit(f, ", ");
- ir_print_compound_element(f, m, empty_exact_value, elem_type);
- }
+ ir_write_byte(f, '[');
- ir_write_byte(f, ']');
+ for (isize i = 0; i < elem_count; i++) {
+ if (i > 0) ir_write_str_lit(f, ", ");
+ TypeAndValue tav = cl->elems[i]->tav;
+ GB_ASSERT(tav.mode != Addressing_Invalid);
+ ir_print_compound_element(f, m, tav.value, elem_type);
+ }
+ for (isize i = elem_count; i < type->Array.count; i++) {
+ if (i >= elem_count) ir_write_str_lit(f, ", ");
+ ir_print_compound_element(f, m, empty_exact_value, elem_type);
+ }
+
+ ir_write_byte(f, ']');
+ }
} else if (is_type_simd_vector(type)) {
ast_node(cl, CompoundLit, value.value_compound);
@@ -927,7 +1034,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
if (type->Struct.is_packed) ir_write_byte(f, '<');
ir_write_byte(f, '{');
if (type->Struct.custom_align > 0) {
- ir_fprintf(f, "[0 x <%lld x i8>] zeroinitializer", cast(i64)type->Struct.custom_align);
+ ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align);
+ ir_write_str_lit(f, " zeroinitializer");
if (value_count > 0) {
ir_write_string(f, str_lit(", "));
}
@@ -1089,7 +1197,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
break;
}
case irValue_Param:
- ir_print_encoded_local(f, value->Param.entity->token.string);
+ if (value->Param.index >= 0) {
+ ir_fprintf(f, "%%_.%d", value->Param.index);
+ } else {
+ ir_print_encoded_local(f, value->Param.entity->token.string);
+ }
break;
case irValue_SourceCodeLocation: {
irValue *file = value->SourceCodeLocation.file;
@@ -1124,7 +1236,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
switch (cc) {
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
- case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
+ // case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
+ case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
case ProcCC_None: ir_write_str_lit(f, ""); break;
@@ -1134,8 +1247,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
ir_print_type(f, m, t_context_ptr);
- ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
- // ir_write_str_lit(f, " noalias nonnull nocapture ");
+ // ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
+ ir_write_str_lit(f, " noalias nonnull nocapture ");
}
void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
@@ -1186,6 +1299,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_write_str_lit(f, ", ");
ir_print_type(f, m, type);
ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
+ // ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
break;
}
@@ -1888,11 +2002,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
+ if (e->flags&EntityFlag_ImplicitReference) {
+ ir_write_str_lit(f, " nonnull dereferenceable");
+ }
ir_write_byte(f, ' ');
irValue *arg = call->args[i];
- if (is_type_boolean(t)) {
-
- }
ir_print_value(f, m, arg, t);
param_index++;
}
@@ -1907,24 +2021,43 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
param_index++;
}
} else {
- GB_ASSERT(call->args.count == params->variables.count);
+ // GB_ASSERT(call->args.count == params->variables.count);
+ isize arg_index = 0;
for_array(i, params->variables) {
Entity *e = params->variables[i];
GB_ASSERT(e != nullptr);
- if (e->kind != Entity_Variable) continue;
+ if (e->kind != Entity_Variable) {
+ arg_index++;
+ continue;
+ }
if (param_index > 0) ir_write_str_lit(f, ", ");
- irValue *arg = call->args[i];
Type *t = proc_type->Proc.abi_compat_params[i];
-
- ir_print_type(f, m, t);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
+ 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);
+ if (e->flags&EntityFlag_NoAlias) {
+ ir_write_str_lit(f, " noalias");
+ }
+ ir_write_byte(f, ' ');
+ ir_print_value(f, m, arg, t);
+ param_index++;
}
- ir_write_byte(f, ' ');
- ir_print_value(f, m, arg, t);
- param_index++;
}
}
}
@@ -1995,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
+ set_procedure_abi_types(heap_allocator(), proc->type);
+
if (proc->body == nullptr) {
ir_write_str_lit(f, "declare ");
// if (proc->tags & ProcTag_dll_import) {
@@ -2043,7 +2178,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (param_count > 0) {
TypeTuple *params = &proc_type->params->Tuple;
- for (isize i = 0; i < param_count; i++) {
+ isize parameter_index = 0;
+ for (isize i = 0; i < param_count; i++, parameter_index++) {
Entity *e = params->variables[i];
Type *original_type = e->type;
Type *abi_type = proc_type->abi_compat_params[i];
@@ -2053,16 +2189,29 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (i+1 == params->variables.count && proc_type->c_vararg) {
ir_write_str_lit(f, " ...");
} else {
- ir_print_type(f, m, abi_type);
- if (e->flags&EntityFlag_NoAlias) {
- ir_write_str_lit(f, " noalias");
- }
- if (proc->body != nullptr) {
- if (e->token.string != "" && !is_blank_ident(e->token)) {
- ir_write_byte(f, ' ');
- ir_print_encoded_local(f, e->token.string);
- } else {
- ir_fprintf(f, " %%_.param_%td", i);
+ if (is_type_tuple(abi_type)) {
+ for_array(j, abi_type->Tuple.variables) {
+ if (j > 0) ir_write_string(f, str_lit(", "));
+
+ Type *tft = abi_type->Tuple.variables[j]->type;
+ ir_print_type(f, m, tft);
+ if (e->flags&EntityFlag_NoAlias) {
+ ir_write_str_lit(f, " noalias");
+ }
+
+ if (proc->body != nullptr) {
+ ir_fprintf(f, " %%_.%td", parameter_index+j);
+ }
+ }
+ parameter_index += abi_type->Tuple.variables.count-1;
+ param_index += abi_type->Tuple.variables.count-1;
+ } else {
+ ir_print_type(f, m, abi_type);
+ if (e->flags&EntityFlag_NoAlias) {
+ ir_write_str_lit(f, " noalias");
+ }
+ if (proc->body != nullptr) {
+ ir_fprintf(f, " %%_.%td", parameter_index);
}
}
}
@@ -2176,6 +2325,22 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
ir_write_byte(f, '\n');
}
+bool ir_print_global_type_allowed(Type *t) {
+ if (t == nullptr) {
+ return true;
+ }
+ t = core_type(t);
+ switch (t->kind) {
+ case Type_DynamicArray:
+ case Type_Map:
+ case Type_Union:
+ case Type_BitField:
+ return false;
+ }
+
+ return true;
+}
+
void print_llvm_ir(irGen *ir) {
irModule *m = &ir->module;
@@ -2184,9 +2349,11 @@ void print_llvm_ir(irGen *ir) {
defer (ir_file_buffer_destroy(f));
i32 word_bits = cast(i32)(8*build_context.word_size);
- if (build_context.ODIN_OS == "osx" || build_context.ODIN_OS == "macos") {
+ if (build_context.ODIN_OS == "darwin") {
GB_ASSERT(word_bits == 64);
- ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n\n");
+ ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n");
+ ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n");
+ ir_write_str_lit(f, "\n");
} else if (build_context.ODIN_OS == "windows") {
ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
@@ -2210,6 +2377,13 @@ void print_llvm_ir(irGen *ir) {
ir_print_encoded_local(f, str_lit("..complex128"));
ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
+ ir_print_encoded_local(f, str_lit("..quaternion64"));
+ ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
+ ir_print_encoded_local(f, str_lit("..quaternion128"));
+ ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
+ ir_print_encoded_local(f, str_lit("..quaternion256"));
+ ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
+
ir_print_encoded_local(f, str_lit("..typeid"));
ir_write_str_lit(f, " = type ");
ir_print_type(f, m, t_uintptr);
@@ -2339,7 +2513,7 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, g->entity->type);
ir_write_byte(f, ' ');
if (!g->is_foreign) {
- if (g->value != nullptr) {
+ if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) {
ir_print_value(f, m, g->value, g->entity->type);
} else {
ir_write_string(f, str_lit("zeroinitializer"));
@@ -2383,11 +2557,13 @@ void print_llvm_ir(irGen *ir) {
for_array(di_index, m->debug_info.entries) {
irDebugInfo *di = m->debug_info.entries[di_index].value;
+ GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
ir_fprintf(f, "!%d = ", di->id);
-
switch (di->kind) {
case irDebugInfo_CompileUnit: {
- irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
+ irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
+ GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath));
+ irDebugInfo *file = *found;
ir_fprintf(f,
"distinct !DICompileUnit("
"language: DW_LANG_C_plus_plus" // Is this good enough?
diff --git a/src/main.cpp b/src/main.cpp
index 05fa6c366..acb580ca2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -75,7 +75,7 @@ i32 system_exec_command_line_app(char *name, char *fmt, ...) {
va_end(va);
cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
- //printf("do: %s\n", cmd_line);
+ // printf("do: %s\n", cmd_line);
exit_code = system(&cmd_line[0]);
// pid_t pid = fork();
@@ -160,8 +160,9 @@ void usage(String argv0) {
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
- print_usage_line(1, "build compile .odin file as executable");
- print_usage_line(1, "run compile and run .odin file");
+ print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
+ print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
+ print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse and type check .odin file");
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "docs generate documentation for a .odin file");
@@ -210,9 +211,8 @@ enum BuildFlagKind {
BuildFlag_Collection,
BuildFlag_Define,
BuildFlag_BuildMode,
+ BuildFlag_Target,
BuildFlag_Debug,
- BuildFlag_CrossCompile,
- BuildFlag_CrossLibDir,
BuildFlag_NoBoundsCheck,
BuildFlag_NoCRT,
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_Define, str_lit("define"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
+ add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
- add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
- add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
@@ -447,7 +446,7 @@ bool parse_build_flags(Array<String> args) {
path = substring(path, 0, string_extension_position(path));
}
#endif
- build_context.out_filepath = path;
+ build_context.out_filepath = path_to_full_path(heap_allocator(), path);
} else {
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
bad_flags = true;
@@ -478,33 +477,6 @@ bool parse_build_flags(Array<String> args) {
build_context.keep_temp_files = true;
break;
- case BuildFlag_CrossCompile: {
- GB_ASSERT(value.kind == ExactValue_String);
- cross_compile_target = value.value_string;
- #if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
- if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
-
- } else
- #endif
- {
- gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
- gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
- bad_flags = true;
- }
- break;
- }
-
- case BuildFlag_CrossLibDir: {
- GB_ASSERT(value.kind == ExactValue_String);
- if (cross_compile_lib_dir.len) {
- gb_printf_err("Multiple cross compilation library directories\n");
- bad_flags = true;
- } else {
- cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
- }
- break;
- }
-
case BuildFlag_Collection: {
GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string;
@@ -623,7 +595,25 @@ bool parse_build_flags(Array<String> args) {
break;
}
+ case BuildFlag_Target: {
+ String str = value.value_string;
+ bool found = false;
+
+ for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) {
+ if (str_eq_ignore_case(str, named_targets[i].name)) {
+ found = true;
+ selected_target_metrics = named_targets + i;
+ break;
+ }
+ }
+
+ if (!found) {
+ gb_printf_err("Unknown target '%.*s'\n", LIT(str));
+ bad_flags = true;
+ }
+ break;
+ }
case BuildFlag_BuildMode: {
GB_ASSERT(value.kind == ExactValue_String);
@@ -635,7 +625,7 @@ bool parse_build_flags(Array<String> args) {
break;
}
- if (str == "dll") {
+ if (str == "dll" || str == "shared") {
build_context.is_dll = true;
} else if (str == "exe") {
build_context.is_dll = false;
@@ -889,8 +879,8 @@ i32 exec_llvm_opt(String output_base) {
}
i32 exec_llvm_llc(String output_base) {
-#if defined(GB_SYSTEM_WINDOWS)
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
+#if defined(GB_SYSTEM_WINDOWS)
return system_exec_command_line_app("llvm-llc",
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
"-o \"%.*s.obj\" "
@@ -903,21 +893,19 @@ i32 exec_llvm_llc(String output_base) {
LIT(build_context.llc_flags));
#else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
- // For more arguments: http://llvm.org/docs/CommandGuide/llc.html
return system_exec_command_line_app("llc",
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
"%.*s "
- "%s"
- "",
+ "%s%.*s",
LIT(output_base),
build_context.optimization_level,
LIT(build_context.llc_flags),
- str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
+ build_context.cross_compiling ? "-mtriple=" : "",
+ (int) (build_context.cross_compiling ? build_context.target_triplet.len : 0),
+ build_context.target_triplet.text);
#endif
}
-
-
int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) {
usage(make_string_c(arg_ptr[0]));
@@ -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) {
print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
return 1;
@@ -1121,6 +1109,17 @@ int main(int arg_count, char **arg_ptr) {
return exit_code;
}
+ if (build_context.cross_compiling) {
+ if (0) {
+#ifdef GB_SYSTEM_UNIX
+ } else if (selected_target_metrics->metrics == &target_essence_amd64) {
+ system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
+ LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
+#endif
+ } else {
+ gb_printf_err("Don't know how to cross compile to selected target.\n");
+ }
+ } else {
#if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("msvc-link"));
@@ -1219,7 +1218,7 @@ int main(int arg_count, char **arg_ptr) {
remove_temp_files(output_base);
if (run_output) {
- system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
+ return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
}
#else
timings_start_section(&timings, str_lit("ld-link"));
@@ -1241,15 +1240,17 @@ int main(int arg_count, char **arg_ptr) {
// This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX)
- if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
+ if (string_ends_with(lib, str_lit(".framework"))) {
// framework thingie
- lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
+ String lib_name = lib;
+ lib_name = remove_extension_from_path(lib_name);
+ lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
} else if (string_ends_with(lib, str_lit(".a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
} else if (string_ends_with(lib, str_lit(".dylib"))) {
- // dynamic lib, relative path to executable
- lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
+ // dynamic lib
+ lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
} else {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -1309,11 +1310,7 @@ int main(int arg_count, char **arg_ptr) {
// It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_.
- if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
- linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
- } else {
- linker = "clang -Wno-unused-command-line-argument";
- }
+ linker = "clang -Wno-unused-command-line-argument";
#endif
exit_code = system_exec_command_line_app("ld-link",
@@ -1321,7 +1318,6 @@ int main(int arg_count, char **arg_ptr) {
" %s "
" %.*s "
" %s "
- " %.*s "
#if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
@@ -1332,11 +1328,9 @@ int main(int arg_count, char **arg_ptr) {
#endif
, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
lib_str,
- str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm",
+ "-lc -lm",
LIT(build_context.link_flags),
- link_settings,
- LIT(cross_compile_lib_dir)
- );
+ link_settings);
if (exit_code != 0) {
return exit_code;
}
@@ -1366,9 +1360,10 @@ int main(int arg_count, char **arg_ptr) {
//NOTE(thebirk): This whole thing is a little leaky
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
complete_path = path_to_full_path(heap_allocator(), complete_path);
- system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
+ return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
}
#endif
+ }
return 0;
}
diff --git a/src/parser.cpp b/src/parser.cpp
index a377b773c..10aa10119 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -51,6 +51,7 @@ Token ast_token(Ast *node) {
case Ast_ReturnStmt: return node->ReturnStmt.token;
case Ast_ForStmt: return node->ForStmt.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_SwitchStmt: return node->SwitchStmt.token;
case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
@@ -143,6 +144,7 @@ Ast *clone_ast(Ast *node) {
case Ast_ProcLit:
n->ProcLit.type = clone_ast(n->ProcLit.type);
n->ProcLit.body = clone_ast(n->ProcLit.body);
+ n->ProcLit.where_clauses = clone_ast_array(n->ProcLit.where_clauses);
break;
case Ast_CompoundLit:
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.body = clone_ast(n->RangeStmt.body);
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:
n->CaseClause.list = clone_ast_array(n->CaseClause.list);
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.polymorphic_params = clone_ast(n->StructType.polymorphic_params);
n->StructType.align = clone_ast(n->StructType.align);
+ n->StructType.where_clauses = clone_ast_array(n->StructType.where_clauses);
break;
case Ast_UnionType:
n->UnionType.variants = clone_ast_array(n->UnionType.variants);
n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params);
+ n->UnionType.where_clauses = clone_ast_array(n->UnionType.where_clauses);
break;
case Ast_EnumType:
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) {
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 true;
@@ -578,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) {
Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
Ast *result = alloc_ast_node(f, Ast_BasicLit);
result->BasicLit.token = basic_lit;
+ result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
return result;
}
@@ -605,11 +616,13 @@ Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<Ast
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);
result->ProcLit.type = type;
result->ProcLit.body = body;
result->ProcLit.tags = tags;
+ result->ProcLit.where_token = where_token;
+ result->ProcLit.where_clauses = where_clauses;
return result;
}
@@ -748,6 +761,18 @@ Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_toke
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 *result = alloc_ast_node(f, Ast_SwitchStmt);
result->SwitchStmt.token = token;
@@ -805,13 +830,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
return result;
}
-Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags,
- CommentGroup *docs, CommentGroup *comment) {
+Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Token tag,
+ CommentGroup *docs, CommentGroup *comment) {
Ast *result = alloc_ast_node(f, Ast_Field);
result->Field.names = names;
result->Field.type = type;
result->Field.default_value = default_value;
result->Field.flags = flags;
+ result->Field.tag = tag;
result->Field.docs = docs;
result->Field.comment = comment;
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 *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);
result->StructType.token = token;
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_raw_union = is_raw_union;
result->StructType.align = align;
+ result->StructType.where_token = where_token;
+ result->StructType.where_clauses = where_clauses;
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);
result->UnionType.token = token;
result->UnionType.variants = variants;
result->UnionType.polymorphic_params = polymorphic_params;
result->UnionType.align = align;
result->UnionType.no_nil = no_nil;
+ result->UnionType.where_token = where_token;
+ result->UnionType.where_clauses = where_clauses;
return result;
}
@@ -1118,6 +1150,17 @@ Token advance_token(AstFile *f) {
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 prev = f->curr_token;
if (prev.kind != kind) {
@@ -1302,7 +1345,8 @@ bool is_semicolon_optional_for_node(AstFile *f, Ast *s) {
case Ast_UnionType:
case Ast_EnumType:
case Ast_BitFieldType:
- return true;
+ // Require semicolon within a procedure body
+ return f->curr_proc == nullptr;
case Ast_ProcLit:
return true;
@@ -1336,10 +1380,6 @@ void expect_semicolon(AstFile *f, Ast *s) {
return;
}
- switch (f->curr_token.kind) {
- case Token_EOF:
- return;
- }
if (s != nullptr) {
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_else:
return;
+ case Token_EOF:
+ if (is_semicolon_optional_for_node(f, s)) {
+ return;
+ }
+ break;
}
}
String node_string = ast_strings[s->kind];
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 {
+ switch (f->curr_token.kind) {
+ case Token_EOF:
+ return;
+ }
syntax_error(prev_token, "Expected ';'");
}
fix_advance_to_next_stmt(f);
@@ -1461,8 +1510,11 @@ Ast *parse_value(AstFile *f) {
if (f->curr_token.kind == Token_OpenBrace) {
return parse_literal_value(f, nullptr);
}
-
- Ast *value = parse_expr(f, false);
+ Ast *value;
+ bool prev_allow_range = f->allow_range;
+ f->allow_range = true;
+ value = parse_expr(f, false);
+ f->allow_range = prev_allow_range;
return value;
}
@@ -1614,7 +1666,7 @@ void check_polymorphic_params_for_type(AstFile *f, Ast *polymorphic_params, Toke
for_array(i, field->Field.names) {
Ast *name = field->Field.names[i];
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?
}
}
@@ -1687,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) {
operand = ast_bad_expr(f, token, f->curr_token);
}
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 == "procedure") { 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);
+ 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 (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;
}
- u64 tags = type->ProcType.tags;
-
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) {
Ast *curr_proc = f->curr_proc;
Ast *body = nullptr;
@@ -1812,7 +1891,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
body = parse_body(f);
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)) {
Ast *curr_proc = f->curr_proc;
Ast *body = nullptr;
@@ -1820,11 +1899,14 @@ Ast *parse_operand(AstFile *f, bool lhs) {
body = convert_stmt_to_body(f, parse_stmt(f));
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) {
- 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;
@@ -1847,10 +1929,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
case 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);
} break;
@@ -1952,6 +2030,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
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");
isize name_count = 0;
@@ -1964,7 +2054,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
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;
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");
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);
- 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;
case Token_enum: {
@@ -2091,7 +2193,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
bool prev_allow_range = f->allow_range;
f->allow_range = true;
- elem = parse_expr(f, false);
+ elem = parse_expr(f, true);
f->allow_range = prev_allow_range;
if (allow_token(f, Token_Semicolon)) {
underlying = parse_type(f);
@@ -2383,17 +2485,18 @@ i32 token_precedence(AstFile *f, TokenKind t) {
case Token_LtEq:
case Token_GtEq:
return 5;
+
case Token_in:
case Token_notin:
- if (f->expr_level >= 0 || f->allow_in_expr) {
- return 6;
+ if (f->expr_level < 0 && !f->allow_in_expr) {
+ return 0;
}
- return 0;
+ /*fallthrough*/
case Token_Add:
case Token_Sub:
case Token_Or:
case Token_Xor:
- return 7;
+ return 6;
case Token_Mul:
case Token_Quo:
case Token_Mod:
@@ -2402,7 +2505,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
case Token_AndNot:
case Token_Shl:
case Token_Shr:
- return 8;
+ return 7;
}
return 0;
}
@@ -2649,7 +2752,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) {
allow_token(f, Token_in);
bool prev_allow_range = f->allow_range;
f->allow_range = true;
- Ast *expr = parse_expr(f, false);
+ Ast *expr = parse_expr(f, true);
f->allow_range = prev_allow_range;
auto rhs = array_make<Ast *>(heap_allocator(), 0, 1);
@@ -2740,7 +2843,8 @@ Ast *parse_results(AstFile *f, bool *diverging) {
Array<Ast *> empty_names = {};
auto list = array_make<Ast *>(heap_allocator(), 0, 1);
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);
}
@@ -2795,8 +2899,6 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) {
results = parse_results(f, &diverging);
u64 tags = 0;
- parse_proc_tags(f, &tags);
-
bool is_generic = false;
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 *default_value = nullptr;
+ Token tag = {};
expect_token_after(f, Token_Colon, "field list");
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");
}
+ 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);
- 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(&params, param);
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF) {
CommentGroup *docs = f->lead_comment;
-
u32 set_flags = parse_field_prefixes(f);
+ Token tag = {};
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
if (names.count == 0) {
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");
}
+ 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);
- 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(&params, param);
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;
names[0] = ast_ident(f, token);
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
-
- Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
+ Token tag = {};
+ Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment);
array_add(&params, param);
}
@@ -3758,9 +3879,55 @@ Ast *parse_stmt(AstFile *f) {
Token token = f->curr_token;
switch (token.kind) {
// Operands
- case Token_context: // Also allows for `context =`
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_context: // Also allows for `context =`
+ case Token_proc:
case Token_Ident:
case Token_Integer:
case Token_Float:
@@ -3808,34 +3975,6 @@ Ast *parse_stmt(AstFile *f) {
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: {
CommentGroup *docs = f->lead_comment;
Token token = expect_token(f, Token_using);
@@ -3909,12 +4048,10 @@ Ast *parse_stmt(AstFile *f) {
} else if (tag == "assert") {
Ast *t = ast_basic_directive(f, hash_token, tag);
return ast_expr_stmt(f, parse_call_expr(f, t));
- } /* else if (name.string == "no_deferred") {
- s = parse_stmt(f);
- s->stmt_state_flags |= StmtStateFlag_no_deferred;
- } */
-
- if (tag == "include") {
+ } else if (tag == "panic") {
+ Ast *t = ast_basic_directive(f, hash_token, tag);
+ return ast_expr_stmt(f, parse_call_expr(f, t));
+ } else if (tag == "include") {
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
s = ast_bad_stmt(f, token, f->curr_token);
} else {
@@ -4037,7 +4174,6 @@ bool init_parser(Parser *p) {
map_init(&p->package_map, heap_allocator());
array_init(&p->packages, 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_decl_mutex);
return true;
@@ -4060,7 +4196,6 @@ void destroy_parser(Parser *p) {
#endif
array_free(&p->packages);
array_free(&p->package_imports);
- array_free(&p->files_to_process);
string_set_destroy(&p->imported_files);
map_destroy(&p->package_map);
gb_mutex_destroy(&p->file_add_mutex);
@@ -4077,19 +4212,32 @@ void parser_add_package(Parser *p, AstPackage *pkg) {
if (found) {
GB_ASSERT(pkg->files.count > 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);
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 {
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) {
- ImportedFile f = {pkg, fi, pos, p->files_to_process.count};
- array_add(&p->files_to_process, f);
+ // TODO(bill): Use a better allocator
+ 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) {
case ReadDirectory_InvalidPath:
- error(pos, "Invalid path: %.*s", LIT(rel_path));
+ syntax_error(pos, "Invalid path: %.*s", LIT(rel_path));
return false;
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;
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;
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;
case ReadDirectory_Empty:
- error(pos, "Empty directory: %.*s", LIT(rel_path));
+ syntax_error(pos, "Empty directory: %.*s", LIT(rel_path));
return false;
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;
}
@@ -4257,7 +4405,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
String file_str = {};
if (colon_pos == 0) {
- error(node, "Expected a collection name");
+ syntax_error(node, "Expected a collection name");
return false;
}
@@ -4272,32 +4420,19 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
if (has_windows_drive) {
String sub_file_path = substring(file_str, 3, file_str.len);
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;
}
} 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;
}
- 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 == "system") {
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;
} else {
*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)) {
// 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;
}
} else {
@@ -4324,6 +4459,20 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
#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) {
*path = file_str;
} else {
@@ -4412,7 +4561,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *>
array_add(&fl->fullpaths, fullpath);
}
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]);
goto end;
}
@@ -4461,7 +4610,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
is_notted = true;
p = substring(p, 1, p.len);
if (p.len == 0) {
- error(token_for_pos, "Expected a build platform after '!'");
+ syntax_error(token_for_pos, "Expected a build platform after '!'");
break;
}
}
@@ -4490,7 +4639,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
}
}
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;
}
}
@@ -4536,11 +4685,11 @@ bool parse_file(Parser *p, AstFile *f) {
Token package_name = expect_token_after(f, Token_Ident, "package");
if (package_name.kind == Token_Ident) {
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") {
- 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)) {
- 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;
@@ -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;
- FileInfo *fi = &imported_file.fi;
+ FileInfo const *fi = &imported_file.fi;
TokenPos pos = imported_file.pos;
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_EmptyFile) {
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);
}
- goto skip;
- }
+ } else {
+ switch (err) {
+ case ParseFile_WrongExtension:
+ syntax_error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name));
+ break;
+ case ParseFile_InvalidFile:
+ syntax_error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name));
+ break;
+ case ParseFile_Permission:
+ syntax_error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
+ break;
+ case ParseFile_NotFound:
+ syntax_error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath));
+ break;
+ case ParseFile_InvalidToken:
+ syntax_error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name));
+ break;
+ case ParseFile_EmptyFile:
+ syntax_error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name));
+ break;
+ }
- switch (err) {
- case ParseFile_WrongExtension:
- error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name));
- break;
- case ParseFile_InvalidFile:
- error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name));
- break;
- case ParseFile_Permission:
- error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
- break;
- case ParseFile_NotFound:
- error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath));
- break;
- case ParseFile_InvalidToken:
- error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name));
- break;
- case ParseFile_EmptyFile:
- error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name));
- break;
+ return err;
}
-
- return err;
}
-
-skip:
if (parse_file(p, file)) {
gb_mutex_lock(&p->file_add_mutex);
defer (gb_mutex_unlock(&p->file_add_mutex));
@@ -4648,42 +4794,33 @@ skip:
if (pkg->name.len == 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_token_count += file->tokens.count;
}
+
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) {
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]);
- // String init_fullpath = string_trim_whitespace(make_string_c(fullpath_str));
+ isize thread_count = gb_max(build_context.thread_count, 1);
+ 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);
if (!path_is_directory(init_fullpath)) {
String const ext = str_lit(".odin");
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;
}
}
-
TokenPos init_pos = {};
if (!build_context.generate_docs) {
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);
p->init_fullpath = init_fullpath;
-#if 1
- isize thread_count = gb_max(build_context.thread_count, 1);
- 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);
- defer (array_free(&worker_threads));
-
- for_array(i, worker_threads) {
- gbThread *t = &worker_threads[i];
- gb_thread_init(t);
- }
- defer (for_array(i, worker_threads) {
- gb_thread_destroy(&worker_threads[i]);
- });
+ thread_pool_start(&parser_thread_pool);
+ thread_pool_wait_to_process(&parser_thread_pool);
- 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) {
- return err;
- }
- }
- }
-#else
- for_array(i, p->files_to_process) {
- ImportedFile f = p->files_to_process[i];
- ParseFileError err = process_imported_file(p, f);
+ // NOTE(bill): Get the last error and use that
+ for (isize i = parser_thread_pool.task_tail-1; i >= 0; i--) {
+ WorkerTask *task = &parser_thread_pool.tasks[i];
+ ParseFileError err = cast(ParseFileError)task->result;
if (err != ParseFile_None) {
return err;
}
}
-#endif
return ParseFile_None;
}
diff --git a/src/parser.hpp b/src/parser.hpp
index 9f4f68a7b..f07f3ce0d 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -134,13 +134,26 @@ struct Parser {
Map<AstPackage *> package_map; // Key: String (package name)
Array<AstPackage *> packages;
Array<ImportedPackage> package_imports;
- Array<ImportedFile> files_to_process;
+ isize file_to_process_count;
isize total_token_count;
isize total_line_count;
gbMutex file_add_mutex;
gbMutex file_decl_mutex;
};
+
+gb_global ThreadPool parser_thread_pool = {};
+
+struct ParserWorkerData {
+ Parser *parser;
+ ImportedFile imported_file;
+};
+
+
+
+
+
+
enum ProcInlining {
ProcInlining_none = 0,
ProcInlining_inline = 1,
@@ -186,11 +199,12 @@ enum FieldFlag {
FieldFlag_c_vararg = 1<<3,
FieldFlag_auto_cast = 1<<4,
+ FieldFlag_Tags = 1<<10,
FieldFlag_Results = 1<<16,
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
- FieldFlag_Struct = FieldFlag_using,
+ FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
};
enum StmtAllowFlag {
@@ -208,6 +222,7 @@ enum StmtAllowFlag {
AST_KIND(Undef, "undef", Token) \
AST_KIND(BasicLit, "basic literal", struct { \
Token token; \
+ ExactValue value; \
}) \
AST_KIND(BasicDirective, "basic directive", struct { \
Token token; \
@@ -228,11 +243,14 @@ enum StmtAllowFlag {
Ast *body; \
u64 tags; \
ProcInlining inlining; \
+ Token where_token; \
+ Array<Ast *> where_clauses; \
}) \
AST_KIND(CompoundLit, "compound literal", struct { \
Ast *type; \
Array<Ast *> elems; \
Token open, close; \
+ i64 max_count; \
}) \
AST_KIND(_ExprBegin, "", bool) \
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
@@ -325,6 +343,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
Ast *expr; \
Ast *body; \
}) \
+ AST_KIND(InlineRangeStmt, "inline range statement", struct { \
+ Token inline_token; \
+ Token for_token; \
+ Ast *val0; \
+ Ast *val1; \
+ Token in_token; \
+ Ast *expr; \
+ Ast *body; \
+ }) \
AST_KIND(CaseClause, "case clause", struct { \
Token token; \
Array<Ast *> list; \
@@ -412,6 +439,7 @@ AST_KIND(_DeclEnd, "", bool) \
Array<Ast *> names; \
Ast * type; \
Ast * default_value; \
+ Token tag; \
u32 flags; \
CommentGroup * docs; \
CommentGroup * comment; \
@@ -465,20 +493,24 @@ AST_KIND(_TypeBegin, "", bool) \
Ast *elem; \
}) \
AST_KIND(StructType, "struct type", struct { \
- Token token; \
- Array<Ast *> fields; \
- isize field_count; \
- Ast *polymorphic_params; \
- Ast *align; \
- bool is_packed; \
- bool is_raw_union; \
+ Token token; \
+ Array<Ast *> fields; \
+ isize field_count; \
+ Ast *polymorphic_params; \
+ Ast *align; \
+ Token where_token; \
+ Array<Ast *> where_clauses; \
+ bool is_packed; \
+ bool is_raw_union; \
}) \
AST_KIND(UnionType, "union type", struct { \
- Token token; \
- Array<Ast *> variants; \
- Ast *polymorphic_params; \
- Ast * align; \
- bool no_nil; \
+ Token token; \
+ Array<Ast *> variants; \
+ Ast *polymorphic_params; \
+ Ast * align; \
+ bool no_nil; \
+ Token where_token; \
+ Array<Ast *> where_clauses; \
}) \
AST_KIND(EnumType, "enum type", struct { \
Token token; \
diff --git a/src/priority_queue.cpp b/src/priority_queue.cpp
index 7c36e6a22..aee2061b5 100644
--- a/src/priority_queue.cpp
+++ b/src/priority_queue.cpp
@@ -20,7 +20,7 @@ bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
j = j2;
}
- if (pq->cmp(&pq->queue[0], i, j) < 0) break;
+ if (pq->cmp(&pq->queue[0], j, i) >= 0) break;
pq->swap(&pq->queue[0], i, j);
i = j;
@@ -32,7 +32,7 @@ template <typename T>
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
while (0 <= j && j < pq->queue.count) {
isize i = (j-1)/2;
- if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) {
+ if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
break;
}
pq->swap(&pq->queue[0], i, j);
diff --git a/src/range_cache.cpp b/src/range_cache.cpp
new file mode 100644
index 000000000..9701fb432
--- /dev/null
+++ b/src/range_cache.cpp
@@ -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;
+}
diff --git a/src/string.cpp b/src/string.cpp
index 774061edf..6812c5c39 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -404,7 +404,7 @@ String16 string_to_string16(gbAllocator a, String s) {
}
text[len] = 0;
- return make_string16(text, len-1);
+ return make_string16(text, len);
}
@@ -440,12 +440,94 @@ String string16_to_string(gbAllocator a, String16 s) {
+bool is_printable(Rune r) {
+ if (r <= 0xff) {
+ if (0x20 <= r && r <= 0x7e) {
+ return true;
+ }
+ if (0xa1 <= r && r <= 0xff) {
+ return r != 0xad;
+ }
+ return false;
+ }
+ return false;
+}
+gb_global char const lower_hex[] = "0123456789abcdef";
+
+String quote_to_ascii(gbAllocator a, String str, u8 quote='"') {
+ u8 *s = str.text;
+ isize n = str.len;
+ auto buf = array_make<u8>(a, 0, n);
+ array_add(&buf, quote);
+ for (isize width = 0; n > 0; s += width, n -= width) {
+ Rune r = cast(Rune)s[0];
+ width = 1;
+ if (r >= 0x80) {
+ width = gb_utf8_decode(s, n, &r);
+ }
+ if (width == 1 && r == GB_RUNE_INVALID) {
+ array_add(&buf, cast(u8)'\\');
+ array_add(&buf, cast(u8)'x');
+ array_add(&buf, cast(u8)lower_hex[s[0]>>4]);
+ array_add(&buf, cast(u8)lower_hex[s[0]&0xf]);
+ continue;
+ }
+ if (r == quote || r == '\\') {
+ array_add(&buf, cast(u8)'\\');
+ array_add(&buf, u8(r));
+ continue;
+ }
+ if (r < 0x80 && is_printable(r)) {
+ array_add(&buf, u8(r));
+ continue;
+ }
+ switch (r) {
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ default:
+ if (r < ' ') {
+ u8 b = cast(u8)r;
+ array_add(&buf, cast(u8)'\\');
+ array_add(&buf, cast(u8)'x');
+ array_add(&buf, cast(u8)lower_hex[b>>4]);
+ array_add(&buf, cast(u8)lower_hex[b&0xf]);
+ }
+ if (r > GB_RUNE_MAX) {
+ r = 0XFFFD;
+ }
+ if (r < 0x10000) {
+ u8 b = cast(u8)r;
+ array_add(&buf, cast(u8)'\\');
+ array_add(&buf, cast(u8)'u');
+ for (isize i = 12; i >= 0; i -= 4) {
+ array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
+ }
+ } else {
+ u8 b = cast(u8)r;
+ array_add(&buf, cast(u8)'\\');
+ array_add(&buf, cast(u8)'U');
+ for (isize i = 28; i >= 0; i -= 4) {
+ array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
+ }
+ }
+ }
+ }
-
+ array_add(&buf, quote);
+ String res = {};
+ res.text = buf.data;
+ res.len = buf.count;
+ return res;
+}
diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp
new file mode 100644
index 000000000..2467ba609
--- /dev/null
+++ b/src/thread_pool.cpp
@@ -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;
+}
+
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index a551f0545..4b0db7ac4 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_package, "package"), \
TOKEN_KIND(Token_typeid, "typeid"), \
TOKEN_KIND(Token_when, "when"), \
+ TOKEN_KIND(Token_where, "where"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
@@ -400,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) {
va_end(va);
}
+void syntax_error(TokenPos pos, char *fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ Token token = {};
+ token.pos = pos;
+ syntax_error_va(token, fmt, va);
+ va_end(va);
+}
+
void syntax_warning(Token token, char *fmt, ...) {
va_list va;
va_start(va, fmt);
@@ -745,9 +755,11 @@ exponent:
scan_mantissa(t, 10);
}
- if (t->curr_rune == 'i') {
+ switch (t->curr_rune) {
+ case 'i': case 'j': case 'k':
token.kind = Token_Imag;
advance_to_next_rune(t);
+ break;
}
end:
diff --git a/src/types.cpp b/src/types.cpp
index dc7ecb946..bef69ee30 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -32,6 +32,9 @@ enum BasicKind {
Basic_complex64,
Basic_complex128,
+ Basic_quaternion128,
+ Basic_quaternion256,
+
Basic_int,
Basic_uint,
Basic_uintptr,
@@ -66,6 +69,7 @@ enum BasicKind {
Basic_UntypedInteger,
Basic_UntypedFloat,
Basic_UntypedComplex,
+ Basic_UntypedQuaternion,
Basic_UntypedString,
Basic_UntypedRune,
Basic_UntypedNil,
@@ -82,17 +86,18 @@ enum BasicFlag {
BasicFlag_Unsigned = GB_BIT(2),
BasicFlag_Float = GB_BIT(3),
BasicFlag_Complex = GB_BIT(4),
- BasicFlag_Pointer = GB_BIT(5),
- BasicFlag_String = GB_BIT(6),
- BasicFlag_Rune = GB_BIT(7),
- BasicFlag_Untyped = GB_BIT(8),
+ BasicFlag_Quaternion = GB_BIT(5),
+ BasicFlag_Pointer = GB_BIT(6),
+ BasicFlag_String = GB_BIT(7),
+ BasicFlag_Rune = GB_BIT(8),
+ BasicFlag_Untyped = GB_BIT(9),
- BasicFlag_LLVM = GB_BIT(10),
+ BasicFlag_LLVM = GB_BIT(11),
BasicFlag_EndianLittle = GB_BIT(13),
BasicFlag_EndianBig = GB_BIT(14),
- BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex,
+ BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion,
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
@@ -107,21 +112,23 @@ struct BasicType {
struct TypeStruct {
Array<Entity *> fields;
- Ast *node;
- Scope * scope;
-
- Array<i64> offsets;
- bool are_offsets_set;
- bool are_offsets_being_processed;
- bool is_packed;
- bool is_raw_union;
- bool is_polymorphic;
- bool is_poly_specialized;
+ Array<String> tags;
+ Array<i64> offsets;
+ Ast * node;
+ Scope * scope;
+
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
- i64 custom_align; // NOTE(bill): Only used in structs at the moment
+ i64 custom_align;
Entity * names;
+
+ bool are_offsets_set;
+ bool are_offsets_being_processed;
+ bool is_packed;
+ bool is_raw_union;
+ bool is_polymorphic;
+ bool is_poly_specialized;
};
struct TypeUnion {
@@ -131,12 +138,11 @@ struct TypeUnion {
i64 variant_block_size;
i64 custom_align;
i64 tag_size;
+ Type * polymorphic_params; // Type_Tuple
+ Type * polymorphic_parent;
bool no_nil;
-
- bool is_polymorphic;
- bool is_poly_specialized;
- Type * polymorphic_params; // Type_Tuple
- Type * polymorphic_parent;
+ bool is_polymorphic;
+ bool is_poly_specialized;
};
#define TYPE_KINDS \
@@ -184,7 +190,9 @@ struct TypeUnion {
TYPE_KIND(Tuple, struct { \
Array<Entity *> variables; /* Entity_Variable */ \
Array<i64> offsets; \
+ bool are_offsets_being_processed; \
bool are_offsets_set; \
+ bool is_packed; \
}) \
TYPE_KIND(Proc, struct { \
Ast *node; \
@@ -195,9 +203,9 @@ struct TypeUnion {
i32 result_count; \
Array<Type *> abi_compat_params; \
Type * abi_compat_result_type; \
- bool return_by_pointer; \
- bool variadic; \
i32 variadic_index; \
+ bool variadic; \
+ bool abi_types_set; \
bool require_results; \
bool c_vararg; \
bool is_polymorphic; \
@@ -205,6 +213,7 @@ struct TypeUnion {
bool has_proc_default_values; \
bool has_named_results; \
bool diverging; /* no return */ \
+ bool return_by_pointer; \
u64 tags; \
isize specialization_count; \
ProcCallingConvention calling_convention; \
@@ -341,6 +350,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
+ {Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}},
+ {Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}},
+
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
@@ -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_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
{Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}},
+ {Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}},
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
@@ -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_complex128 = &basic_types[Basic_complex128];
+gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128];
+gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256];
+
gb_global Type *t_int = &basic_types[Basic_int];
gb_global Type *t_uint = &basic_types[Basic_uint];
gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
@@ -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_float = &basic_types[Basic_UntypedFloat];
gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex];
+gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
@@ -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_float = nullptr;
gb_global Type *t_type_info_complex = nullptr;
+gb_global Type *t_type_info_quaternion = nullptr;
gb_global Type *t_type_info_any = nullptr;
gb_global Type *t_type_info_typeid = nullptr;
gb_global Type *t_type_info_string = nullptr;
@@ -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_float_ptr = nullptr;
gb_global Type *t_type_info_complex_ptr = nullptr;
+gb_global Type *t_type_info_quaternion_ptr = nullptr;
gb_global Type *t_type_info_any_ptr = nullptr;
gb_global Type *t_type_info_typeid_ptr = nullptr;
gb_global Type *t_type_info_string_ptr = nullptr;
@@ -535,8 +554,27 @@ i64 type_offset_of (Type *t, i32 index);
gbString type_to_string (Type *type);
void init_map_internal_types(Type *type);
Type * bit_set_to_int(Type *t);
+bool are_types_identical(Type *x, Type *y);
+bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
+ if (ptr_set_exists(s, t)) {
+ return true;
+ }
+
+ // TODO(bill, 2019-10-05): This is very slow and it's probably a lot
+ // faster to cache types correctly
+ for_array(i, s->entries) {
+ Type *f = s->entries[i].ptr;
+ if (are_types_identical(t, f)) {
+ ptr_set_add(s, t);
+ return true;
+ }
+ }
+
+ return false;
+}
+
Type *base_type(Type *t) {
for (;;) {
if (t == nullptr) {
@@ -923,6 +961,13 @@ bool is_type_complex(Type *t) {
}
return false;
}
+bool is_type_quaternion(Type *t) {
+ t = core_type(t);
+ if (t->kind == Type_Basic) {
+ return (t->Basic.flags & BasicFlag_Quaternion) != 0;
+ }
+ return false;
+}
bool is_type_f32(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
@@ -1037,14 +1082,40 @@ Type *core_array_type(Type *t) {
return t;
}
+// NOTE(bill): type can be easily compared using memcmp
+bool is_type_simple_compare(Type *t) {
+ t = core_type(t);
+ switch (t->kind) {
+ case Type_Array:
+ return is_type_simple_compare(t->Array.elem);
+
+ case Type_Basic:
+ if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) {
+ return true;
+ }
+ return false;
+
+ case Type_Pointer:
+ case Type_Proc:
+ case Type_BitSet:
+ case Type_BitField:
+ return true;
+ }
+
+ return false;
+}
+
Type *base_complex_elem_type(Type *t) {
t = core_type(t);
- if (is_type_complex(t)) {
+ if (t->kind == Type_Basic) {
switch (t->Basic.kind) {
- // case Basic_complex32: return t_f16;
- case Basic_complex64: return t_f32;
- case Basic_complex128: return t_f64;
- case Basic_UntypedComplex: return t_untyped_float;
+ // case Basic_complex32: return t_f16;
+ case Basic_complex64: return t_f32;
+ case Basic_complex128: return t_f64;
+ case Basic_quaternion128: return t_f32;
+ case Basic_quaternion256: return t_f64;
+ case Basic_UntypedComplex: return t_untyped_float;
+ case Basic_UntypedQuaternion: return t_untyped_float;
}
}
GB_PANIC("Invalid complex type");
@@ -1099,12 +1170,11 @@ bool is_type_integer_endian_big(Type *t) {
return is_type_integer_endian_big(bit_set_to_int(t));
} else if (t->kind == Type_Pointer) {
return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
- } else {
- GB_PANIC("Unsupported type: %s", type_to_string(t));
}
return build_context.endian_kind == TargetEndian_Big;
}
+
bool is_type_integer_endian_little(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
@@ -1118,11 +1188,24 @@ bool is_type_integer_endian_little(Type *t) {
return is_type_integer_endian_little(bit_set_to_int(t));
} else if (t->kind == Type_Pointer) {
return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
- } else {
- GB_PANIC("Unsupported type: %s", type_to_string(t));
}
return build_context.endian_kind == TargetEndian_Little;
}
+bool is_type_endian_big(Type *t) {
+ return is_type_integer_endian_big(t);
+}
+bool is_type_endian_little(Type *t) {
+ return is_type_integer_endian_little(t);
+}
+
+bool is_type_dereferenceable(Type *t) {
+ if (is_type_rawptr(t)) {
+ return false;
+ }
+ return is_type_pointer(t);
+}
+
+
bool is_type_different_to_arch_endianness(Type *t) {
switch (build_context.endian_kind) {
@@ -1284,6 +1367,19 @@ bool is_type_indexable(Type *t) {
return false;
}
+bool is_type_sliceable(Type *t) {
+ Type *bt = base_type(t);
+ switch (bt->kind) {
+ case Type_Basic:
+ return bt->Basic.kind == Basic_string;
+ case Type_Array:
+ case Type_Slice:
+ case Type_DynamicArray:
+ return true;
+ }
+ return false;
+}
+
bool is_type_polymorphic_record(Type *t) {
t = base_type(t);
@@ -1663,6 +1759,12 @@ bool are_types_identical(Type *x, Type *y) {
if (xf_is_using ^ yf_is_using) {
return false;
}
+ if (x->Struct.tags.count != y->Struct.tags.count) {
+ return false;
+ }
+ if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) {
+ return false;
+ }
}
return true;
}
@@ -1683,7 +1785,8 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Tuple:
if (y->kind == Type_Tuple) {
- if (x->Tuple.variables.count == y->Tuple.variables.count) {
+ if (x->Tuple.variables.count == y->Tuple.variables.count &&
+ x->Tuple.is_packed == y->Tuple.is_packed) {
for_array(i, x->Tuple.variables) {
Entity *xe = x->Tuple.variables[i];
Entity *ye = y->Tuple.variables[i];
@@ -1763,6 +1866,7 @@ Type *default_type(Type *type) {
case Basic_UntypedInteger: return t_int;
case Basic_UntypedFloat: return t_f64;
case Basic_UntypedComplex: return t_complex128;
+ case Basic_UntypedQuaternion: return t_quaternion256;
case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune;
}
@@ -2131,19 +2235,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
if (type->Array.count <= 4) {
// HACK(bill): Memory leak
switch (type->Array.count) {
- #define _ARRAY_FIELD_CASE(_length, _name) \
- case (_length): \
- if (field_name == _name) { \
+ #define _ARRAY_FIELD_CASE_IF(_length, _name) \
+ if (field_name == (_name)) { \
selection_add_index(&sel, (_length)-1); \
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
return sel; \
- } \
+ }
+ #define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
+ case (_length): \
+ _ARRAY_FIELD_CASE_IF(_length, _name0); \
+ _ARRAY_FIELD_CASE_IF(_length, _name1); \
/*fallthrough*/
- _ARRAY_FIELD_CASE(4, "w");
- _ARRAY_FIELD_CASE(3, "z");
- _ARRAY_FIELD_CASE(2, "y");
- _ARRAY_FIELD_CASE(1, "x");
+ _ARRAY_FIELD_CASE(4, "w", "a");
+ _ARRAY_FIELD_CASE(3, "z", "b");
+ _ARRAY_FIELD_CASE(2, "y", "g");
+ _ARRAY_FIELD_CASE(1, "x", "r");
default: break;
#undef _ARRAY_FIELD_CASE
@@ -2254,7 +2361,9 @@ i64 type_size_of(Type *t) {
return 0;
}
// NOTE(bill): Always calculate the size when it is a Type_Basic
- if (t->kind != Type_Basic && t->cached_size >= 0) {
+ if (t->kind == Type_Named && t->cached_size >= 0) {
+
+ } else if (t->kind != Type_Basic && t->cached_size >= 0) {
return t->cached_size;
}
TypePath path = {0};
@@ -2269,7 +2378,9 @@ i64 type_align_of(Type *t) {
return 1;
}
// NOTE(bill): Always calculate the size when it is a Type_Basic
- if (t->kind != Type_Basic && t->cached_align > 0) {
+ if (t->kind == Type_Named && t->cached_align >= 0) {
+
+ } if (t->kind != Type_Basic && t->cached_align > 0) {
return t->cached_align;
}
@@ -2303,6 +2414,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
case Basic_complex64: case Basic_complex128:
return type_size_of_internal(t, path) / 2;
+ case Basic_quaternion128: case Basic_quaternion256:
+ return type_size_of_internal(t, path) / 4;
}
} break;
@@ -2488,9 +2601,9 @@ bool type_set_offsets(Type *t) {
}
} else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) {
- t->Struct.are_offsets_being_processed = true;
- t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false);
- t->Struct.are_offsets_being_processed = false;
+ t->Tuple.are_offsets_being_processed = true;
+ t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
+ t->Tuple.are_offsets_being_processed = false;
t->Tuple.are_offsets_set = true;
return true;
}
@@ -2913,35 +3026,54 @@ gbString write_type_to_string(gbString str, Type *type) {
isize comma_index = 0;
for_array(i, type->Tuple.variables) {
Entity *var = type->Tuple.variables[i];
- if (var != nullptr) {
- if (var->kind == Entity_Constant) {
- // Ignore
- continue;
+ if (var == nullptr) {
+ continue;
+ }
+ String name = var->token.string;
+ if (var->kind == Entity_Constant) {
+ str = gb_string_appendc(str, "$");
+ str = gb_string_append_length(str, name.text, name.len);
+ if (!is_type_untyped(var->type)) {
+ str = gb_string_appendc(str, ": ");
+ str = write_type_to_string(str, var->type);
+ str = gb_string_appendc(str, " = ");
+ str = write_exact_value_to_string(str, var->Constant.value);
+ } else {
+ str = gb_string_appendc(str, "=");
+ str = write_exact_value_to_string(str, var->Constant.value);
}
+ continue;
+ }
- if (comma_index++ > 0) {
- str = gb_string_appendc(str, ", ");
- }
+ if (comma_index++ > 0) {
+ str = gb_string_appendc(str, ", ");
+ }
- if (var->kind == Entity_Variable) {
- if (var->flags&EntityFlag_CVarArg) {
- str = gb_string_appendc(str, "#c_vararg ");
- }
- if (var->flags&EntityFlag_Ellipsis) {
- Type *slice = base_type(var->type);
- str = gb_string_appendc(str, "..");
- GB_ASSERT(var->type->kind == Type_Slice);
- str = write_type_to_string(str, slice->Slice.elem);
- } else {
- str = write_type_to_string(str, var->type);
- }
+ if (var->kind == Entity_Variable) {
+ if (var->flags&EntityFlag_CVarArg) {
+ str = gb_string_appendc(str, "#c_vararg ");
+ }
+ if (var->flags&EntityFlag_Ellipsis) {
+ Type *slice = base_type(var->type);
+ str = gb_string_appendc(str, "..");
+ GB_ASSERT(var->type->kind == Type_Slice);
+ str = write_type_to_string(str, slice->Slice.elem);
+ } else {
+ str = write_type_to_string(str, var->type);
+ }
+ } else {
+ GB_ASSERT(var->kind == Entity_TypeName);
+ if (var->type->kind == Type_Generic) {
+ str = gb_string_appendc(str, "typeid/");
+ str = write_type_to_string(str, var->type);
} else {
- GB_ASSERT(var->kind == Entity_TypeName);
- if (var->type->kind == Type_Generic) {
- 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, "type");
+ str = gb_string_appendc(str, "typeid");
}
}
}
diff --git a/src/unicode.cpp b/src/unicode.cpp
index 0ad658806..679d56365 100644
--- a/src/unicode.cpp
+++ b/src/unicode.cpp
@@ -2,7 +2,6 @@
#pragma warning(disable: 4245)
extern "C" {
-#include "utf8proc/utf8proc.h"
#include "utf8proc/utf8proc.c"
}
#pragma warning(pop)
diff --git a/src/utf8proc/utf8proc.c b/src/utf8proc/utf8proc.c
index e821889c6..29fc250fc 100644
--- a/src/utf8proc/utf8proc.c
+++ b/src/utf8proc/utf8proc.c
@@ -40,7 +40,6 @@
* Implementation of libutf8proc.
*/
-
#include "utf8proc.h"
#include "utf8proc_data.c"