Browse Source

Merge remote-tracking branch 'upstream/master'

Chris Heyes 5 years ago
parent
commit
153e7525b5
84 changed files with 9281 additions and 2487 deletions
  1. 57 0
      .github/workflows/ci.yml
  2. 0 24
      .travis.yml
  3. 4 7
      README.md
  4. 0 19
      appveyor.yml
  5. 0 1
      build.bat
  6. 105 0
      core/builtin/builtin.odin
  7. 2 0
      core/c/c.odin
  8. 93 0
      core/encoding/base64/base64.odin
  9. 3 3
      core/encoding/cel/cel.odin
  10. 3 3
      core/encoding/cel/token.odin
  11. 5 6
      core/encoding/json/marshal.odin
  12. 57 231
      core/fmt/fmt.odin
  13. 126 0
      core/intrinsics/intrinsics.odin
  14. 16 16
      core/log/file_console_logger.odin
  15. 36 31
      core/log/log.odin
  16. 283 0
      core/math/linalg/linalg.odin
  17. 362 363
      core/math/math.odin
  18. 2 2
      core/math/rand/normal.odin
  19. 0 2
      core/mem/allocators.odin
  20. 6 0
      core/mem/raw.odin
  21. 114 105
      core/odin/ast/ast.odin
  22. 2 2
      core/odin/ast/clone.odin
  23. 2 2
      core/odin/ast/file.odin
  24. 200 200
      core/odin/parser/parser.odin
  25. 21 23
      core/odin/tokenizer/token.odin
  26. 80 80
      core/odin/tokenizer/tokenizer.odin
  27. 4 4
      core/os/os_darwin.odin
  28. 2402 142
      core/os/os_essence.odin
  29. 3 3
      core/os/os_linux.odin
  30. 1 1
      core/os/os_windows.odin
  31. 396 0
      core/reflect/reflect.odin
  32. 217 1
      core/reflect/types.odin
  33. 98 75
      core/runtime/core.odin
  34. 242 12
      core/runtime/internal.odin
  35. 4 3
      core/sort/sort.odin
  36. 1 1
      core/strconv/decimal/decimal.odin
  37. 2 2
      core/strconv/generic_float.odin
  38. 4 0
      core/strconv/strconv.odin
  39. 4 0
      core/strings/builder.odin
  40. 147 3
      core/strings/strings.odin
  41. 0 24
      core/sys/essence_linker_userland64.ld
  42. 1 1
      core/sys/win32/kernel32.odin
  43. 1 1
      core/sys/win32/user32.odin
  44. 0 0
      core/time/time_darwin.odin
  45. 2 0
      core/time/time_essence.odin
  46. 1 1
      core/time/time_windows.odin
  47. 60 17
      core/unicode/utf8/utf8.odin
  48. 334 40
      examples/demo/demo.odin
  49. BIN
      misc/logo-slim.png
  50. 0 0
      misc/old_demos/demo001.odin
  51. 0 0
      misc/old_demos/demo002.odin
  52. 0 0
      misc/old_demos/demo004.odin
  53. 0 0
      misc/old_demos/demo005.odin
  54. 0 0
      misc/old_demos/demo006.odin
  55. 0 0
      misc/old_demos/demo007.odin
  56. 0 0
      misc/old_demos/demo008.odin
  57. 0 0
      misc/old_demos/old_runtime.odin
  58. 0 0
      misc/old_stuff/demo_backup.odin
  59. 2 2
      misc/shell.bat
  60. 42 14
      src/build_settings.cpp
  61. 163 84
      src/check_decl.cpp
  62. 602 48
      src/check_expr.cpp
  63. 192 29
      src/check_stmt.cpp
  64. 360 40
      src/check_type.cpp
  65. 119 47
      src/checker.cpp
  66. 8 212
      src/checker.hpp
  67. 320 0
      src/checker_builtin_procs.hpp
  68. 4 4
      src/common.cpp
  69. 8 5
      src/entity.cpp
  70. 249 15
      src/exact_value.cpp
  71. 19 11
      src/gb/gb.h
  72. 495 89
      src/ir.cpp
  73. 238 62
      src/ir_print.cpp
  74. 55 60
      src/main.cpp
  75. 301 223
      src/parser.cpp
  76. 46 14
      src/parser.hpp
  77. 2 2
      src/priority_queue.cpp
  78. 70 0
      src/range_cache.cpp
  79. 84 2
      src/string.cpp
  80. 184 0
      src/thread_pool.cpp
  81. 13 1
      src/tokenizer.cpp
  82. 202 70
      src/types.cpp
  83. 0 1
      src/unicode.cpp
  84. 0 1
      src/utf8proc/utf8proc.c

+ 57 - 0
.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
+
+

+ 0 - 24
.travis.yml

@@ -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

+ 4 - 7
README.md

@@ -10,15 +10,12 @@
     <a href="https://github.com/odin-lang/odin/releases/latest">
     <a href="https://github.com/odin-lang/odin/releases/latest">
         <img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
         <img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
     </a>
     </a>
-    <a href="https://github.com/odin-lang/odin/blob/master/LICENSE">
-        <img src="https://img.shields.io/github/license/odin-lang/odin.svg">
-    </a>
     <br>
     <br>
-    <a href="https://ci.appveyor.com/project/ThisDrunkDane/odin-vf0ap">
-        <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>
-    <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>
     </a>
 </p>
 </p>
 
 

+ 0 - 19
appveyor.yml

@@ -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

+ 0 - 1
build.bat

@@ -39,7 +39,6 @@ set linker_settings=%libs% %linker_flags%
 del *.pdb > NUL 2> NUL
 del *.pdb > NUL 2> NUL
 del *.ilk > NUL 2> NUL
 del *.ilk > NUL 2> NUL
 
 
-
 cl %compiler_settings% "src\main.cpp" ^
 cl %compiler_settings% "src\main.cpp" ^
 	/link %linker_settings% -OUT:%exe_name% ^
 	/link %linker_settings% -OUT:%exe_name% ^
 	&& odin run examples/demo/demo.odin
 	&& odin run examples/demo/demo.odin

+ 105 - 0
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 ---

+ 2 - 0
core/c/c.odin

@@ -31,3 +31,5 @@ ssize_t   :: b.int;
 ptrdiff_t :: b.int;
 ptrdiff_t :: b.int;
 uintptr_t :: b.uintptr;
 uintptr_t :: b.uintptr;
 intptr_t  :: b.int;
 intptr_t  :: b.int;
+
+wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32;

+ 93 - 0
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;
+}

+ 3 - 3
core/encoding/cel/cel.odin

@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
 }
 }
 
 
 error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
 error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
-	fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
-	fmt.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;
 	p.error_count += 1;
 }
 }

+ 3 - 3
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) {
 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;
 	t.error_count += 1;
 }
 }
 
 

+ 5 - 6
core/encoding/json/marshal.odin

@@ -5,7 +5,7 @@ import "core:math/bits"
 import "core:runtime"
 import "core:runtime"
 import "core:strconv"
 import "core:strconv"
 import "core:strings"
 import "core:strings"
-import "core:types"
+import "core:reflect"
 
 
 Marshal_Error :: enum {
 Marshal_Error :: enum {
 	None,
 	None,
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
 				data := uintptr(entries.data) + uintptr(i*entry_size);
 				data := uintptr(entries.data) + uintptr(i*entry_size);
 				header := cast(^Map_Entry_Header)data;
 				header := cast(^Map_Entry_Header)data;
 
 
-				if types.is_string(info.key) {
+				if reflect.is_string(info.key) {
 					marshal_arg(b, header.key.str);
 					marshal_arg(b, header.key.str);
 				} else {
 				} else {
 					marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
 					marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
@@ -284,11 +284,10 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
 			t := runtime.type_info_base(ti);
 			t := runtime.type_info_base(ti);
 			switch info in t.variant {
 			switch info in t.variant {
 			case runtime.Type_Info_Integer:
 			case runtime.Type_Info_Integer:
-				using runtime.Type_Info_Endianness;
 				switch info.endianness {
 				switch info.endianness {
-				case Platform: return false;
-				case 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;
 			return false;

+ 57 - 231
core/fmt/fmt.odin

@@ -5,9 +5,9 @@ import "core:os"
 import "core:mem"
 import "core:mem"
 import "core:math/bits"
 import "core:math/bits"
 import "core:unicode/utf8"
 import "core:unicode/utf8"
-import "core:types"
 import "core:strconv"
 import "core:strconv"
 import "core:strings"
 import "core:strings"
+import "core:reflect"
 
 
 
 
 @private
 @private
@@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
 
 
 
 
 // print* procedures return the number of bytes written
 // print* procedures return the number of bytes written
-print       :: proc(args: ..any)              -> int { return fprint(context.stdout, ..args); }
-print_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
 // aprint* procedures return a string that was allocated with the current context
@@ -143,7 +149,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location)
 fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
 fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := strings.builder_from_slice(data[:]);
 	buf := strings.builder_from_slice(data[:]);
-	write_type(&buf, info);
+	reflect.write_type(&buf, info);
 	os.write_string(fd, strings.to_string(buf));
 	os.write_string(fd, strings.to_string(buf));
 }
 }
 
 
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
 	fi.buf = buf;
 	fi.buf = buf;
 
 
 	for arg, i in args {
 	for arg, i in args {
-		is_string := arg != nil && types.is_string(type_info_of(arg.id));
+		is_string := arg != nil && reflect.is_string(type_info_of(arg.id));
 		if i > 0 && !is_string && !prev_string {
 		if i > 0 && !is_string && !prev_string {
 			strings.write_byte(buf, ' ');
 			strings.write_byte(buf, ' ');
 		}
 		}
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
 	strings.write_rune(buf, verb);
 	strings.write_rune(buf, verb);
 	strings.write_byte(buf, '(');
 	strings.write_byte(buf, '(');
 	if arg.id != nil {
 	if arg.id != nil {
-		write_typeid(buf, arg.id);
+		reflect.write_typeid(buf, arg.id);
 		strings.write_byte(buf, '=');
 		strings.write_byte(buf, '=');
 		fmt_value(fi, arg, 'v');
 		fmt_value(fi, arg, 'v');
 	} else {
 	} else {
@@ -792,7 +798,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) {
 	case: return "", false;
 	case: return "", false;
 	case runtime.Type_Info_Enum:
 	case runtime.Type_Info_Enum:
 		get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
 		get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
-			if types.is_string(e.base) {
+			if reflect.is_string(e.base) {
 				for val, idx in e.values {
 				for val, idx in e.values {
 					if v, ok := val.(T); ok && v == i {
 					if v, ok := val.(T); ok && v == i {
 						return e.names[idx], true;
 						return e.names[idx], true;
@@ -947,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
 		if name != "" {
 		if name != "" {
 			strings.write_string(fi.buf, name);
 			strings.write_string(fi.buf, name);
 		} else {
 		} else {
-			write_type(fi.buf, type_info);
+			reflect.write_type(fi.buf, type_info);
 		}
 		}
 		strings.write_byte(fi.buf, '{');
 		strings.write_byte(fi.buf, '{');
 		defer strings.write_byte(fi.buf, '}');
 		defer strings.write_byte(fi.buf, '}');
@@ -1042,7 +1048,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
 	if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
 	if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
 		elem := rt.type_info_base(ot.elem);
 		elem := rt.type_info_base(ot.elem);
 		if elem == nil do return;
 		if elem == nil do return;
-		write_type(fi.buf, type_info);
+		reflect.write_type(fi.buf, type_info);
 		strings.write_byte(fi.buf, '{');
 		strings.write_byte(fi.buf, '{');
 		defer strings.write_byte(fi.buf, '}');
 		defer strings.write_byte(fi.buf, '}');
 
 
@@ -1053,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
 			// Okay
 			// Okay
 		}
 		}
 	} else {
 	} else {
-		write_type(fi.buf, type_info);
+		reflect.write_type(fi.buf, type_info);
 		strings.write_byte(fi.buf, '{');
 		strings.write_byte(fi.buf, '{');
 		strings.write_byte(fi.buf, '}');
 		strings.write_byte(fi.buf, '}');
 	}
 	}
@@ -1101,7 +1107,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 				strings.write_string(fi.buf, name);
 				strings.write_string(fi.buf, name);
 				strings.write_string(fi.buf, " = ");
 				strings.write_string(fi.buf, " = ");
 
 
-				if t := b.types[i]; types.is_any(t) {
+				if t := b.types[i]; reflect.is_any(t) {
 					strings.write_string(fi.buf, "any{}");
 					strings.write_string(fi.buf, "any{}");
 				} else {
 				} else {
 					data := rawptr(uintptr(v.data) + b.offsets[i]);
 					data := rawptr(uintptr(v.data) + b.offsets[i]);
@@ -1129,11 +1135,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 	case runtime.Type_Info_Rune:       fmt_arg(fi, v, verb);
 	case runtime.Type_Info_Rune:       fmt_arg(fi, v, verb);
 	case runtime.Type_Info_Float:      fmt_arg(fi, v, verb);
 	case runtime.Type_Info_Float:      fmt_arg(fi, v, verb);
 	case runtime.Type_Info_Complex:    fmt_arg(fi, v, verb);
 	case runtime.Type_Info_Complex:    fmt_arg(fi, v, verb);
+	case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
 	case runtime.Type_Info_String:     fmt_arg(fi, v, verb);
 	case runtime.Type_Info_String:     fmt_arg(fi, v, verb);
 
 
 	case runtime.Type_Info_Pointer:
 	case runtime.Type_Info_Pointer:
 		if v.id == typeid_of(^runtime.Type_Info) {
 		if v.id == typeid_of(^runtime.Type_Info) {
-			write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
+			reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
 		} else {
 		} else {
 			ptr := (^rawptr)(v.data)^;
 			ptr := (^rawptr)(v.data)^;
 			if verb != 'p' && info.elem != nil {
 			if verb != 'p' && info.elem != nil {
@@ -1256,7 +1263,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 				data := uintptr(entries.data) + uintptr(i*entry_size);
 				data := uintptr(entries.data) + uintptr(i*entry_size);
 				header := cast(^runtime.Map_Entry_Header)data;
 				header := cast(^runtime.Map_Entry_Header)data;
 
 
-				if types.is_string(info.key) {
+				if reflect.is_string(info.key) {
 					strings.write_string(fi.buf, header.key.str);
 					strings.write_string(fi.buf, header.key.str);
 				} else {
 				} else {
 					fi := Info{buf = fi.buf};
 					fi := Info{buf = fi.buf};
@@ -1297,7 +1304,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 			strings.write_string(fi.buf, info.names[i]);
 			strings.write_string(fi.buf, info.names[i]);
 			strings.write_string(fi.buf, " = ");
 			strings.write_string(fi.buf, " = ");
 
 
-			if t := info.types[i]; types.is_any(t) {
+			if t := info.types[i]; reflect.is_any(t) {
 				strings.write_string(fi.buf, "any{}");
 				strings.write_string(fi.buf, "any{}");
 			} else {
 			} else {
 				data := uintptr(v.data) + info.offsets[i];
 				data := uintptr(v.data) + info.offsets[i];
@@ -1349,14 +1356,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 		if ptr == nil {
 		if ptr == nil {
 			strings.write_string(fi.buf, "nil");
 			strings.write_string(fi.buf, "nil");
 		} else {
 		} else {
-			write_typeid(fi.buf, v.id);
+			reflect.write_typeid(fi.buf, v.id);
 			strings.write_string(fi.buf, " @ ");
 			strings.write_string(fi.buf, " @ ");
 			fmt_pointer(fi, ptr, 'p');
 			fmt_pointer(fi, ptr, 'p');
 		}
 		}
 
 
 	case runtime.Type_Info_Type_Id:
 	case runtime.Type_Info_Type_Id:
 		id := (^typeid)(v.data)^;
 		id := (^typeid)(v.data)^;
-		write_typeid(fi.buf, id);
+		reflect.write_typeid(fi.buf, id);
 
 
 	case runtime.Type_Info_Bit_Field:
 	case runtime.Type_Info_Bit_Field:
 		fmt_bit_field(fi, v);
 		fmt_bit_field(fi, v);
@@ -1386,6 +1393,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
 	}
 	}
 }
 }
 
 
+fmt_quaternion  :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) {
+	switch verb {
+	case 'f', 'F', 'v', 'h', 'H':
+		r, i, j, k := real(q), imag(q), jmag(q), kmag(q);
+
+		fmt_float(fi, r, bits/4, verb);
+
+		if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+');
+		fmt_float(fi, i, bits/4, verb);
+		strings.write_rune(fi.buf, 'i');
+
+		if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+');
+		fmt_float(fi, j, bits/4, verb);
+		strings.write_rune(fi.buf, 'j');
+
+		if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+');
+		fmt_float(fi, k, bits/4, verb);
+		strings.write_rune(fi.buf, 'k');
+
+	case:
+		fmt_bad_verb(fi, verb);
+		return;
+	}
+}
+
 fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 	if arg == nil {
 	if arg == nil {
 		strings.write_string(fi.buf, "<nil>");
 		strings.write_string(fi.buf, "<nil>");
@@ -1398,7 +1430,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 		switch a in arg {
 		switch a in arg {
 		case ^runtime.Type_Info: ti = a;
 		case ^runtime.Type_Info: ti = a;
 		}
 		}
-		write_type(fi.buf, ti);
+		reflect.write_type(fi.buf, ti);
 		return;
 		return;
 	}
 	}
 
 
@@ -1434,6 +1466,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 	case complex64:  fmt_complex(fi, complex128(a), 64, verb);
 	case complex64:  fmt_complex(fi, complex128(a), 64, verb);
 	case complex128: fmt_complex(fi, a, 128, verb);
 	case complex128: fmt_complex(fi, a, 128, verb);
 
 
+	case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
+	case quaternion256: fmt_quaternion(fi, a, 256, verb);
+
 	case i8:      fmt_int(fi, u64(a), true,   8, verb);
 	case i8:      fmt_int(fi, u64(a), true,   8, verb);
 	case u8:      fmt_int(fi, u64(a), false,  8, verb);
 	case u8:      fmt_int(fi, u64(a), false,  8, verb);
 	case i16:     fmt_int(fi, u64(a), true,  16, verb);
 	case i16:     fmt_int(fi, u64(a), true,  16, verb);
@@ -1449,7 +1484,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 	case string:  fmt_string(fi, a, verb);
 	case string:  fmt_string(fi, a, verb);
 	case cstring: fmt_cstring(fi, a, verb);
 	case cstring: fmt_cstring(fi, a, verb);
 
 
-	case typeid:  write_typeid(fi.buf, a);
+	case typeid:  reflect.write_typeid(fi.buf, a);
 
 
 	case i16le:     fmt_int(fi, u64(a), true,  16, verb);
 	case i16le:     fmt_int(fi, u64(a), true,  16, verb);
 	case u16le:     fmt_int(fi, u64(a), false, 16, verb);
 	case u16le:     fmt_int(fi, u64(a), false, 16, verb);
@@ -1482,212 +1517,3 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 
 
 
 
 
 
-
-write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
-	write_type(buf, type_info_of(id));
-}
-
-write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
-	using strings;
-	if ti == nil {
-		write_string(buf, "nil");
-		return;
-	}
-
-	switch info in ti.variant {
-	case runtime.Type_Info_Named:
-		write_string(buf, info.name);
-	case runtime.Type_Info_Integer:
-		switch ti.id {
-		case int:     write_string(buf, "int");
-		case uint:    write_string(buf, "uint");
-		case uintptr: write_string(buf, "uintptr");
-		case:
-			write_byte(buf, info.signed ? 'i' : 'u');
-			write_i64(buf, i64(8*ti.size), 10);
-			switch info.endianness {
-			case runtime.Type_Info_Endianness.Little:
-				write_string(buf, "le");
-			case runtime.Type_Info_Endianness.Big:
-				write_string(buf, "be");
-			}
-		}
-	case runtime.Type_Info_Rune:
-		write_string(buf, "rune");
-	case runtime.Type_Info_Float:
-		write_byte(buf, 'f');
-		write_i64(buf, i64(8*ti.size), 10);
-	case runtime.Type_Info_Complex:
-		write_string(buf, "complex");
-		write_i64(buf, i64(8*ti.size), 10);
-	case runtime.Type_Info_String:
-		if info.is_cstring {
-			write_string(buf, "cstring");
-		} else {
-			write_string(buf, "string");
-		}
-	case runtime.Type_Info_Boolean:
-		switch ti.id {
-		case bool: write_string(buf, "bool");
-		case:
-			write_byte(buf, 'b');
-			write_i64(buf, i64(8*ti.size), 10);
-		}
-	case runtime.Type_Info_Any:
-		write_string(buf, "any");
-
-	case runtime.Type_Info_Type_Id:
-		write_string(buf, "typeid");
-
-	case runtime.Type_Info_Pointer:
-		if info.elem == nil {
-			write_string(buf, "rawptr");
-		} else {
-			write_string(buf, "^");
-			write_type(buf, info.elem);
-		}
-	case runtime.Type_Info_Procedure:
-		write_string(buf, "proc");
-		if info.params == nil {
-			write_string(buf, "()");
-		} else {
-			t := info.params.variant.(runtime.Type_Info_Tuple);
-			write_string(buf, "(");
-			for t, i in t.types {
-				if i > 0 do write_string(buf, ", ");
-				write_type(buf, t);
-			}
-			write_string(buf, ")");
-		}
-		if info.results != nil {
-			write_string(buf, " -> ");
-			write_type(buf, info.results);
-		}
-	case runtime.Type_Info_Tuple:
-		count := len(info.names);
-		if count != 1 do write_string(buf, "(");
-		for name, i in info.names {
-			if i > 0 do write_string(buf, ", ");
-
-			t := info.types[i];
-
-			if len(name) > 0 {
-				write_string(buf, name);
-				write_string(buf, ": ");
-			}
-			write_type(buf, t);
-		}
-		if count != 1 do write_string(buf, ")");
-
-	case runtime.Type_Info_Array:
-		write_string(buf, "[");
-		write_i64(buf, i64(info.count), 10);
-		write_string(buf, "]");
-		write_type(buf, info.elem);
-	case runtime.Type_Info_Dynamic_Array:
-		write_string(buf, "[dynamic]");
-		write_type(buf, info.elem);
-	case runtime.Type_Info_Slice:
-		write_string(buf, "[]");
-		write_type(buf, info.elem);
-
-	case runtime.Type_Info_Map:
-		write_string(buf, "map[");
-		write_type(buf, info.key);
-		write_byte(buf, ']');
-		write_type(buf, info.value);
-
-	case runtime.Type_Info_Struct:
-		write_string(buf, "struct ");
-		if info.is_packed    do write_string(buf, "#packed ");
-		if info.is_raw_union do write_string(buf, "#raw_union ");
-		if info.custom_align {
-			write_string(buf, "#align ");
-			write_i64(buf, i64(ti.align), 10);
-			write_byte(buf, ' ');
-		}
-		write_byte(buf, '{');
-		for name, i in info.names {
-			if i > 0 do write_string(buf, ", ");
-			write_string(buf, name);
-			write_string(buf, ": ");
-			write_type(buf, info.types[i]);
-		}
-		write_byte(buf, '}');
-
-	case runtime.Type_Info_Union:
-		write_string(buf, "union ");
-		if info.custom_align {
-			write_string(buf, "#align ");
-			write_i64(buf, i64(ti.align), 10);
-			write_byte(buf, ' ');
-		}
-		write_byte(buf, '{');
-		for variant, i in info.variants {
-			if i > 0 do write_string(buf, ", ");
-			write_type(buf, variant);
-		}
-		write_byte(buf, '}');
-
-	case runtime.Type_Info_Enum:
-		write_string(buf, "enum ");
-		write_type(buf, info.base);
-		write_string(buf, " {");
-		for name, i in info.names {
-			if i > 0 do write_string(buf, ", ");
-			write_string(buf, name);
-		}
-		write_byte(buf, '}');
-
-	case runtime.Type_Info_Bit_Field:
-		write_string(buf, "bit_field ");
-		if ti.align != 1 {
-			write_string(buf, "#align ");
-			write_i64(buf, i64(ti.align), 10);
-			write_byte(buf, ' ');
-		}
-		write_string(buf, " {");
-		for name, i in info.names {
-			if i > 0 do write_string(buf, ", ");
-			write_string(buf, name);
-			write_string(buf, ": ");
-			write_i64(buf, i64(info.bits[i]), 10);
-		}
-		write_byte(buf, '}');
-
-	case runtime.Type_Info_Bit_Set:
-		write_string(buf, "bit_set[");
-		switch {
-		case types.is_enum(info.elem):
-			write_type(buf, info.elem);
-		case types.is_rune(info.elem):
-			write_encoded_rune(buf, rune(info.lower));
-			write_string(buf, "..");
-			write_encoded_rune(buf, rune(info.upper));
-		case:
-			write_i64(buf, info.lower, 10);
-			write_string(buf, "..");
-			write_i64(buf, info.upper, 10);
-		}
-		if info.underlying != nil {
-			write_string(buf, "; ");
-			write_type(buf, info.underlying);
-		}
-		write_byte(buf, ']');
-
-	case runtime.Type_Info_Opaque:
-		write_string(buf, "opaque ");
-		write_type(buf, info.elem);
-
-	case runtime.Type_Info_Simd_Vector:
-		if info.is_x86_mmx {
-			write_string(buf, "intrinsics.x86_mmx");
-		} else {
-			write_string(buf, "intrinsics.vector(");
-			write_i64(buf, i64(info.count));
-			write_string(buf, ", ");
-			write_type(buf, info.elem);
-			write_byte(buf, ')');
-		}
-	}
-}

+ 126 - 0
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) ---

+ 16 - 16
core/log/file_console_logger.odin

@@ -14,18 +14,18 @@ Level_Headers := []string{
 };
 };
 
 
 Default_Console_Logger_Opts :: Options{
 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;
 } | Full_Timestamp_Opts;
 
 
 Default_File_Logger_Opts :: Options{
 Default_File_Logger_Opts :: Options{
-    Option.Level,
-    Option.Short_File_Path,
-    Option.Line,
-    Option.Procedure,
+    .Level,
+    .Short_File_Path,
+    .Line,
+    .Procedure,
 } | Full_Timestamp_Opts;
 } | Full_Timestamp_Opts;
 
 
 
 
@@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
     case Level.Error, Level.Fatal : col = RED;
     case Level.Error, Level.Fatal : col = RED;
     }
     }
 
 
-    if Option.Level in opts {
-        if 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]);
         fmt.sbprint(str, Level_Headers[level]);
-        if Option.Terminal_Color in opts do fmt.sbprint(str, RESET);
+        if .Terminal_Color in opts do fmt.sbprint(str, RESET);
     }
     }
 }
 }
 
 
@@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
     if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
     if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
 
 
     file := location.file_path;
     file := location.file_path;
-    if Option.Short_File_Path in opts {
+    if .Short_File_Path in opts {
         when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
         when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
         last := 0;
         last := 0;
         for r, i in location.file_path do if r == delimiter do last = i+1;
         for r, i in location.file_path do if r == delimiter do last = i+1;
@@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
 
 
     if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
     if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
 
 
-    if Option.Procedure in opts {
+    if .Procedure in opts {
         if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
         if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
         fmt.sbprintf(buf, "%s()", location.procedure);
         fmt.sbprintf(buf, "%s()", location.procedure);
     }
     }
 
 
-    if Option.Line in opts {
-        if 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);
         fmt.sbprint(buf, location.line);
     }
     }
 
 

+ 36 - 31
core/log/log.odin

@@ -11,30 +11,30 @@ Level :: enum {
 }
 }
 
 
 Option :: 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];
 Options :: bit_set[Option];
 Full_Timestamp_Opts :: Options{
 Full_Timestamp_Opts :: Options{
-    Option.Date,
-    Option.Time
+	.Date,
+	.Time
 };
 };
 Location_Header_Opts :: Options{
 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{
 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);
 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 {
 Logger :: struct {
 	procedure: Logger_Proc,
 	procedure: Logger_Proc,
 	data:      rawptr,
 	data:      rawptr,
-    options:   Options,
+	options:   Options,
 }
 }
 
 
 Multi_Logger_Data :: struct {
 Multi_Logger_Data :: struct {
-    loggers : []Logger,
+	loggers : []Logger,
 }
 }
 
 
 create_multi_logger :: proc(logs: ..Logger) -> 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,
 multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
                           options: Options, location := #caller_location) {
                           options: Options, location := #caller_location) {
-    data := cast(^Multi_Logger_Data)logger_data;
-    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) {
 nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
@@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger {
 	return Logger{nil_logger_proc, nil, nil};
 	return Logger{nil_logger_proc, nil, nil};
 }
 }
 
 
+// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
 debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug,   fmt_str=fmt_str, args=args, location=location);
 debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug,   fmt_str=fmt_str, args=args, location=location);
 info  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info,    fmt_str=fmt_str, args=args, location=location);
 info  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info,    fmt_str=fmt_str, args=args, location=location);
 warn  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
 warn  :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
@@ -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);
 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) {
 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);
 }
 }

+ 283 - 0
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;
+}

+ 362 - 363
core/math/math.odin

@@ -1,36 +1,41 @@
 package math
 package math
 
 
+import "intrinsics"
+
+Float_Class :: enum {
+	Normal,    // an ordinary nonzero floating point value
+	Subnormal, // a subnormal floating point value
+	Zero,      // zero
+	Neg_Zero,  // the negative zero
+	NaN,       // Not-A-Number (NaN)
+	Inf,       // positive infinity
+	Neg_Inf    // negative infinity
+};
+
 TAU          :: 6.28318530717958647692528676655900576;
 TAU          :: 6.28318530717958647692528676655900576;
 PI           :: 3.14159265358979323846264338327950288;
 PI           :: 3.14159265358979323846264338327950288;
 
 
 E            :: 2.71828182845904523536;
 E            :: 2.71828182845904523536;
-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;
 τ :: TAU;
 π :: PI;
 π :: 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 _ {
 foreign _ {
 	@(link_name="llvm.sqrt.f32")
 	@(link_name="llvm.sqrt.f32")
 	sqrt_f32 :: proc(x: f32) -> f32 ---;
 	sqrt_f32 :: proc(x: f32) -> f32 ---;
@@ -58,9 +63,9 @@ foreign _ {
 	fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
 	fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
 
 
 	@(link_name="llvm.log.f32")
 	@(link_name="llvm.log.f32")
-	log_f32 :: proc(x: f32) -> f32 ---;
+	ln_f32 :: proc(x: f32) -> f32 ---;
 	@(link_name="llvm.log.f64")
 	@(link_name="llvm.log.f64")
-	log_f64 :: proc(x: f64) -> f64 ---;
+	ln_f64 :: proc(x: f64) -> f64 ---;
 
 
 	@(link_name="llvm.exp.f32")
 	@(link_name="llvm.exp.f32")
 	exp_f32 :: proc(x: f32) -> f32 ---;
 	exp_f32 :: proc(x: f32) -> f32 ---;
@@ -68,20 +73,40 @@ foreign _ {
 	exp_f64 :: proc(x: f64) -> f64 ---;
 	exp_f64 :: proc(x: f64) -> f64 ---;
 }
 }
 
 
-log :: proc{log_f32, log_f64};
-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_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
 tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
 tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
+tan     :: proc{tan_f32, tan_f64};
 
 
 lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
 lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
 
 
 unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
 unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
 unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
 unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
+unlerp     :: proc{unlerp_f32, unlerp_f64};
 
 
-
-sign_f32 :: proc(x: f32) -> f32 { return 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 {
 copy_sign_f32 :: proc(x, y: f32) -> f32 {
 	ix := transmute(u32)x;
 	ix := transmute(u32)x;
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
 	ix |= iy & 0x8000_0000;
 	ix |= iy & 0x8000_0000;
 	return transmute(f32)ix;
 	return transmute(f32)ix;
 }
 }
-
 copy_sign_f64 :: proc(x, y: f64) -> f64 {
 copy_sign_f64 :: proc(x, y: f64) -> f64 {
 	ix := transmute(u64)x;
 	ix := transmute(u64)x;
 	iy := transmute(u64)y;
 	iy := transmute(u64)y;
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
 	ix |= iy & 0x8000_0000_0000_0000;
 	ix |= iy & 0x8000_0000_0000_0000;
 	return transmute(f64)ix;
 	return transmute(f64)ix;
 }
 }
+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};
 round :: proc{round_f32, round_f64};
 
 
+
+ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
+ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
+ceil :: proc{ceil_f32, ceil_f64};
+
 floor_f32 :: proc(x: f32) -> f32 {
 floor_f32 :: proc(x: f32) -> f32 {
 	if x == 0 || is_nan(x) || is_inf(x) {
 	if x == 0 || is_nan(x) || is_inf(x) {
 		return x;
 		return x;
@@ -144,33 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
 }
 }
 floor :: proc{floor_f32, floor_f64};
 floor :: proc{floor_f32, floor_f64};
 
 
-ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); }
-ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); }
-ceil :: proc{ceil_f32, ceil_f64};
 
 
-remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
-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) {
 modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
 	shift :: 32 - 8 - 1;
 	shift :: 32 - 8 - 1;
 	mask  :: 0xff;
 	mask  :: 0xff;
@@ -190,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
 	i := transmute(u32)x;
 	i := transmute(u32)x;
 	e := uint(i>>shift)&mask - bias;
 	e := uint(i>>shift)&mask - bias;
 
 
-	if e < 32-9 {
-		i &~= 1<<(32-9-e) - 1;
+	if e < shift {
+		i &~= 1<<(shift-e) - 1;
 	}
 	}
 	int = transmute(f32)i;
 	int = transmute(f32)i;
 	frac = x - int;
 	frac = x - int;
@@ -216,361 +301,275 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
 	i := transmute(u64)x;
 	i := transmute(u64)x;
 	e := uint(i>>shift)&mask - bias;
 	e := uint(i>>shift)&mask - bias;
 
 
-	if e < 64-12 {
-		i &~= 1<<(64-12-e) - 1;
+	if e < shift {
+		i &~= 1<<(shift-e) - 1;
 	}
 	}
 	int = transmute(f64)i;
 	int = transmute(f64)i;
 	frac = x - int;
 	frac = x - int;
 	return;
 	return;
 }
 }
 modf :: proc{modf_f32, modf_f64};
 modf :: proc{modf_f32, modf_f64};
+split_decimal :: modf;
 
 
-is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; }
-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_DIG        :: 6;
 F32_EPSILON    :: 1.192092896e-07;
 F32_EPSILON    :: 1.192092896e-07;
 F32_GUARD      :: 0;
 F32_GUARD      :: 0;

+ 2 - 2
core/math/rand/normal.odin

@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
 
 
 		if i == 0 {
 		if i == 0 {
 			for {
 			for {
-				x = -math.log(float64(r)) * (1.0/ rn);
-				y := -math.log(float64(r));
+				x = -math.ln(float64(r)) * (1.0/ rn);
+				y := -math.ln(float64(r));
 				if y+y >= x*x {
 				if y+y >= x*x {
 					break;
 					break;
 				}
 				}

+ 0 - 2
core/mem/allocators.odin

@@ -1,7 +1,5 @@
 package mem
 package mem
 
 
-
-
 nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
 nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
                            size, alignment: int,
                            size, alignment: int,
                            old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
                            old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {

+ 6 - 0
core/mem/raw.odin

@@ -31,6 +31,12 @@ Raw_Map :: struct {
 	entries: Raw_Dynamic_Array,
 	entries: Raw_Dynamic_Array,
 }
 }
 
 
+Raw_Complex64     :: struct {real, imag: f32};
+Raw_Complex128    :: struct {real, imag: f64};
+Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32};
+Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64};
+Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32};
+Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64};
 
 
 make_any :: inline proc(data: rawptr, id: typeid) -> any {
 make_any :: inline proc(data: rawptr, id: typeid) -> any {
 	return transmute(any)Raw_Any{data, id};
 	return transmute(any)Raw_Any{data, id};

+ 114 - 105
core/odin/ast/ast.odin

@@ -1,11 +1,10 @@
 package odin_ast
 package odin_ast
 
 
-import "core:odin/token"
+import "core:odin/tokenizer"
 
 
 Proc_Tag :: enum {
 Proc_Tag :: enum {
 	Bounds_Check,
 	Bounds_Check,
 	No_Bounds_Check,
 	No_Bounds_Check,
-	Require_Results,
 }
 }
 Proc_Tags :: distinct bit_set[Proc_Tag; u32];
 Proc_Tags :: distinct bit_set[Proc_Tag; u32];
 
 
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
 
 
 
 
 Comment_Group :: struct {
 Comment_Group :: struct {
-	list: []token.Token,
+	list: []tokenizer.Token,
 }
 }
 
 
 Node :: struct {
 Node :: struct {
-	pos:         token.Pos,
-	end:         token.Pos,
+	pos:         tokenizer.Pos,
+	end:         tokenizer.Pos,
 	derived:     any,
 	derived:     any,
 	state_flags: Node_State_Flags,
 	state_flags: Node_State_Flags,
 }
 }
@@ -68,29 +67,29 @@ Ident :: struct {
 
 
 Implicit :: struct {
 Implicit :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok: token.Token,
+	tok: tokenizer.Token,
 }
 }
 
 
 
 
 Undef :: struct {
 Undef :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:  token.Kind,
+	tok:  tokenizer.Token_Kind,
 }
 }
 
 
 Basic_Lit :: struct {
 Basic_Lit :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok: token.Token,
+	tok: tokenizer.Token,
 }
 }
 
 
 Basic_Directive :: struct {
 Basic_Directive :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:  token.Token,
+	tok:  tokenizer.Token,
 	name: string,
 	name: string,
 }
 }
 
 
 Ellipsis :: struct {
 Ellipsis :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:  token.Kind,
+	tok:  tokenizer.Token_Kind,
 	expr: ^Expr,
 	expr: ^Expr,
 }
 }
 
 
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
 	body: ^Stmt,
 	body: ^Stmt,
 	tags: Proc_Tags,
 	tags: Proc_Tags,
 	inlining: Proc_Inlining,
 	inlining: Proc_Inlining,
+	where_token: tokenizer.Token,
+	where_clauses: []^Expr,
 }
 }
 
 
 Comp_Lit :: struct {
 Comp_Lit :: struct {
 	using node: Expr,
 	using node: Expr,
 	type: ^Expr,
 	type: ^Expr,
-	open: token.Pos,
+	open: tokenizer.Pos,
 	elems: []^Expr,
 	elems: []^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 
 
 Tag_Expr :: struct {
 Tag_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
-	op:      token.Token,
+	op:      tokenizer.Token,
 	name:    string,
 	name:    string,
 	expr:    ^Expr,
 	expr:    ^Expr,
 }
 }
 
 
 Unary_Expr :: struct {
 Unary_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
-	op:   token.Token,
+	op:   tokenizer.Token,
 	expr: ^Expr,
 	expr: ^Expr,
 }
 }
 
 
 Binary_Expr :: struct {
 Binary_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	left:  ^Expr,
 	left:  ^Expr,
-	op:    token.Token,
+	op:    tokenizer.Token,
 	right: ^Expr,
 	right: ^Expr,
 }
 }
 
 
 Paren_Expr :: struct {
 Paren_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
-	open:  token.Pos,
+	open:  tokenizer.Pos,
 	expr:  ^Expr,
 	expr:  ^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 Selector_Expr :: struct {
 Selector_Expr :: struct {
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
 Index_Expr :: struct {
 Index_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	expr:  ^Expr,
 	expr:  ^Expr,
-	open:  token.Pos,
+	open:  tokenizer.Pos,
 	index: ^Expr,
 	index: ^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 Deref_Expr :: struct {
 Deref_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	expr: ^Expr,
 	expr: ^Expr,
-	op:   token.Token,
+	op:   tokenizer.Token,
 }
 }
 
 
 Slice_Expr :: struct {
 Slice_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	expr:     ^Expr,
 	expr:     ^Expr,
-	open:     token.Pos,
+	open:     tokenizer.Pos,
 	low:      ^Expr,
 	low:      ^Expr,
-	interval: token.Token,
+	interval: tokenizer.Token,
 	high:     ^Expr,
 	high:     ^Expr,
-	close:    token.Pos,
+	close:    tokenizer.Pos,
 }
 }
 
 
 Call_Expr :: struct {
 Call_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	inlining: Proc_Inlining,
 	inlining: Proc_Inlining,
 	expr:     ^Expr,
 	expr:     ^Expr,
-	open:     token.Pos,
+	open:     tokenizer.Pos,
 	args:     []^Expr,
 	args:     []^Expr,
-	ellipsis: token.Token,
-	close:    token.Pos,
+	ellipsis: tokenizer.Token,
+	close:    tokenizer.Pos,
 }
 }
 
 
 Field_Value :: struct {
 Field_Value :: struct {
 	using node: Expr,
 	using node: Expr,
 	field: ^Expr,
 	field: ^Expr,
-	sep:   token.Pos,
+	sep:   tokenizer.Pos,
 	value: ^Expr,
 	value: ^Expr,
 }
 }
 
 
 Ternary_Expr :: struct {
 Ternary_Expr :: struct {
 	using node: Expr,
 	using node: Expr,
 	cond: ^Expr,
 	cond: ^Expr,
-	op1:  token.Token,
+	op1:  tokenizer.Token,
 	x:    ^Expr,
 	x:    ^Expr,
-	op2:  token.Token,
+	op2:  tokenizer.Token,
 	y:    ^Expr,
 	y:    ^Expr,
 }
 }
 
 
 Type_Assertion :: struct {
 Type_Assertion :: struct {
 	using node: Expr,
 	using node: Expr,
 	expr:  ^Expr,
 	expr:  ^Expr,
-	dot:   token.Pos,
-	open:  token.Pos,
+	dot:   tokenizer.Pos,
+	open:  tokenizer.Pos,
 	type:  ^Expr,
 	type:  ^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 Type_Cast :: struct {
 Type_Cast :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:   token.Token,
-	open:  token.Pos,
+	tok:   tokenizer.Token,
+	open:  tokenizer.Pos,
 	type:  ^Expr,
 	type:  ^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 	expr:  ^Expr,
 	expr:  ^Expr,
 }
 }
 
 
 Auto_Cast :: struct {
 Auto_Cast :: struct {
 	using node: Expr,
 	using node: Expr,
-	op:   token.Token,
+	op:   tokenizer.Token,
 	expr: ^Expr,
 	expr: ^Expr,
 }
 }
 
 
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
 
 
 Empty_Stmt :: struct {
 Empty_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
-	semicolon: token.Pos, // Position of the following ';'
+	semicolon: tokenizer.Pos, // Position of the following ';'
 }
 }
 
 
 Expr_Stmt :: struct {
 Expr_Stmt :: struct {
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
 
 
 Tag_Stmt :: struct {
 Tag_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
-	op:      token.Token,
+	op:      tokenizer.Token,
 	name:    string,
 	name:    string,
 	stmt:    ^Stmt,
 	stmt:    ^Stmt,
 }
 }
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
 Assign_Stmt :: struct {
 Assign_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	lhs:    []^Expr,
 	lhs:    []^Expr,
-	op:     token.Token,
+	op:     tokenizer.Token,
 	rhs:    []^Expr,
 	rhs:    []^Expr,
 }
 }
 
 
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
 Block_Stmt :: struct {
 Block_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	label: ^Expr,
 	label: ^Expr,
-	open:  token.Pos,
+	open:  tokenizer.Pos,
 	stmts: []^Stmt,
 	stmts: []^Stmt,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 If_Stmt :: struct {
 If_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	label:     ^Expr,
 	label:     ^Expr,
-	if_pos:    token.Pos,
+	if_pos:    tokenizer.Pos,
 	init:      ^Stmt,
 	init:      ^Stmt,
 	cond:      ^Expr,
 	cond:      ^Expr,
 	body:      ^Stmt,
 	body:      ^Stmt,
@@ -277,7 +278,7 @@ If_Stmt :: struct {
 
 
 When_Stmt :: struct {
 When_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
-	when_pos:  token.Pos,
+	when_pos:  tokenizer.Pos,
 	cond:      ^Expr,
 	cond:      ^Expr,
 	body:      ^Stmt,
 	body:      ^Stmt,
 	else_stmt: ^Stmt,
 	else_stmt: ^Stmt,
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
 For_Stmt :: struct {
 For_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	label:     ^Expr,
 	label:     ^Expr,
-	for_pos:   token.Pos,
+	for_pos:   tokenizer.Pos,
 	init:      ^Stmt,
 	init:      ^Stmt,
 	cond:      ^Expr,
 	cond:      ^Expr,
 	post:      ^Stmt,
 	post:      ^Stmt,
@@ -306,10 +307,10 @@ For_Stmt :: struct {
 Range_Stmt :: struct {
 Range_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	label:     ^Expr,
 	label:     ^Expr,
-	for_pos:   token.Pos,
+	for_pos:   tokenizer.Pos,
 	val0:      ^Expr,
 	val0:      ^Expr,
 	val1:      ^Expr,
 	val1:      ^Expr,
-	in_pos:    token.Pos,
+	in_pos:    tokenizer.Pos,
 	expr:      ^Expr,
 	expr:      ^Expr,
 	body:      ^Stmt,
 	body:      ^Stmt,
 }
 }
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
 
 
 Case_Clause :: struct {
 Case_Clause :: struct {
 	using node: Stmt,
 	using node: Stmt,
-	case_pos:   token.Pos,
+	case_pos:   tokenizer.Pos,
 	list:       []^Expr,
 	list:       []^Expr,
-	terminator: token.Token,
+	terminator: tokenizer.Token,
 	body:       []^Stmt,
 	body:       []^Stmt,
 }
 }
 
 
 Switch_Stmt :: struct {
 Switch_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	label:      ^Expr,
 	label:      ^Expr,
-	switch_pos: token.Pos,
+	switch_pos: tokenizer.Pos,
 	init:       ^Stmt,
 	init:       ^Stmt,
 	cond:       ^Expr,
 	cond:       ^Expr,
 	body:       ^Stmt,
 	body:       ^Stmt,
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
 Type_Switch_Stmt :: struct {
 Type_Switch_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
 	label:      ^Expr,
 	label:      ^Expr,
-	switch_pos: token.Pos,
+	switch_pos: tokenizer.Pos,
 	tag:        ^Stmt,
 	tag:        ^Stmt,
 	expr:       ^Expr,
 	expr:       ^Expr,
 	body:       ^Stmt,
 	body:       ^Stmt,
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
 
 
 Branch_Stmt :: struct {
 Branch_Stmt :: struct {
 	using node: Stmt,
 	using node: Stmt,
-	tok:   token.Token,
+	tok:   tokenizer.Token,
 	label: ^Ident,
 	label: ^Ident,
 }
 }
 
 
@@ -376,7 +377,7 @@ Value_Decl :: struct {
 Package_Decl :: struct {
 Package_Decl :: struct {
 	using node: Decl,
 	using node: Decl,
 	docs:    ^Comment_Group,
 	docs:    ^Comment_Group,
-	token:   token.Token,
+	token:   tokenizer.Token,
 	name:    string,
 	name:    string,
 	comment: ^Comment_Group,
 	comment: ^Comment_Group,
 }
 }
@@ -385,9 +386,9 @@ Import_Decl :: struct {
 	using node: Decl,
 	using node: Decl,
 	docs:       ^Comment_Group,
 	docs:       ^Comment_Group,
 	is_using:    bool,
 	is_using:    bool,
-	import_tok:  token.Token,
-	name:        token.Token,
-	relpath:     token.Token,
+	import_tok:  tokenizer.Token,
+	name:        tokenizer.Token,
+	relpath:     tokenizer.Token,
 	fullpath:    string,
 	fullpath:    string,
 	comment:     ^Comment_Group,
 	comment:     ^Comment_Group,
 }
 }
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
 	using node: Decl,
 	using node: Decl,
 	docs:            ^Comment_Group,
 	docs:            ^Comment_Group,
 	attributes:      [dynamic]^Attribute, // dynamic as parsing will add to them lazily
 	attributes:      [dynamic]^Attribute, // dynamic as parsing will add to them lazily
-	tok:             token.Token,
+	tok:             tokenizer.Token,
 	foreign_library: ^Expr,
 	foreign_library: ^Expr,
 	body:            ^Stmt,
 	body:            ^Stmt,
 }
 }
@@ -404,8 +405,8 @@ Foreign_Block_Decl :: struct {
 Foreign_Import_Decl :: struct {
 Foreign_Import_Decl :: struct {
 	using node: Decl,
 	using node: Decl,
 	docs:            ^Comment_Group,
 	docs:            ^Comment_Group,
-	foreign_tok:     token.Token,
-	import_tok:      token.Token,
+	foreign_tok:     tokenizer.Token,
+	import_tok:      tokenizer.Token,
 	name:            ^Ident,
 	name:            ^Ident,
 	collection_name: string,
 	collection_name: string,
 	fullpaths:       []string,
 	fullpaths:       []string,
@@ -435,7 +436,9 @@ Field_Flag :: enum {
 	C_Vararg,
 	C_Vararg,
 	Auto_Cast,
 	Auto_Cast,
 	In,
 	In,
+
 	Results,
 	Results,
+	Tags,
 	Default_Parameters,
 	Default_Parameters,
 	Typeid_Token,
 	Typeid_Token,
 }
 }
@@ -443,18 +446,19 @@ Field_Flag :: enum {
 Field_Flags :: distinct bit_set[Field_Flag];
 Field_Flags :: distinct bit_set[Field_Flag];
 
 
 Field_Flags_Struct :: Field_Flags{
 Field_Flags_Struct :: Field_Flags{
-	Field_Flag.Using,
+	.Using,
+	.Tags,
 };
 };
 Field_Flags_Record_Poly_Params :: Field_Flags{
 Field_Flags_Record_Poly_Params :: Field_Flags{
-	Field_Flag.Typeid_Token,
+	.Typeid_Token,
 };
 };
 Field_Flags_Signature :: Field_Flags{
 Field_Flags_Signature :: Field_Flags{
-	Field_Flag.Ellipsis,
-	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};
 Field_Flags_Signature_Params  :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
@@ -463,18 +467,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
 
 
 Proc_Group :: struct {
 Proc_Group :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:   token.Token,
-	open:  token.Pos,
+	tok:   tokenizer.Token,
+	open:  tokenizer.Pos,
 	args:  []^Expr,
 	args:  []^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 Attribute :: struct {
 Attribute :: struct {
 	using node: Node,
 	using node: Node,
-	tok:   token.Kind,
-	open:  token.Pos,
+	tok:   tokenizer.Token_Kind,
+	open:  tokenizer.Pos,
 	elems: []^Expr,
 	elems: []^Expr,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 Field :: struct {
 Field :: struct {
@@ -483,56 +487,57 @@ Field :: struct {
 	names:         []^Expr, // Could be polymorphic
 	names:         []^Expr, // Could be polymorphic
 	type:          ^Expr,
 	type:          ^Expr,
 	default_value: ^Expr,
 	default_value: ^Expr,
+	tag:           tokenizer.Token,
 	flags:         Field_Flags,
 	flags:         Field_Flags,
 	comment:       ^Comment_Group,
 	comment:       ^Comment_Group,
 }
 }
 
 
 Field_List :: struct {
 Field_List :: struct {
 	using node: Node,
 	using node: Node,
-	open:  token.Pos,
+	open:  tokenizer.Pos,
 	list:  []^Field,
 	list:  []^Field,
-	close: token.Pos,
+	close: tokenizer.Pos,
 }
 }
 
 
 
 
 // Types
 // Types
 Typeid_Type :: struct {
 Typeid_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:            token.Kind,
+	tok:            tokenizer.Token_Kind,
 	specialization: ^Expr,
 	specialization: ^Expr,
 }
 }
 
 
 Helper_Type :: struct {
 Helper_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:  token.Kind,
+	tok:  tokenizer.Token_Kind,
 	type: ^Expr,
 	type: ^Expr,
 }
 }
 
 
 Distinct_Type :: struct {
 Distinct_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:  token.Kind,
+	tok:  tokenizer.Token_Kind,
 	type: ^Expr,
 	type: ^Expr,
 }
 }
 
 
 Opaque_Type :: struct {
 Opaque_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:  token.Kind,
+	tok:  tokenizer.Token_Kind,
 	type: ^Expr,
 	type: ^Expr,
 }
 }
 
 
 Poly_Type :: struct {
 Poly_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	dollar:         token.Pos,
+	dollar:         tokenizer.Pos,
 	type:           ^Ident,
 	type:           ^Ident,
 	specialization: ^Expr,
 	specialization: ^Expr,
 }
 }
 
 
 Proc_Type :: struct {
 Proc_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok:       token.Token,
+	tok:       tokenizer.Token,
 	calling_convention: Proc_Calling_Convention,
 	calling_convention: Proc_Calling_Convention,
 	params:    ^Field_List,
 	params:    ^Field_List,
-	arrow:     token.Pos,
+	arrow:     tokenizer.Pos,
 	results:   ^Field_List,
 	results:   ^Field_List,
 	tags:      Proc_Tags,
 	tags:      Proc_Tags,
 	generic:   bool,
 	generic:   bool,
@@ -541,77 +546,81 @@ Proc_Type :: struct {
 
 
 Pointer_Type :: struct {
 Pointer_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	pointer: token.Pos,
+	pointer: tokenizer.Pos,
 	elem:    ^Expr,
 	elem:    ^Expr,
 }
 }
 
 
 Array_Type :: struct {
 Array_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	open:  token.Pos,
+	open:  tokenizer.Pos,
 	len:   ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
 	len:   ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
-	close: token.Pos,
+	close: tokenizer.Pos,
 	elem:  ^Expr,
 	elem:  ^Expr,
 }
 }
 
 
 Dynamic_Array_Type :: struct {
 Dynamic_Array_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	open:        token.Pos,
-	dynamic_pos: token.Pos,
-	close:       token.Pos,
+	open:        tokenizer.Pos,
+	dynamic_pos: tokenizer.Pos,
+	close:       tokenizer.Pos,
 	elem:        ^Expr,
 	elem:        ^Expr,
 }
 }
 
 
 Struct_Type :: struct {
 Struct_Type :: struct {
 	using node: Expr,
 	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 {
 Union_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok_pos:     token.Pos,
+	tok_pos:     tokenizer.Pos,
 	poly_params: ^Field_List,
 	poly_params: ^Field_List,
 	align:       ^Expr,
 	align:       ^Expr,
 	variants:    []^Expr,
 	variants:    []^Expr,
+	where_token: tokenizer.Token,
+	where_clauses: []^Expr,
 }
 }
 
 
 Enum_Type :: struct {
 Enum_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok_pos:  token.Pos,
+	tok_pos:  tokenizer.Pos,
 	base_type: ^Expr,
 	base_type: ^Expr,
-	open:      token.Pos,
+	open:      tokenizer.Pos,
 	fields:    []^Expr,
 	fields:    []^Expr,
-	close:     token.Pos,
+	close:     tokenizer.Pos,
 
 
 	is_using:  bool,
 	is_using:  bool,
 }
 }
 
 
 Bit_Field_Type :: struct {
 Bit_Field_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok_pos: token.Pos,
+	tok_pos: tokenizer.Pos,
 	align:   ^Expr,
 	align:   ^Expr,
-	open:    token.Pos,
+	open:    tokenizer.Pos,
 	fields:  []^Field_Value, // Field_Value with ':' rather than '='
 	fields:  []^Field_Value, // Field_Value with ':' rather than '='
-	close:   token.Pos,
+	close:   tokenizer.Pos,
 }
 }
 
 
 Bit_Set_Type :: struct {
 Bit_Set_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok_pos:    token.Pos,
-	open:       token.Pos,
+	tok_pos:    tokenizer.Pos,
+	open:       tokenizer.Pos,
 	elem:       ^Expr,
 	elem:       ^Expr,
 	underlying: ^Expr,
 	underlying: ^Expr,
-	close:      token.Pos,
+	close:      tokenizer.Pos,
 }
 }
 
 
 Map_Type :: struct {
 Map_Type :: struct {
 	using node: Expr,
 	using node: Expr,
-	tok_pos: token.Pos,
+	tok_pos: tokenizer.Pos,
 	key:     ^Expr,
 	key:     ^Expr,
 	value:   ^Expr,
 	value:   ^Expr,
 }
 }

+ 2 - 2
core/odin/ast/clone.odin

@@ -2,9 +2,9 @@ package odin_ast
 
 
 import "core:mem"
 import "core:mem"
 import "core:fmt"
 import "core:fmt"
-import "core:odin/token"
+import "core:odin/tokenizer"
 
 
-new :: proc($T: typeid, pos, end: token.Pos) -> ^T {
+new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
 	n := mem.new(T);
 	n := mem.new(T);
 	n.pos = pos;
 	n.pos = pos;
 	n.end = end;
 	n.end = end;

+ 2 - 2
core/odin/ast/file.odin

@@ -1,6 +1,6 @@
 package odin_ast
 package odin_ast
 
 
-import "core:odin/token"
+import "core:odin/tokenizer"
 
 
 Package_Kind :: enum {
 Package_Kind :: enum {
 	Normal,
 	Normal,
@@ -26,7 +26,7 @@ File :: struct {
 	src:      []byte,
 	src:      []byte,
 
 
 	pkg_decl:  ^Package_Decl,
 	pkg_decl:  ^Package_Decl,
-	pkg_token: token.Token,
+	pkg_token: tokenizer.Token,
 	pkg_name:  string,
 	pkg_name:  string,
 
 
 	decls:   [dynamic]^Stmt,
 	decls:   [dynamic]^Stmt,

File diff suppressed because it is too large
+ 200 - 200
core/odin/parser/parser.odin


+ 21 - 23
core/odin/token/token.odin → core/odin/tokenizer/token.odin

@@ -1,9 +1,9 @@
-package odin_token
+package odin_tokenizer
 
 
 import "core:strings"
 import "core:strings"
 
 
 Token :: struct {
 Token :: struct {
-	kind: Kind,
+	kind: Token_Kind,
 	text: string,
 	text: string,
 	pos:  Pos,
 	pos:  Pos,
 }
 }
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
 	return strings.compare(lhs.file, rhs.file);
 	return strings.compare(lhs.file, rhs.file);
 }
 }
 
 
-using Kind :: enum u32 {
+Token_Kind :: enum u32 {
 	Invalid,
 	Invalid,
 	EOF,
 	EOF,
 	Comment,
 	Comment,
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
 		Package,
 		Package,
 		Typeid,
 		Typeid,
 		When,
 		When,
+		Where,
 		If,
 		If,
 		Else,
 		Else,
 		For,
 		For,
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
 		Offset_Of,
 		Offset_Of,
 		Type_Of,
 		Type_Of,
 		Const,
 		Const,
-		Asm,
-		Yield,
-		Await,
 	B_Keyword_End,
 	B_Keyword_End,
 
 
 	COUNT,
 	COUNT,
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
 	// ... Custom keywords
 	// ... Custom keywords
 };
 };
 
 
-tokens := [Kind.COUNT]string {
+tokens := [Token_Kind.COUNT]string {
 	"Invalid",
 	"Invalid",
 	"EOF",
 	"EOF",
 	"Comment",
 	"Comment",
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
 	"package",
 	"package",
 	"typeid",
 	"typeid",
 	"when",
 	"when",
+	"where",
 	"if",
 	"if",
 	"else",
 	"else",
 	"for",
 	"for",
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
 	"offset_of",
 	"offset_of",
 	"type_of",
 	"type_of",
 	"const",
 	"const",
-	"asm",
-	"yield",
-	"await",
 	"",
 	"",
 };
 };
 
 
 custom_keyword_tokens: []string;
 custom_keyword_tokens: []string;
 
 
-to_string :: proc(kind: Kind) -> string {
-	if Invalid <= kind && kind < COUNT {
+to_string :: proc(kind: Token_Kind) -> string {
+	if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
 		return tokens[kind];
 		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) {
 		if n < len(custom_keyword_tokens) {
 			return custom_keyword_tokens[n];
 			return custom_keyword_tokens[n];
 		}
 		}
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
 	return "Invalid";
 	return "Invalid";
 }
 }
 
 
-is_literal  :: proc(kind: Kind) -> bool { return B_Literal_Begin  < kind && kind < B_Literal_End;  }
-is_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 {
 	switch kind {
-	case B_Operator_Begin..B_Operator_End:
+	case .B_Operator_Begin .. .B_Operator_End:
 		return true;
 		return true;
-	case In, Notin:
+	case .In, .Notin:
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
-is_assignment_operator :: proc(kind: Kind) -> bool {
-	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 {
 	switch {
-	case B_Keyword_Begin < kind && kind < B_Keyword_End:
+	case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
 		return true;
 		return true;
-	case B_Custom_Keyword_Begin < kind:
+	case Token_Kind.B_Custom_Keyword_Begin < kind:
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;

+ 80 - 80
core/odin/tokenizer/tokenizer.odin

@@ -1,10 +1,9 @@
 package odin_tokenizer
 package odin_tokenizer
 
 
 import "core:fmt"
 import "core:fmt"
-import "core:odin/token"
 import "core:unicode/utf8"
 import "core:unicode/utf8"
 
 
-Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any);
+Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
 
 
 Tokenizer :: struct {
 Tokenizer :: struct {
 	// Immutable data
 	// Immutable data
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
 }
 }
 
 
 @(private)
 @(private)
-offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
+offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
 	line := t.line_count;
 	line := t.line_count;
 	column := offset - t.line_offset + 1;
 	column := offset - t.line_offset + 1;
 
 
-	return token.Pos {
+	return Pos {
 		file = t.path,
 		file = t.path,
 		offset = offset,
 		offset = offset,
 		line = line,
 		line = line,
@@ -53,10 +52,10 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
 	};
 	};
 }
 }
 
 
-default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) {
-	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) {
 error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
 	return string(t.src[offset : t.offset]);
 	return string(t.src[offset : t.offset]);
 }
 }
 
 
-scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) {
+scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
 	scan_mantissa :: proc(t: ^Tokenizer, base: int) {
 	scan_mantissa :: proc(t: ^Tokenizer, base: int) {
 		for digit_val(t.ch) < base || t.ch == '_' {
 		for digit_val(t.ch) < base || t.ch == '_' {
 			advance_rune(t);
 			advance_rune(t);
 		}
 		}
 	}
 	}
-	scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) {
+	scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) {
 		if t.ch == 'e' || t.ch == 'E' {
 		if t.ch == 'e' || t.ch == 'E' {
-			kind^ = token.Float;
+			kind^ = .Float;
 			advance_rune(t);
 			advance_rune(t);
 			if t.ch == '-' || t.ch == '+' {
 			if t.ch == '-' || t.ch == '+' {
 				advance_rune(t);
 				advance_rune(t);
@@ -343,17 +342,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
 		}
 		}
 
 
 		// NOTE(bill): This needs to be here for sanity's sake
 		// NOTE(bill): This needs to be here for sanity's sake
-		if t.ch == 'i' {
-			kind^ = token.Imag;
+		switch t.ch {
+		case 'i', 'j', 'k':
+			kind^ = .Imag;
 			advance_rune(t);
 			advance_rune(t);
 		}
 		}
 	}
 	}
-	scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) {
+	scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
 		if t.ch == '.' && peek_byte(t) == '.' {
 		if t.ch == '.' && peek_byte(t) == '.' {
 			return true;
 			return true;
 		}
 		}
 		if t.ch == '.' {
 		if t.ch == '.' {
-			kind^ = token.Float;
+			kind^ = .Float;
 			advance_rune(t);
 			advance_rune(t);
 			scan_mantissa(t, 10);
 			scan_mantissa(t, 10);
 		}
 		}
@@ -362,22 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
 
 
 
 
 	offset := t.offset;
 	offset := t.offset;
-	kind := token.Integer;
+	kind := Token_Kind.Integer;
 	seen_point := seen_decimal_point;
 	seen_point := seen_decimal_point;
 
 
 	if seen_point {
 	if seen_point {
 		offset -= 1;
 		offset -= 1;
-		kind = token.Float;
+		kind = .Float;
 		scan_mantissa(t, 10);
 		scan_mantissa(t, 10);
 		scan_exponent(t, &kind);
 		scan_exponent(t, &kind);
 	} else {
 	} else {
 		if t.ch == '0' {
 		if t.ch == '0' {
-			int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) {
+			int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) {
 				prev := t.offset;
 				prev := t.offset;
 				advance_rune(t);
 				advance_rune(t);
 				scan_mantissa(t, base);
 				scan_mantissa(t, base);
 				if t.offset - prev <= 1 {
 				if t.offset - prev <= 1 {
-					kind^ = token.Invalid;
+					kind^ = .Invalid;
 					error(t, t.offset, msg);
 					error(t, t.offset, msg);
 				}
 				}
 			}
 			}
@@ -394,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
 				advance_rune(t);
 				advance_rune(t);
 				scan_mantissa(t, 16);
 				scan_mantissa(t, 16);
 				if t.offset - prev <= 1 {
 				if t.offset - prev <= 1 {
-					kind = token.Invalid;
+					kind = .Invalid;
 					error(t, t.offset, "illegal hexadecimal floating-point number");
 					error(t, t.offset, "illegal hexadecimal floating-point number");
 				} else {
 				} else {
 					sub := t.src[prev+1 : t.offset];
 					sub := t.src[prev+1 : t.offset];
@@ -439,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
 }
 }
 
 
 
 
-scan :: proc(t: ^Tokenizer) -> token.Token {
-	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 == '=' {
 		if t.ch == '=' {
 			advance_rune(t);
 			advance_rune(t);
 			return tok1;
 			return tok1;
 		}
 		}
 		return tok0;
 		return tok0;
 	}
 	}
-	switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind {
+	switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind {
 		if t.ch == '=' {
 		if t.ch == '=' {
 			advance_rune(t);
 			advance_rune(t);
 			return tok1;
 			return tok1;
@@ -458,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
 		}
 		}
 		return tok0;
 		return tok0;
 	}
 	}
-	switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind {
+	switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
 		if t.ch == '=' {
 		if t.ch == '=' {
 			advance_rune(t);
 			advance_rune(t);
 			return tok1;
 			return tok1;
@@ -479,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
 
 
 	offset := t.offset;
 	offset := t.offset;
 
 
-	kind: token.Kind;
+	kind: Token_Kind;
 	lit:  string;
 	lit:  string;
 	pos := offset_to_pos(t, offset);
 	pos := offset_to_pos(t, offset);
 
 
 	switch ch := t.ch; true {
 	switch ch := t.ch; true {
 	case is_letter(ch):
 	case is_letter(ch):
 		lit = scan_identifier(t);
 		lit = scan_identifier(t);
-		kind = token.Ident;
+		kind = .Ident;
 		check_keyword: if len(lit) > 1 {
 		check_keyword: if len(lit) > 1 {
 			// TODO(bill): Maybe have a hash table lookup rather than this linear search
 			// TODO(bill): Maybe have a hash table lookup rather than this linear search
-			for i in token.B_Keyword_Begin .. token.B_Keyword_End {
-				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;
 					break check_keyword;
 				}
 				}
 			}
 			}
-			for keyword, i in token.custom_keyword_tokens {
+			for keyword, i in custom_keyword_tokens {
 				if lit == keyword {
 				if lit == keyword {
-					kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin;
+					kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
 					break check_keyword;
 					break check_keyword;
 				}
 				}
 			}
 			}
@@ -508,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
 		advance_rune(t);
 		advance_rune(t);
 		switch ch {
 		switch ch {
 		case -1:
 		case -1:
-			kind = token.EOF;
+			kind = .EOF;
 		case '"':
 		case '"':
-			kind = token.String;
+			kind = .String;
 			lit = scan_string(t);
 			lit = scan_string(t);
 		case '\'':
 		case '\'':
-			kind = token.Rune;
+			kind = .Rune;
 			lit = scan_rune(t);
 			lit = scan_rune(t);
 		case '`':
 		case '`':
-			kind = token.String;
+			kind = .String;
 			lit = scan_raw_string(t);
 			lit = scan_raw_string(t);
 		case '=':
 		case '=':
 			if t.ch == '>' {
 			if t.ch == '>' {
 				advance_rune(t);
 				advance_rune(t);
-				kind = token.Double_Arrow_Right;
+				kind = .Double_Arrow_Right;
 			} else {
 			} else {
-				kind = switch2(t, token.Eq, token.Cmp_Eq);
+				kind = switch2(t, .Eq, .Cmp_Eq);
 			}
 			}
-		case '!': kind = switch2(t, token.Not, token.Not_Eq);
+		case '!': kind = switch2(t, .Not, .Not_Eq);
 		case '#':
 		case '#':
-			kind = token.Hash;
+			kind = .Hash;
 			if t.ch == '!' {
 			if t.ch == '!' {
-				kind = token.Comment;
+				kind = .Comment;
 				lit = scan_comment(t);
 				lit = scan_comment(t);
 			}
 			}
-		case '?': kind = token.Question;
-		case '@': kind = 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 '-':
 		case '-':
 			if t.ch == '>' {
 			if t.ch == '>' {
 				advance_rune(t);
 				advance_rune(t);
-				kind = token.Arrow_Right;
+				kind = .Arrow_Right;
 			} else if t.ch == '-' && peek_byte(t) == '-' {
 			} else if t.ch == '-' && peek_byte(t) == '-' {
 				advance_rune(t);
 				advance_rune(t);
 				advance_rune(t);
 				advance_rune(t);
-				kind = token.Undef;
+				kind = .Undef;
 			} else {
 			} else {
-				kind = switch2(t, token.Sub, token.Sub_Eq);
+				kind = switch2(t, .Sub, .Sub_Eq);
 			}
 			}
-		case '*': kind = switch2(t, token.Mul, token.Mul_Eq);
+		case '*': kind = switch2(t, .Mul, .Mul_Eq);
 		case '/':
 		case '/':
 			if t.ch == '/' || t.ch == '*' {
 			if t.ch == '/' || t.ch == '*' {
-				kind = token.Comment;
+				kind = .Comment;
 				lit = scan_comment(t);
 				lit = scan_comment(t);
 			} else {
 			} else {
-				kind = switch2(t, token.Quo, token.Quo_Eq);
+				kind = switch2(t, .Quo, .Quo_Eq);
 			}
 			}
-		case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq);
+		case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
 		case '&':
 		case '&':
 			if t.ch == '~' {
 			if t.ch == '~' {
 				advance_rune(t);
 				advance_rune(t);
-				kind = switch2(t, token.And_Not, token.And_Not_Eq);
+				kind = switch2(t, .And_Not, .And_Not_Eq);
 			} else {
 			} else {
-				kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And);
+				kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
 			}
 			}
-		case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or);
-		case '~': kind = token.Xor;
+		case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
+		case '~': kind = .Xor;
 		case '<':
 		case '<':
 			if t.ch == '-' {
 			if t.ch == '-' {
 				advance_rune(t);
 				advance_rune(t);
-				kind = token.Arrow_Left;
+				kind = .Arrow_Left;
 			} else {
 			} else {
-				kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq);
+				kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
 			}
 			}
-		case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq);
+		case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
 
 
-		case '≠': kind = token.Not_Eq;
-		case '≤': kind = 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 '.':
 		case '.':
 			if '0' <= t.ch && t.ch <= '9' {
 			if '0' <= t.ch && t.ch <= '9' {
 				kind, lit = scan_number(t, true);
 				kind, lit = scan_number(t, true);
 			} else {
 			} else {
-				kind = token.Period;
+				kind = .Period;
 				if t.ch == '.' {
 				if t.ch == '.' {
 					advance_rune(t);
 					advance_rune(t);
-					kind = token.Ellipsis;
+					kind = .Ellipsis;
 					if t.ch == '<' {
 					if t.ch == '<' {
 						advance_rune(t);
 						advance_rune(t);
-						kind = token.Range_Half;
+						kind = .Range_Half;
 					}
 					}
 				}
 				}
 			}
 			}
-		case ':': kind = token.Colon;
-		case ',': kind = 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:
 		case:
 			if ch != utf8.RUNE_BOM {
 			if ch != utf8.RUNE_BOM {
 				error(t, t.offset, "illegal character '%r': %d", ch, ch);
 				error(t, t.offset, "illegal character '%r': %d", ch, ch);
 			}
 			}
-			kind = token.Invalid;
+			kind = .Invalid;
 		}
 		}
 	}
 	}
 
 
 	if lit == "" {
 	if lit == "" {
 		lit = string(t.src[offset : t.offset]);
 		lit = string(t.src[offset : t.offset]);
 	}
 	}
-	return token.Token{kind, lit, pos};
+	return Token{kind, lit, pos};
 }
 }

+ 4 - 4
core/os/os_osx.odin → core/os/os_darwin.odin

@@ -6,7 +6,7 @@ foreign import libc "system:c"
 import "core:runtime"
 import "core:runtime"
 import "core:strings"
 import "core:strings"
 
 
-OS :: "osx";
+OS :: "darwin";
 
 
 Handle    :: distinct i32;
 Handle    :: distinct i32;
 File_Time :: distinct u64;
 File_Time :: distinct u64;
@@ -319,9 +319,9 @@ dlerror :: proc() -> string {
 
 
 
 
 _alloc_command_line_arguments :: proc() -> []string {
 _alloc_command_line_arguments :: proc() -> []string {
-	args := make([]string, len(runtime.args__));
+	res := make([]string, len(runtime.args__));
 	for arg, i in runtime.args__ {
 	for arg, i in runtime.args__ {
-		args[i] = string(arg);
+		res[i] = string(arg);
 	}
 	}
-	return args;
+	return res;
 }
 }

+ 2402 - 142
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) {
 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";

+ 3 - 3
core/os/os_linux.odin

@@ -392,9 +392,9 @@ dlerror :: proc() -> string {
 
 
 
 
 _alloc_command_line_arguments :: proc() -> []string {
 _alloc_command_line_arguments :: proc() -> []string {
-	args := make([]string, len(runtime.args__));
+	res := make([]string, len(runtime.args__));
 	for arg, i in runtime.args__ {
 	for arg, i in runtime.args__ {
-		args[i] = string(arg);
+		res[i] = string(arg);
 	}
 	}
-	return args;
+	return res;
 }
 }

+ 1 - 1
core/os/os_windows.odin

@@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool {
 is_windows_10 :: proc() -> bool {
 is_windows_10 :: proc() -> bool {
 	osvi := get_windows_version_ansi();
 	osvi := get_windows_version_ansi();
 	return (osvi.major_version == 10 && osvi.minor_version == 0);
 	return (osvi.major_version == 10 && osvi.minor_version == 0);
-}
+}

+ 396 - 0
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;
+}

+ 217 - 1
core/types/types.odin → core/reflect/types.odin

@@ -1,6 +1,7 @@
-package types
+package reflect
 
 
 import rt "core:runtime"
 import rt "core:runtime"
+import "core:strings"
 
 
 are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 	if a == b do return true;
 	if a == b do return true;
@@ -108,9 +109,11 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 		for _, i in x.types {
 		for _, i in x.types {
 			xn, yn := x.names[i], y.names[i];
 			xn, yn := x.names[i], y.names[i];
 			xt, yt := x.types[i], y.types[i];
 			xt, yt := x.types[i], y.types[i];
+			xl, yl := x.tags[i],  y.tags[i];
 
 
 			if xn != yn do return false;
 			if xn != yn do return false;
 			if !are_types_identical(xt, yt) do return false;
 			if !are_types_identical(xt, yt) do return false;
+			if xl != yl do return false;
 		}
 		}
 		return true;
 		return true;
 
 
@@ -272,3 +275,216 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
 	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
 	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
 	return ok;
 	return ok;
 }
 }
+
+
+
+
+
+
+write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
+	write_type(buf, type_info_of(id));
+}
+
+write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
+	using strings;
+	if ti == nil {
+		write_string(buf, "nil");
+		return;
+	}
+
+	switch info in ti.variant {
+	case rt.Type_Info_Named:
+		write_string(buf, info.name);
+	case rt.Type_Info_Integer:
+		switch ti.id {
+		case int:     write_string(buf, "int");
+		case uint:    write_string(buf, "uint");
+		case uintptr: write_string(buf, "uintptr");
+		case:
+			write_byte(buf, info.signed ? 'i' : 'u');
+			write_i64(buf, i64(8*ti.size), 10);
+			switch info.endianness {
+			case .Little: write_string(buf, "le");
+			case .Big:    write_string(buf, "be");
+			}
+		}
+	case rt.Type_Info_Rune:
+		write_string(buf, "rune");
+	case rt.Type_Info_Float:
+		write_byte(buf, 'f');
+		write_i64(buf, i64(8*ti.size), 10);
+	case rt.Type_Info_Complex:
+		write_string(buf, "complex");
+		write_i64(buf, i64(8*ti.size), 10);
+	case rt.Type_Info_String:
+		if info.is_cstring {
+			write_string(buf, "cstring");
+		} else {
+			write_string(buf, "string");
+		}
+	case rt.Type_Info_Boolean:
+		switch ti.id {
+		case bool: write_string(buf, "bool");
+		case:
+			write_byte(buf, 'b');
+			write_i64(buf, i64(8*ti.size), 10);
+		}
+	case rt.Type_Info_Any:
+		write_string(buf, "any");
+
+	case rt.Type_Info_Type_Id:
+		write_string(buf, "typeid");
+
+	case rt.Type_Info_Pointer:
+		if info.elem == nil {
+			write_string(buf, "rawptr");
+		} else {
+			write_string(buf, "^");
+			write_type(buf, info.elem);
+		}
+	case rt.Type_Info_Procedure:
+		write_string(buf, "proc");
+		if info.params == nil {
+			write_string(buf, "()");
+		} else {
+			t := info.params.variant.(rt.Type_Info_Tuple);
+			write_string(buf, "(");
+			for t, i in t.types {
+				if i > 0 do write_string(buf, ", ");
+				write_type(buf, t);
+			}
+			write_string(buf, ")");
+		}
+		if info.results != nil {
+			write_string(buf, " -> ");
+			write_type(buf, info.results);
+		}
+	case rt.Type_Info_Tuple:
+		count := len(info.names);
+		if count != 1 do write_string(buf, "(");
+		for name, i in info.names {
+			if i > 0 do write_string(buf, ", ");
+
+			t := info.types[i];
+
+			if len(name) > 0 {
+				write_string(buf, name);
+				write_string(buf, ": ");
+			}
+			write_type(buf, t);
+		}
+		if count != 1 do write_string(buf, ")");
+
+	case rt.Type_Info_Array:
+		write_string(buf, "[");
+		write_i64(buf, i64(info.count), 10);
+		write_string(buf, "]");
+		write_type(buf, info.elem);
+	case rt.Type_Info_Dynamic_Array:
+		write_string(buf, "[dynamic]");
+		write_type(buf, info.elem);
+	case rt.Type_Info_Slice:
+		write_string(buf, "[]");
+		write_type(buf, info.elem);
+
+	case rt.Type_Info_Map:
+		write_string(buf, "map[");
+		write_type(buf, info.key);
+		write_byte(buf, ']');
+		write_type(buf, info.value);
+
+	case rt.Type_Info_Struct:
+		write_string(buf, "struct ");
+		if info.is_packed    do write_string(buf, "#packed ");
+		if info.is_raw_union do write_string(buf, "#raw_union ");
+		if info.custom_align {
+			write_string(buf, "#align ");
+			write_i64(buf, i64(ti.align), 10);
+			write_byte(buf, ' ');
+		}
+		write_byte(buf, '{');
+		for name, i in info.names {
+			if i > 0 do write_string(buf, ", ");
+			write_string(buf, name);
+			write_string(buf, ": ");
+			write_type(buf, info.types[i]);
+		}
+		write_byte(buf, '}');
+
+	case rt.Type_Info_Union:
+		write_string(buf, "union ");
+		if info.custom_align {
+			write_string(buf, "#align ");
+			write_i64(buf, i64(ti.align), 10);
+			write_byte(buf, ' ');
+		}
+		write_byte(buf, '{');
+		for variant, i in info.variants {
+			if i > 0 do write_string(buf, ", ");
+			write_type(buf, variant);
+		}
+		write_byte(buf, '}');
+
+	case rt.Type_Info_Enum:
+		write_string(buf, "enum ");
+		write_type(buf, info.base);
+		write_string(buf, " {");
+		for name, i in info.names {
+			if i > 0 do write_string(buf, ", ");
+			write_string(buf, name);
+		}
+		write_byte(buf, '}');
+
+	case rt.Type_Info_Bit_Field:
+		write_string(buf, "bit_field ");
+		if ti.align != 1 {
+			write_string(buf, "#align ");
+			write_i64(buf, i64(ti.align), 10);
+			write_byte(buf, ' ');
+		}
+		write_string(buf, " {");
+		for name, i in info.names {
+			if i > 0 do write_string(buf, ", ");
+			write_string(buf, name);
+			write_string(buf, ": ");
+			write_i64(buf, i64(info.bits[i]), 10);
+		}
+		write_byte(buf, '}');
+
+	case rt.Type_Info_Bit_Set:
+		write_string(buf, "bit_set[");
+		switch {
+		case is_enum(info.elem):
+			write_type(buf, info.elem);
+		case is_rune(info.elem):
+			write_encoded_rune(buf, rune(info.lower));
+			write_string(buf, "..");
+			write_encoded_rune(buf, rune(info.upper));
+		case:
+			write_i64(buf, info.lower, 10);
+			write_string(buf, "..");
+			write_i64(buf, info.upper, 10);
+		}
+		if info.underlying != nil {
+			write_string(buf, "; ");
+			write_type(buf, info.underlying);
+		}
+		write_byte(buf, ']');
+
+	case rt.Type_Info_Opaque:
+		write_string(buf, "opaque ");
+		write_type(buf, info.elem);
+
+	case rt.Type_Info_Simd_Vector:
+		if info.is_x86_mmx {
+			write_string(buf, "intrinsics.x86_mmx");
+		} else {
+			write_string(buf, "intrinsics.vector(");
+			write_i64(buf, i64(info.count));
+			write_string(buf, ", ");
+			write_type(buf, info.elem);
+			write_byte(buf, ')');
+		}
+	}
+}
+

+ 98 - 75
core/runtime/core.odin

@@ -6,6 +6,7 @@ package runtime
 import "core:os"
 import "core:os"
 import "core:mem"
 import "core:mem"
 import "core:log"
 import "core:log"
+import "intrinsics"
 
 
 // Naming Conventions:
 // Naming Conventions:
 // In general, Ada_Case for types and snake_case for values
 // In general, Ada_Case for types and snake_case for values
@@ -40,23 +41,24 @@ Type_Info_Enum_Value :: union {
 	u8, u16, u32, u64, uint, uintptr,
 	u8, u16, u32, u64, uint, uintptr,
 };
 };
 
 
-Type_Info_Endianness :: enum u8 {
+Platform_Endianness :: enum u8 {
 	Platform = 0,
 	Platform = 0,
 	Little   = 1,
 	Little   = 1,
 	Big      = 2,
 	Big      = 2,
 }
 }
 
 
 // Variant Types
 // 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
 	elem: ^Type_Info // nil -> rawptr
 };
 };
 Type_Info_Procedure :: struct {
 Type_Info_Procedure :: struct {
@@ -79,8 +81,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
 Type_Info_Struct :: struct {
 Type_Info_Struct :: struct {
 	types:        []^Type_Info,
 	types:        []^Type_Info,
 	names:        []string,
 	names:        []string,
-	offsets:      []uintptr, // offsets may not be used in tuples
-	usings:       []bool,    // usings may not be used in tuples
+	offsets:      []uintptr,
+	usings:       []bool,
+	tags:         []string,
 	is_packed:    bool,
 	is_packed:    bool,
 	is_raw_union: bool,
 	is_raw_union: bool,
 	custom_align: bool,
 	custom_align: bool,
@@ -134,6 +137,7 @@ Type_Info :: struct {
 		Type_Info_Rune,
 		Type_Info_Rune,
 		Type_Info_Float,
 		Type_Info_Float,
 		Type_Info_Complex,
 		Type_Info_Complex,
+		Type_Info_Quaternion,
 		Type_Info_String,
 		Type_Info_String,
 		Type_Info_Boolean,
 		Type_Info_Boolean,
 		Type_Info_Any,
 		Type_Info_Any,
@@ -162,6 +166,7 @@ Typeid_Kind :: enum u8 {
 	Rune,
 	Rune,
 	Float,
 	Float,
 	Complex,
 	Complex,
+	Quaternion,
 	String,
 	String,
 	Boolean,
 	Boolean,
 	Any,
 	Any,
@@ -183,12 +188,13 @@ Typeid_Kind :: enum u8 {
 #assert(len(Typeid_Kind) < 32);
 #assert(len(Typeid_Kind) < 32);
 
 
 Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
 Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
-	index:    8*size_of(align_of(uintptr)) - 8,
+	index:    8*size_of(uintptr) - 8,
 	kind:     5, // Typeid_Kind
 	kind:     5, // Typeid_Kind
 	named:    1,
 	named:    1,
 	special:  1, // signed, cstring, etc
 	special:  1, // signed, cstring, etc
 	reserved: 1,
 	reserved: 1,
 }
 }
+#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
 
 
 // NOTE(bill): only the ones that are needed (not all types)
 // NOTE(bill): only the ones that are needed (not all types)
 // This will be set by the compiler
 // This will be set by the compiler
@@ -231,7 +237,22 @@ global_scratch_allocator_data: mem.Scratch_Allocator;
 
 
 
 
 
 
+Raw_Slice :: struct {
+	data: rawptr,
+	len:  int,
+}
+
+Raw_Dynamic_Array :: struct {
+	data:      rawptr,
+	len:       int,
+	cap:       int,
+	allocator: mem.Allocator,
+}
 
 
+Raw_Map :: struct {
+	hashes:  []int,
+	entries: Raw_Dynamic_Array,
+}
 
 
 INITIAL_MAP_CAP :: 16;
 INITIAL_MAP_CAP :: 16;
 
 
@@ -255,7 +276,7 @@ Map_Entry_Header :: struct {
 }
 }
 
 
 Map_Header :: struct {
 Map_Header :: struct {
-	m:             ^mem.Raw_Map,
+	m:             ^Raw_Map,
 	is_key_string: bool,
 	is_key_string: bool,
 
 
 	entry_size:    int,
 	entry_size:    int,
@@ -282,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;
 	if info == nil do return nil;
 
 
 	base := info;
 	base := info;
 	loop: for {
 	loop: for {
 		switch i in base.variant {
 		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;
 		case: break loop;
 		}
 		}
 	}
 	}
 	return base;
 	return base;
 }
 }
+type_info_base_without_enum :: type_info_core;
 
 
 __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
 __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
 	data := transmute(Typeid_Bit_Field)id;
 	data := transmute(Typeid_Bit_Field)id;
@@ -310,10 +333,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
 	ti = type_info_base(ti);
 	ti = type_info_base(ti);
 	return ti.id;
 	return ti.id;
 }
 }
-typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
+typeid_core :: proc "contextless" (id: typeid) -> typeid {
 	ti := type_info_base_without_enum(type_info_of(id));
 	ti := type_info_base_without_enum(type_info_of(id));
 	return ti.id;
 	return ti.id;
 }
 }
+typeid_base_without_enum :: typeid_core;
 
 
 
 
 
 
@@ -385,7 +409,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
 @builtin
 @builtin
 copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
 copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
 	n := max(0, min(len(dst), len(src)));
 	n := max(0, min(len(dst), len(src)));
-	if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
+	if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
 	return n;
 	return n;
 }
 }
 
 
@@ -396,7 +420,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
 	if array == nil do return E{};
 	if array == nil do return E{};
 	assert(len(array) > 0);
 	assert(len(array) > 0);
 	res := array[len(array)-1];
 	res := array[len(array)-1];
-	(^mem.Raw_Dynamic_Array)(array).len -= 1;
+	(^Raw_Dynamic_Array)(array).len -= 1;
 	return res;
 	return res;
 }
 }
 
 
@@ -460,14 +484,11 @@ make :: proc{
 	mem.make_map,
 	mem.make_map,
 };
 };
 
 
-
-
-
 @builtin
 @builtin
 clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
 clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
 	if m == nil do return;
 	if m == nil do return;
-	raw_map := (^mem.Raw_Map)(m);
-	entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
+	raw_map := (^Raw_Map)(m);
+	entries := (^Raw_Dynamic_Array)(&raw_map.entries);
 	entries.len = 0;
 	entries.len = 0;
 	for _, i in raw_map.hashes {
 	for _, i in raw_map.hashes {
 		raw_map.hashes[i] = -1;
 		raw_map.hashes[i] = -1;
@@ -498,11 +519,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location)  {
 	}
 	}
 	arg_len = min(cap(array)-len(array), arg_len);
 	arg_len = min(cap(array)-len(array), arg_len);
 	if arg_len > 0 {
 	if arg_len > 0 {
-		a := (^mem.Raw_Dynamic_Array)(array);
+		a := (^Raw_Dynamic_Array)(array);
 		data := (^E)(a.data);
 		data := (^E)(a.data);
 		assert(data != nil);
 		assert(data != nil);
 		val := arg;
 		val := arg;
-		mem.copy(mem.ptr_offset(data, a.len), &val, size_of(E));
+		mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E));
 		a.len += arg_len;
 		a.len += arg_len;
 	}
 	}
 }
 }
@@ -520,10 +541,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
 	}
 	}
 	arg_len = min(cap(array)-len(array), arg_len);
 	arg_len = min(cap(array)-len(array), arg_len);
 	if arg_len > 0 {
 	if arg_len > 0 {
-		a := (^mem.Raw_Dynamic_Array)(array);
+		a := (^Raw_Dynamic_Array)(array);
 		data := (^E)(a.data);
 		data := (^E)(a.data);
 		assert(data != nil);
 		assert(data != nil);
-		mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
+		mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
 		a.len += arg_len;
 		a.len += arg_len;
 	}
 	}
 }
 }
@@ -540,13 +561,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
 
 
 @builtin
 @builtin
 clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
 clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
-	if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
+	if array != nil do (^Raw_Dynamic_Array)(array).len = 0;
 }
 }
 
 
 @builtin
 @builtin
 reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
 reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
 	if array == nil do return false;
 	if array == nil do return false;
-	a := (^mem.Raw_Dynamic_Array)(array);
+	a := (^Raw_Dynamic_Array)(array);
 
 
 	if capacity <= a.cap do return true;
 	if capacity <= a.cap do return true;
 
 
@@ -573,7 +594,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
 @builtin
 @builtin
 resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
 resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
 	if array == nil do return false;
 	if array == nil do return false;
-	a := (^mem.Raw_Dynamic_Array)(array);
+	a := (^Raw_Dynamic_Array)(array);
 
 
 	if length <= a.cap {
 	if length <= a.cap {
 		a.len = max(length, 0);
 		a.len = max(length, 0);
@@ -666,11 +687,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
 @builtin
 @builtin
 assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
 assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
 	if !condition {
 	if !condition {
-		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;
 	return condition;
 }
 }
@@ -681,7 +704,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
 	if p == nil {
 	if p == nil {
 		p = default_assertion_failure_proc;
 		p = default_assertion_failure_proc;
 	}
 	}
-	p("Panic", message, loc);
+	p("panic", message, loc);
 }
 }
 
 
 @builtin
 @builtin
@@ -711,7 +734,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! {
 
 
 
 
 __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
 __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
-	array := (^mem.Raw_Dynamic_Array)(array_);
+	array := (^Raw_Dynamic_Array)(array_);
 	array.allocator = context.allocator;
 	array.allocator = context.allocator;
 	assert(array.allocator.procedure != nil);
 	assert(array.allocator.procedure != nil);
 
 
@@ -722,7 +745,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca
 }
 }
 
 
 __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
 __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
-	array := (^mem.Raw_Dynamic_Array)(array_);
+	array := (^Raw_Dynamic_Array)(array_);
 
 
 	if cap <= array.cap do return true;
 	if cap <= array.cap do return true;
 
 
@@ -744,7 +767,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
 }
 }
 
 
 __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
 __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
-	array := (^mem.Raw_Dynamic_Array)(array_);
+	array := (^Raw_Dynamic_Array)(array_);
 
 
 	ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
 	ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
 	if ok do array.len = len;
 	if ok do array.len = len;
@@ -754,7 +777,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
 
 
 __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
 __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
                                items: rawptr, item_count: int, loc := #caller_location) -> int {
                                items: rawptr, item_count: int, loc := #caller_location) -> int {
-	array := (^mem.Raw_Dynamic_Array)(array_);
+	array := (^Raw_Dynamic_Array)(array_);
 
 
 	if items == nil    do return 0;
 	if items == nil    do return 0;
 	if item_count <= 0 do return 0;
 	if item_count <= 0 do return 0;
@@ -771,13 +794,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
 	assert(array.data != nil);
 	assert(array.data != nil);
 	data := uintptr(array.data) + uintptr(elem_size*array.len);
 	data := uintptr(array.data) + uintptr(elem_size*array.len);
 
 
-	mem.copy(rawptr(data), items, elem_size * item_count);
+	mem_copy(rawptr(data), items, elem_size * item_count);
 	array.len += item_count;
 	array.len += item_count;
 	return array.len;
 	return array.len;
 }
 }
 
 
 __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
 __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
-	array := (^mem.Raw_Dynamic_Array)(array_);
+	array := (^Raw_Dynamic_Array)(array_);
 
 
 	ok := true;
 	ok := true;
 	if array.cap <= array.len+1 {
 	if array.cap <= array.len+1 {
@@ -800,15 +823,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
 // Map
 // Map
 
 
 __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
 __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
-	header := Map_Header{m = (^mem.Raw_Map)(m)};
+	header := Map_Header{m = (^Raw_Map)(m)};
 	Entry :: struct {
 	Entry :: struct {
 		key:   Map_Key,
 		key:   Map_Key,
 		next:  int,
 		next:  int,
 		value: V,
 		value: V,
-	}
+	};
 
 
-	_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
-	header.is_key_string = is_string;
+	header.is_key_string = intrinsics.type_is_string(K);
 	header.entry_size    = int(size_of(Entry));
 	header.entry_size    = int(size_of(Entry));
 	header.entry_align   = int(align_of(Entry));
 	header.entry_align   = int(align_of(Entry));
 	header.value_offset  = uintptr(offset_of(Entry, value));
 	header.value_offset  = uintptr(offset_of(Entry, value));
@@ -819,33 +841,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
 __get_map_key :: proc "contextless" (k: $K) -> Map_Key {
 __get_map_key :: proc "contextless" (k: $K) -> Map_Key {
 	key := k;
 	key := k;
 	map_key: Map_Key;
 	map_key: Map_Key;
-	ti := type_info_base_without_enum(type_info_of(K));
-	switch _ in ti.variant {
-	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)^);
 		map_key.hash = u64((^rune)(&key)^);
-	case Type_Info_Pointer:
+	} else when intrinsics.type_is_pointer(T) {
 		map_key.hash = u64(uintptr((^rawptr)(&key)^));
 		map_key.hash = u64(uintptr((^rawptr)(&key)^));
-	case Type_Info_Float:
-		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)^;
 		str := (^string)(&key)^;
 		map_key.hash = default_hash_string(str);
 		map_key.hash = default_hash_string(str);
 		map_key.str  = str;
 		map_key.str  = str;
-	case:
-		panic("Unhandled map key type");
+	} else {
+		#assert(false, "Unhandled map key type");
 	}
 	}
+
 	return map_key;
 	return map_key;
 }
 }
 
 
@@ -874,7 +897,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
 
 
 
 
 __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
 __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
-	array := (^mem.Raw_Slice)(array_);
+	array := (^Raw_Slice)(array_);
 
 
 	if new_count < array.len do return true;
 	if new_count < array.len do return true;
 
 
@@ -900,7 +923,7 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller
 }
 }
 __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
 __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
 	new_header: Map_Header = header;
 	new_header: Map_Header = header;
-	nm := mem.Raw_Map{};
+	nm := Raw_Map{};
 	nm.entries.allocator = m.entries.allocator;
 	nm.entries.allocator = m.entries.allocator;
 	new_header.m = &nm;
 	new_header.m = &nm;
 
 
@@ -932,7 +955,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c
 		e := __dynamic_map_get_entry(new_header, j);
 		e := __dynamic_map_get_entry(new_header, j);
 		e.next = fr.entry_index;
 		e.next = fr.entry_index;
 		ndata := uintptr(e);
 		ndata := uintptr(e);
-		mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
+		mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
 
 
 		if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
 		if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
 	}
 	}
@@ -975,7 +998,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca
 		e := __dynamic_map_get_entry(h, index);
 		e := __dynamic_map_get_entry(h, index);
 		e.key = key;
 		e.key = key;
 		val := (^byte)(uintptr(e) + h.value_offset);
 		val := (^byte)(uintptr(e) + h.value_offset);
-		mem.copy(val, value, h.value_size);
+		mem_copy(val, value, h.value_size);
 	}
 	}
 
 
 	if __dynamic_map_full(h) {
 	if __dynamic_map_full(h) {
@@ -1054,7 +1077,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
 	} else {
 	} else {
 		old := __dynamic_map_get_entry(h, fr.entry_index);
 		old := __dynamic_map_get_entry(h, fr.entry_index);
 		end := __dynamic_map_get_entry(h, m.entries.len-1);
 		end := __dynamic_map_get_entry(h, m.entries.len-1);
-		mem.copy(old, end, entry_size);
+		mem_copy(old, end, entry_size);
 
 
 		if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
 		if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
 			last_entry := __dynamic_map_get_entry(h, last.entry_prev);
 			last_entry := __dynamic_map_get_entry(h, last.entry_prev);

+ 242 - 12
core/runtime/internal.odin

@@ -1,9 +1,22 @@
 package runtime
 package runtime
 
 
-import "core:mem"
 import "core:os"
 import "core:os"
-import "core:unicode/utf8"
 
 
+mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
+	if src == nil do return dst;
+	// NOTE(bill): This _must_ be implemented like C's memmove
+	foreign _ {
+		when size_of(rawptr) == 8 {
+			@(link_name="llvm.memmove.p0i8.p0i8.i64")
+			llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
+		} else {
+			@(link_name="llvm.memmove.p0i8.p0i8.i32")
+			llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
+		}
+	}
+	llvm_memmove(dst, src, len, 1, false);
+	return dst;
+}
 
 
 print_u64 :: proc(fd: os.Handle, x: u64) {
 print_u64 :: proc(fd: os.Handle, x: u64) {
 	digits := "0123456789";
 	digits := "0123456789";
@@ -243,6 +256,78 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
 	}
 	}
 }
 }
 
 
+memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
+	x := uintptr(a);
+	y := uintptr(b);
+	n := uintptr(n);
+
+	SU :: size_of(uintptr);
+	fast := uintptr(n/SU + 1);
+	offset := (fast-1)*SU;
+	curr_block := uintptr(0);
+	if n < SU {
+		fast = 0;
+	}
+
+	for /**/; curr_block < fast; curr_block += 1 {
+		va := (^uintptr)(x + curr_block * size_of(uintptr))^;
+		vb := (^uintptr)(y + curr_block * size_of(uintptr))^;
+		if va ~ vb != 0 {
+			for pos := curr_block*SU; pos < n; pos += 1 {
+				a := (^byte)(x+pos)^;
+				b := (^byte)(y+pos)^;
+				if a ~ b != 0 {
+					return (int(a) - int(b)) < 0 ? -1 : +1;
+				}
+			}
+		}
+	}
+
+	for /**/; offset < n; offset += 1 {
+		a := (^byte)(x+offset)^;
+		b := (^byte)(y+offset)^;
+		if a ~ b != 0 {
+			return (int(a) - int(b)) < 0 ? -1 : +1;
+		}
+	}
+
+	return 0;
+}
+
+memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
+	x := uintptr(a);
+	n := uintptr(n);
+
+	SU :: size_of(uintptr);
+	fast := uintptr(n/SU + 1);
+	offset := (fast-1)*SU;
+	curr_block := uintptr(0);
+	if n < SU {
+		fast = 0;
+	}
+
+	for /**/; curr_block < fast; curr_block += 1 {
+		va := (^uintptr)(x + curr_block * size_of(uintptr))^;
+		if va ~ 0 != 0 {
+			for pos := curr_block*SU; pos < n; pos += 1 {
+				a := (^byte)(x+pos)^;
+				if a ~ 0 != 0 {
+					return int(a) < 0 ? -1 : +1;
+				}
+			}
+		}
+	}
+
+	for /**/; offset < n; offset += 1 {
+		a := (^byte)(x+offset)^;
+		if a ~ 0 != 0 {
+			return int(a) < 0 ? -1 : +1;
+		}
+	}
+
+	return 0;
+}
+
 string_eq :: proc "contextless" (a, b: string) -> bool {
 string_eq :: proc "contextless" (a, b: string) -> bool {
 	switch {
 	switch {
 	case len(a) != len(b): return false;
 	case len(a) != len(b): return false;
@@ -253,7 +338,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool {
 }
 }
 
 
 string_cmp :: proc "contextless" (a, b: string) -> int {
 string_cmp :: proc "contextless" (a, b: string) -> int {
-	return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
+	return memory_compare(&a[0], &b[0], min(len(a), len(b)));
 }
 }
 
 
 string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
 string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
@@ -263,18 +348,23 @@ string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cm
 string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
 string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
 
 
 cstring_len :: proc "contextless" (s: cstring) -> int {
 cstring_len :: proc "contextless" (s: cstring) -> int {
-	n := 0;
-	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 {
 cstring_to_string :: proc "contextless" (s: cstring) -> string {
+	Raw_String :: struct {
+		data: ^byte,
+		len: int,
+	};
 	if s == nil do return "";
 	if s == nil do return "";
 	ptr := (^byte)(s);
 	ptr := (^byte)(s);
 	n := cstring_len(s);
 	n := cstring_len(s);
-	return transmute(string)mem.Raw_String{ptr, n};
+	return transmute(string)Raw_String{ptr, n};
 }
 }
 
 
 
 
@@ -285,6 +375,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r
 complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
 complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
 
 
 
 
+quaternion128_eq :: inline proc "contextless"  (a, b: quaternion128)  -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
+quaternion128_ne :: inline proc "contextless"  (a, b: quaternion128)  -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
+
+quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
+quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
 
 
 
 
 bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
 bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
@@ -358,8 +453,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
 	handle_error(file, line, column, from, to);
 	handle_error(file, line, column, from, to);
 }
 }
 
 
+
 string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
 string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
-	return utf8.decode_rune_in_string(s);
+	// NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
+
+	@static accept_sizes := [256]u8{
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
+		0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
+
+		0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
+		0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
+		0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
+		0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
+		0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
+		0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
+		0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
+	};
+	Accept_Range :: struct {lo, hi: u8};
+
+	@static accept_ranges := [5]Accept_Range{
+		{0x80, 0xbf},
+		{0xa0, 0xbf},
+		{0x80, 0x9f},
+		{0x90, 0xbf},
+		{0x80, 0x8f},
+	};
+
+	MASKX :: 0b0011_1111;
+	MASK2 :: 0b0001_1111;
+	MASK3 :: 0b0000_1111;
+	MASK4 :: 0b0000_0111;
+
+	LOCB :: 0b1000_0000;
+	HICB :: 0b1011_1111;
+
+
+	RUNE_ERROR :: '\ufffd';
+
+	n := len(s);
+	if n < 1 {
+		return RUNE_ERROR, 0;
+	}
+	s0 := s[0];
+	x := accept_sizes[s0];
+	if x >= 0xF0 {
+		mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
+		return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
+	}
+	sz := x & 7;
+	accept := accept_ranges[x>>4];
+	if n < int(sz) {
+		return RUNE_ERROR, 1;
+	}
+	b1 := s[1];
+	if b1 < accept.lo || accept.hi < b1 {
+		return RUNE_ERROR, 1;
+	}
+	if sz == 2 {
+		return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
+	}
+	b2 := s[2];
+	if b2 < LOCB || HICB < b2 {
+		return RUNE_ERROR, 1;
+	}
+	if sz == 3 {
+		return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
+	}
+	b3 := s[3];
+	if b3 < LOCB || HICB < b3 {
+		return RUNE_ERROR, 1;
+	}
+	return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
 }
 }
 
 
 bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
 bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
@@ -474,9 +645,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
 	r, i := real(x), imag(x);
 	r, i := real(x), imag(x);
 	return _sqrt_f64(r*r + i*i);
 	return _sqrt_f64(r*r + i*i);
 }
 }
+abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
+	r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
+	return _sqrt_f32(r*r + i*i + j*j + k*k);
+}
+abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
+	r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
+	return _sqrt_f64(r*r + i*i + j*j + k*k);
+}
 
 
-
-quo_complex64 :: proc(n, m: complex64) -> complex64 {
+quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
 	e, f: f32;
 	e, f: f32;
 
 
 	if abs(real(m)) >= abs(imag(m)) {
 	if abs(real(m)) >= abs(imag(m)) {
@@ -494,7 +672,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
 	return complex(e, f);
 	return complex(e, f);
 }
 }
 
 
-quo_complex128 :: proc(n, m: complex128) -> complex128 {
+quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
 	e, f: f64;
 	e, f: f64;
 
 
 	if abs(real(m)) >= abs(imag(m)) {
 	if abs(real(m)) >= abs(imag(m)) {
@@ -511,3 +689,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
 
 
 	return complex(e, f);
 	return complex(e, f);
 }
 }
+
+mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
+	q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+	r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+	t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
+	t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
+	t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
+	t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
+
+	return quaternion(t0, t1, t2, t3);
+}
+
+mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
+	q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+	r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+	t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
+	t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
+	t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
+	t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
+
+	return quaternion(t0, t1, t2, t3);
+}
+
+quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
+	q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+	r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+	invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
+
+	t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
+	t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
+	t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
+	t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
+
+	return quaternion(t0, t1, t2, t3);
+}
+
+quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
+	q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
+	r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
+
+	invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
+
+	t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
+	t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
+	t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
+	t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
+
+	return quaternion(t0, t1, t2, t3);
+}

+ 4 - 3
core/sort/sort.odin

@@ -1,6 +1,7 @@
 package sort
 package sort
 
 
 import "core:mem"
 import "core:mem"
+import "intrinsics"
 
 
 bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
 bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
 	assert(f != nil);
 	assert(f != nil);
@@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
 	}
 	}
 }
 }
 
 
-bubble_sort :: proc(array: $A/[]$T) {
+bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
 	count := len(array);
 	count := len(array);
 
 
 	init_j, last_j := 0, count-1;
 	init_j, last_j := 0, count-1;
@@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
 	quick_sort_proc(a[i:n], f);
 	quick_sort_proc(a[i:n], f);
 }
 }
 
 
-quick_sort :: proc(array: $A/[]$T) {
+quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
 	a := array;
 	a := array;
 	n := len(a);
 	n := len(a);
 	if n < 2 do return;
 	if n < 2 do return;
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
 	if M & 1 == 0 do copy(arr2, arr1);
 	if M & 1 == 0 do copy(arr2, arr1);
 }
 }
 
 
-merge_sort :: proc(array: $A/[]$T) {
+merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
 	merge_slices :: proc(arr1, arr2, out: A) {
 	merge_slices :: proc(arr1, arr2, out: A) {
 		N1, N2 := len(arr1), len(arr2);
 		N1, N2 := len(arr1), len(arr2);
 		i, j := 0, 0;
 		i, j := 0, 0;

+ 1 - 1
core/decimal/decimal.odin → core/strconv/decimal/decimal.odin

@@ -1,6 +1,6 @@
 // Multiple precision decimal numbers
 // Multiple precision decimal numbers
 // NOTE: This is only for floating point printing and nothing else
 // NOTE: This is only for floating point printing and nothing else
-package decimal
+package strconv_decimal
 
 
 Decimal :: struct {
 Decimal :: struct {
 	digits:        [384]byte, // big-endian digits
 	digits:        [384]byte, // big-endian digits

+ 2 - 2
core/strconv/generic_float.odin

@@ -1,6 +1,6 @@
 package strconv
 package strconv
 
 
-using import "core:decimal"
+using import "decimal"
 
 
 Int_Flag :: enum {
 Int_Flag :: enum {
 	Prefix,
 	Prefix,
@@ -105,7 +105,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
 	Buffer :: struct {
 	Buffer :: struct {
 		b: []byte,
 		b: []byte,
 		n: int,
 		n: int,
-	}
+	};
 
 
 	to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
 	to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
 	add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
 	add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {

+ 4 - 0
core/strconv/strconv.odin

@@ -205,7 +205,11 @@ itoa :: proc(buf: []byte, i: int) -> string {
 atoi :: proc(s: string) -> int {
 atoi :: proc(s: string) -> int {
 	return parse_int(s);
 	return parse_int(s);
 }
 }
+atof :: proc(s: string) -> f64 {
+	return parse_f64(s);
+}
 
 
+ftoa :: append_float;
 append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
 append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
 	return string(generic_ftoa(buf, f, fmt, prec, bit_size));
 	return string(generic_ftoa(buf, f, fmt, prec, bit_size));
 }
 }

+ 4 - 0
core/strings/builder.odin

@@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) {
 	reserve(&b.buf, cap);
 	reserve(&b.buf, cap);
 }
 }
 
 
+reset_builder :: proc(b: ^Builder) {
+	clear(&b.buf);
+}
+
 builder_from_slice :: proc(backing: []byte) -> Builder {
 builder_from_slice :: proc(backing: []byte) -> Builder {
 	s := transmute(mem.Raw_Slice)backing;
 	s := transmute(mem.Raw_Slice)backing;
 	d := mem.Raw_Dynamic_Array{
 	d := mem.Raw_Dynamic_Array{

+ 147 - 3
core/strings/strings.odin

@@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
 	return string(b);
 	return string(b);
 }
 }
 
 
+@private
+_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
+	s, n := s_, n_;
+
+	if n == 0 {
+		return nil;
+	}
+
+	if sep == "" {
+		l := utf8.rune_count_in_string(s);
+		if n < 0 || n > l {
+			n = l;
+		}
+
+		res := make([dynamic]string, n, allocator);
+		for i := 0; i < n-1; i += 1 {
+			_, w := utf8.decode_rune_in_string(s);
+			res[i] = s[:w];
+			s = s[w:];
+		}
+		if n > 0 {
+			res[n-1] = s;
+		}
+		return res[:];
+	}
+
+	if n < 0 {
+		n = count(s, sep) + 1;
+	}
+
+	res := make([dynamic]string, n, allocator);
+
+	n -= 1;
+
+	i := 0;
+	for ; i < n; i += 1 {
+		m := index(s, sep);
+		if m < 0 {
+			break;
+		}
+		res[i] = s[:m+sep_save];
+		s = s[m+len(sep):];
+	}
+	res[i] = s;
+
+	return res[:i+1];
+}
+
+split :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
+	return _split(s, sep, 0, -1, allocator);
+}
+
+split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
+	return _split(s, sep, 0, n, allocator);
+}
+
+split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
+	return _split(s, sep, len(sep), -1, allocator);
+}
+
+split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
+	return _split(s, sep, len(sep), n, allocator);
+}
+
+
+
+
 index_byte :: proc(s: string, c: byte) -> int {
 index_byte :: proc(s: string, c: byte) -> int {
 	for i := 0; i < len(s); i += 1 {
 	for i := 0; i < len(s); i += 1 {
 		if s[i] == c do return i;
 		if s[i] == c do return i;
@@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
 	return -1;
 	return -1;
 }
 }
 
 
+
+
+@private PRIME_RABIN_KARP :: 16777619;
+
 index :: proc(s, substr: string) -> int {
 index :: proc(s, substr: string) -> int {
+	hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
+		for i := 0; i < len(s); i += 1 {
+			hash = hash*PRIME_RABIN_KARP + u32(s[i]);
+		}
+		sq := u32(PRIME_RABIN_KARP);
+		for i := len(s); i > 0; i >>= 1 {
+			if (i & 1) != 0 {
+				pow *= sq;
+			}
+			sq *= sq;
+		}
+		return;
+	}
+
 	n := len(substr);
 	n := len(substr);
 	switch {
 	switch {
 	case n == 0:
 	case n == 0:
@@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int {
 		return -1;
 		return -1;
 	}
 	}
 
 
-	for i := 0; i < len(s)-n+1; i += 1 {
-		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;
 			return i;
 		}
 		}
 	}
 	}

+ 0 - 24
core/sys/essence_linker_userland64.ld

@@ -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)
-	}
-}

+ 1 - 1
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="GetModuleFileNameA")        get_module_file_name_a       :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---;
 	@(link_name="GetModuleFileNameW")        get_module_file_name_w       :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
 	@(link_name="GetModuleFileNameW")        get_module_file_name_w       :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---;
 
 
-	@(link_name="Sleep")                     sleep                        :: proc(ms: i32) -> i32 ---;
+	@(link_name="Sleep")                     sleep                        :: proc(ms: u32) ---;
 	@(link_name="QueryPerformanceFrequency") query_performance_frequency  :: proc(result: ^i64) -> i32 ---;
 	@(link_name="QueryPerformanceFrequency") query_performance_frequency  :: proc(result: ^i64) -> i32 ---;
 	@(link_name="QueryPerformanceCounter")   query_performance_counter    :: proc(result: ^i64) -> i32 ---;
 	@(link_name="QueryPerformanceCounter")   query_performance_counter    :: proc(result: ^i64) -> i32 ---;
 	@(link_name="OutputDebugStringA")        output_debug_string_a        :: proc(c_str: cstring) ---;
 	@(link_name="OutputDebugStringA")        output_debug_string_a        :: proc(c_str: cstring) ---;

+ 1 - 1
core/sys/win32/user32.odin

@@ -182,7 +182,7 @@ foreign user32 {
     @(link_name="DestroyIcon")      destroy_icon        :: proc(icon: Hicon) -> Bool ---;
     @(link_name="DestroyIcon")      destroy_icon        :: proc(icon: Hicon) -> Bool ---;
 
 
     @(link_name="LoadCursorA")      load_cursor_a       :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
     @(link_name="LoadCursorA")      load_cursor_a       :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
-    @(link_name="LoadCursorW")      load_cursor_w       :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
+    @(link_name="LoadCursorW")      load_cursor_w       :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---;
 	@(link_name="GetCursor")        get_cursor          :: proc() -> Hcursor ---;
 	@(link_name="GetCursor")        get_cursor          :: proc() -> Hcursor ---;
 	@(link_name="SetCursor")        set_cursor          :: proc(cursor: Hcursor) -> Hcursor ---;
 	@(link_name="SetCursor")        set_cursor          :: proc(cursor: Hcursor) -> Hcursor ---;
 
 

+ 0 - 0
core/time/time_osx.odin → core/time/time_darwin.odin


+ 2 - 0
core/time/time_essence.odin

@@ -0,0 +1,2 @@
+package time
+IS_SUPPORTED :: false;

+ 1 - 1
core/time/time_windows.odin

@@ -20,5 +20,5 @@ now :: proc() -> Time {
 
 
 
 
 sleep :: proc(d: Duration) {
 sleep :: proc(d: Duration) {
-	win32.sleep(i32(d/Millisecond));
+	win32.sleep(u32(d/Millisecond));
 }
 }

+ 60 - 17
core/unicode/utf8/utf8.odin

@@ -41,23 +41,17 @@ accept_ranges := [5]Accept_Range{
 };
 };
 
 
 accept_sizes := [256]u8{
 accept_sizes := [256]u8{
-	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
-	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) {
 encode_rune :: proc(c: rune) -> ([4]u8, int) {
@@ -167,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
 	return r, size;
 	return r, size;
 }
 }
 
 
+rune_at_pos :: proc(s: string, pos: int) -> rune {
+	if pos < 0 {
+		return RUNE_ERROR;
+	}
 
 
+	i := 0;
+	for r in s {
+		if i == pos {
+			return r;
+		}
+		i += 1;
+	}
+	return RUNE_ERROR;
+}
 
 
+rune_string_at_pos :: proc(s: string, pos: int) -> string {
+	if pos < 0 {
+		return "";
+	}
+
+	i := 0;
+	for c, offset in s {
+		if i == pos {
+			w := rune_size(c);
+			return s[offset:][:w];
+		}
+		i += 1;
+	}
+	return "";
+}
 
 
+rune_at :: proc(s: string, byte_index: int) -> rune {
+	r, _ := decode_rune_in_string(s[byte_index:]);
+	return r;
+}
+
+// Returns the byte position of rune at position pos in s with an optional start byte position.
+// Returns -1 if it runs out of the string.
+rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
+	if pos < 0 {
+		return -1;
+	}
+
+	i := 0;
+	for _, offset in s[start:] {
+		if i == pos {
+			return offset+start;
+		}
+		i += 1;
+	}
+	return -1;
+}
 
 
 valid_rune :: proc(r: rune) -> bool {
 valid_rune :: proc(r: rune) -> bool {
 	if r < 0 {
 	if r < 0 {

+ 334 - 40
examples/demo/demo.odin

@@ -3,14 +3,34 @@ package main
 import "core:fmt"
 import "core:fmt"
 import "core:mem"
 import "core:mem"
 import "core:os"
 import "core:os"
+import "core:reflect"
+import "intrinsics"
 
 
 when os.OS == "windows" {
 when os.OS == "windows" {
 	import "core:thread"
 	import "core:thread"
 }
 }
 
 
-@(link_name="general_stuff")
-general_stuff :: proc() {
-	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
 	{ // `do` for inline statements rather than block
 		foo :: proc() do fmt.println("Foo!");
 		foo :: proc() do fmt.println("Foo!");
 		if   false do foo();
 		if   false do foo();
@@ -30,14 +50,12 @@ general_stuff :: proc() {
 		i := i32(137);
 		i := i32(137);
 		ptr := &i;
 		ptr := &i;
 
 
-		_ = (^f32)(ptr);
+		_ = (^f32)(ptr); // Call-based syntax
 		// ^f32(ptr) == ^(f32(ptr))
 		// ^f32(ptr) == ^(f32(ptr))
-		_ = cast(^f32)ptr;
+		_ = cast(^f32)ptr; // Operator-based syntax
 
 
 		_ = (^f32)(ptr)^;
 		_ = (^f32)(ptr)^;
 		_ = (cast(^f32)ptr)^;
 		_ = (cast(^f32)ptr)^;
-
-		// Questions: Should there be two ways to do it?
 	}
 	}
 
 
 	/*
 	/*
@@ -50,7 +68,7 @@ general_stuff :: proc() {
 		Foo :: struct {
 		Foo :: struct {
 			x: int,
 			x: int,
 			b: bool,
 			b: bool,
-		}
+		};
 		f := Foo{137, true};
 		f := Foo{137, true};
 		x, b := expand_to_tuple(f);
 		x, b := expand_to_tuple(f);
 		fmt.println(f);
 		fmt.println(f);
@@ -191,8 +209,8 @@ union_type :: proc() {
 		}
 		}
 	}
 	}
 
 
-	Vector3 :: struct {x, y, z: f32};
-	Quaternion :: struct {x, y, z, w: f32};
+	Vector3 :: distinct [3]f32;
+	Quaternion :: distinct quaternion128;
 
 
 	// More realistic examples
 	// More realistic examples
 	{
 	{
@@ -209,18 +227,18 @@ union_type :: proc() {
 			orientation: Quaternion,
 			orientation: Quaternion,
 
 
 			derived: any,
 			derived: any,
-		}
+		};
 
 
 		Frog :: struct {
 		Frog :: struct {
 			using entity: Entity,
 			using entity: Entity,
 			jump_height:  f32,
 			jump_height:  f32,
-		}
+		};
 
 
 		Monster :: struct {
 		Monster :: struct {
 			using entity: Entity,
 			using entity: Entity,
 			is_robot:     bool,
 			is_robot:     bool,
 			is_zombie:    bool,
 			is_zombie:    bool,
-		}
+		};
 
 
 		// See `parametric_polymorphism` procedure for details
 		// See `parametric_polymorphism` procedure for details
 		new_entity :: proc($T: typeid) -> ^Entity {
 		new_entity :: proc($T: typeid) -> ^Entity {
@@ -254,18 +272,18 @@ union_type :: proc() {
 			orientation: Quaternion,
 			orientation: Quaternion,
 
 
 			derived: union {Frog, Monster},
 			derived: union {Frog, Monster},
-		}
+		};
 
 
 		Frog :: struct {
 		Frog :: struct {
 			using entity: ^Entity,
 			using entity: ^Entity,
 			jump_height:  f32,
 			jump_height:  f32,
-		}
+		};
 
 
 		Monster :: struct {
 		Monster :: struct {
 			using entity: ^Entity,
 			using entity: ^Entity,
 			is_robot:     bool,
 			is_robot:     bool,
 			is_zombie:    bool,
 			is_zombie:    bool,
-		}
+		};
 
 
 		// See `parametric_polymorphism` procedure for details
 		// See `parametric_polymorphism` procedure for details
 		new_entity :: proc($T: typeid) -> ^Entity {
 		new_entity :: proc($T: typeid) -> ^Entity {
@@ -302,17 +320,17 @@ union_type :: proc() {
 
 
 		/*
 		/*
 			Entity :: struct {
 			Entity :: struct {
-				..
+				...
 				derived: union{^Frog, ^Monster},
 				derived: union{^Frog, ^Monster},
 			}
 			}
 
 
 			Frog :: struct {
 			Frog :: struct {
 				using entity: Entity,
 				using entity: Entity,
-				..
+				...
 			}
 			}
 			Monster :: struct {
 			Monster :: struct {
 				using entity: Entity,
 				using entity: Entity,
-				..
+				...
 
 
 			}
 			}
 			new_entity :: proc(T: type) -> ^Entity {
 			new_entity :: proc(T: type) -> ^Entity {
@@ -325,7 +343,7 @@ union_type :: proc() {
 }
 }
 
 
 parametric_polymorphism :: proc() {
 parametric_polymorphism :: proc() {
-	fmt.println("# parametric_polymorphism");
+	fmt.println("\n# parametric_polymorphism");
 
 
 	print_value :: proc(value: $T) {
 	print_value :: proc(value: $T) {
 		fmt.printf("print_value: %T %v\n", value, value);
 		fmt.printf("print_value: %T %v\n", value, value);
@@ -383,13 +401,13 @@ parametric_polymorphism :: proc() {
 			hash:     u32,
 			hash:     u32,
 			key:      Key,
 			key:      Key,
 			value:    Value,
 			value:    Value,
-		}
+		};
 		TABLE_SIZE_MIN :: 32;
 		TABLE_SIZE_MIN :: 32;
 		Table :: struct(Key, Value: typeid) {
 		Table :: struct(Key, Value: typeid) {
 			count:     int,
 			count:     int,
 			allocator: mem.Allocator,
 			allocator: mem.Allocator,
 			slots:     []Table_Slot(Key, Value),
 			slots:     []Table_Slot(Key, Value),
-		}
+		};
 
 
 		// Only allow types that are specializations of a (polymorphic) slice
 		// Only allow types that are specializations of a (polymorphic) slice
 		make_slice :: proc($T: typeid/[]$E, len: int) -> T {
 		make_slice :: proc($T: typeid/[]$E, len: int) -> T {
@@ -513,7 +531,7 @@ parametric_polymorphism :: proc() {
 			Foo1,
 			Foo1,
 			Foo2,
 			Foo2,
 			Foo3,
 			Foo3,
-		}
+		};
 		Para_Union :: union(T: typeid) {T, Error};
 		Para_Union :: union(T: typeid) {T, Error};
 		r: Para_Union(int);
 		r: Para_Union(int);
 		fmt.println(typeid_of(type_of(r)));
 		fmt.println(typeid_of(type_of(r)));
@@ -521,7 +539,7 @@ parametric_polymorphism :: proc() {
 		fmt.println(r);
 		fmt.println(r);
 		r = 123;
 		r = 123;
 		fmt.println(r);
 		fmt.println(r);
-		r = Error.Foo0;
+		r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
 		fmt.println(r);
 		fmt.println(r);
 	}
 	}
 
 
@@ -543,6 +561,30 @@ parametric_polymorphism :: proc() {
 		for v, i in array {
 		for v, i in array {
 			assert(v == T(i*i));
 			assert(v == T(i*i));
 		}
 		}
+
+		// Matrix multiplication
+		mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) {
+			for i in 0..<M {
+				for j in 0..<P {
+					for k in 0..<N {
+						c[i][j] += a[i][k] * b[k][j];
+					}
+				}
+			}
+			return;
+		}
+
+		x := [2][3]f32{
+			{1, 2, 3},
+			{3, 2, 1},
+		};
+		y := [3][2]f32{
+			{0, 8},
+			{6, 2},
+			{8, 4},
+		};
+		z := mul(x, y);
+		assert(z == {{36, 24}, {20, 32}});
 	}
 	}
 }
 }
 
 
@@ -560,7 +602,7 @@ prefix_table := [?]string{
 
 
 threading_example :: proc() {
 threading_example :: proc() {
 	when os.OS == "windows" {
 	when os.OS == "windows" {
-		fmt.println("# threading_example");
+		fmt.println("\n# threading_example");
 
 
 		worker_proc :: proc(t: ^thread.Thread) -> int {
 		worker_proc :: proc(t: ^thread.Thread) -> int {
 			for iteration in 1..5 {
 			for iteration in 1..5 {
@@ -600,7 +642,7 @@ threading_example :: proc() {
 }
 }
 
 
 array_programming :: proc() {
 array_programming :: proc() {
-	fmt.println("# array_programming");
+	fmt.println("\n# array_programming");
 	{
 	{
 		a := [3]f32{1, 2, 3};
 		a := [3]f32{1, 2, 3};
 		b := [3]f32{5, 6, 7};
 		b := [3]f32{5, 6, 7};
@@ -645,7 +687,7 @@ array_programming :: proc() {
 }
 }
 
 
 named_proc_return_parameters :: proc() {
 named_proc_return_parameters :: proc() {
-	fmt.println("# named proc return parameters");
+	fmt.println("\n# named proc return parameters");
 
 
 	foo0 :: proc() -> int {
 	foo0 :: proc() -> int {
 		return 123;
 		return 123;
@@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() {
 
 
 
 
 using_enum :: proc() {
 using_enum :: proc() {
-	fmt.println("# using enum");
+	fmt.println("\n# using enum");
 
 
 	using Foo :: enum {A, B, C};
 	using Foo :: enum {A, B, C};
 
 
@@ -679,25 +721,25 @@ using_enum :: proc() {
 }
 }
 
 
 map_type :: proc() {
 map_type :: proc() {
-	fmt.println("# map type");
+	fmt.println("\n# map type");
 
 
 	// enums of type u16, u32, i16 & i32 also work
 	// enums of type u16, u32, i16 & i32 also work
 	Enum_u8 :: enum u8 {
 	Enum_u8 :: enum u8 {
 		A = 0,
 		A = 0,
 		B = 1 << 8 - 1,
 		B = 1 << 8 - 1,
-	}
+	};
 	Enum_u64 :: enum u64 {
 	Enum_u64 :: enum u64 {
 		A = 0,
 		A = 0,
 		B = 1 << 64 - 1,
 		B = 1 << 64 - 1,
-	}
+	};
 	Enum_i8 :: enum i8 {
 	Enum_i8 :: enum i8 {
 		A = 0,
 		A = 0,
 		B = -(1 << 7),
 		B = -(1 << 7),
-	}
+	};
 	Enum_i64 :: enum i64 {
 	Enum_i64 :: enum i64 {
 		A = 0,
 		A = 0,
 		B = -(1 << 63),
 		B = -(1 << 63),
-	}
+	};
 
 
 	map_u8: map[Enum_u8]u8;
 	map_u8: map[Enum_u8]u8;
 	map_u8[Enum_u8.A] = u8(Enum_u8.B);
 	map_u8[Enum_u8.A] = u8(Enum_u8.B);
@@ -721,7 +763,7 @@ map_type :: proc() {
 
 
 	demo_struct :: struct {
 	demo_struct :: struct {
 		member: Enum_i64,
 		member: Enum_i64,
-	}
+	};
 
 
 	map_string: map[string]demo_struct;
 	map_string: map[string]demo_struct;
 	map_string["Hellope!"] = demo_struct{Enum_i64.B};
 	map_string["Hellope!"] = demo_struct{Enum_i64.B};
@@ -734,7 +776,7 @@ map_type :: proc() {
 }
 }
 
 
 implicit_selector_expression :: proc() {
 implicit_selector_expression :: proc() {
-	fmt.println("# implicit selector expression");
+	fmt.println("\n# implicit selector expression");
 
 
 	Foo :: enum {A, B, C};
 	Foo :: enum {A, B, C};
 
 
@@ -762,7 +804,7 @@ implicit_selector_expression :: proc() {
 }
 }
 
 
 explicit_procedure_overloading :: proc() {
 explicit_procedure_overloading :: proc() {
-	fmt.println("# explicit procedure overloading");
+	fmt.println("\n# explicit procedure overloading");
 
 
 	add_ints :: proc(a, b: int) -> int {
 	add_ints :: proc(a, b: int) -> int {
 		x := a + b;
 		x := a + b;
@@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() {
 }
 }
 
 
 complete_switch :: proc() {
 complete_switch :: proc() {
-	fmt.println("# complete_switch");
+	fmt.println("\n# complete_switch");
 	{ // enum
 	{ // enum
 		using Foo :: enum {
 		using Foo :: enum {
 			A,
 			A,
 			B,
 			B,
 			C,
 			C,
 			D,
 			D,
-		}
+		};
 
 
 		b := Foo.B;
 		b := Foo.B;
 		f := Foo.A;
 		f := Foo.A;
@@ -829,6 +871,8 @@ complete_switch :: proc() {
 }
 }
 
 
 cstring_example :: proc() {
 cstring_example :: proc() {
+	fmt.println("\n# cstring_example");
+
 	W :: "Hellope";
 	W :: "Hellope";
 	X :: cstring(W);
 	X :: cstring(W);
 	Y :: string(X);
 	Y :: string(X);
@@ -860,6 +904,8 @@ deprecated_attribute :: proc() {
 }
 }
 
 
 bit_set_type :: proc() {
 bit_set_type :: proc() {
+	fmt.println("\n# bit_set_type");
+
 	{
 	{
 		using Day :: enum {
 		using Day :: enum {
 			Sunday,
 			Sunday,
@@ -869,7 +915,7 @@ bit_set_type :: proc() {
 			Thursday,
 			Thursday,
 			Friday,
 			Friday,
 			Saturday,
 			Saturday,
-		}
+		};
 
 
 		Days :: distinct bit_set[Day];
 		Days :: distinct bit_set[Day];
 		WEEKEND :: Days{Sunday, Saturday};
 		WEEKEND :: Days{Sunday, Saturday};
@@ -921,6 +967,8 @@ bit_set_type :: proc() {
 }
 }
 
 
 diverging_procedures :: proc() {
 diverging_procedures :: proc() {
+	fmt.println("\n# diverging_procedures");
+
 	// Diverging procedures may never return
 	// Diverging procedures may never return
 	foo :: proc() -> ! {
 	foo :: proc() -> ! {
 		fmt.println("I'm a diverging procedure");
 		fmt.println("I'm a diverging procedure");
@@ -930,6 +978,8 @@ diverging_procedures :: proc() {
 }
 }
 
 
 deferred_procedure_associations :: proc() {
 deferred_procedure_associations :: proc() {
+	fmt.println("\n# deferred_procedure_associations");
+
 	@(deferred_out=closure)
 	@(deferred_out=closure)
 	open :: proc(s: string) -> bool {
 	open :: proc(s: string) -> bool {
 		fmt.println(s);
 		fmt.println(s);
@@ -945,9 +995,247 @@ deferred_procedure_associations :: proc() {
 	}
 	}
 }
 }
 
 
+reflection :: proc() {
+	fmt.println("\n# reflection");
+
+	Foo :: struct {
+		x: int    `tag1`,
+		y: string `json:"y_field"`,
+		z: bool, // no tag
+	};
+
+	id := typeid_of(Foo);
+	names := reflect.struct_field_names(id);
+	types := reflect.struct_field_types(id);
+	tags  := reflect.struct_field_tags(id);
+
+	assert(len(names) == len(types) && len(names) == len(tags));
+
+	fmt.println("Foo :: struct {");
+	for tag, i in tags {
+		name, type := names[i], types[i];
+		if tag != "" {
+			fmt.printf("\t%s: %T `%s`,\n", name, type, tag);
+		} else {
+			fmt.printf("\t%s: %T,\n", name, type);
+		}
+	}
+	fmt.println("}");
+
+
+	for tag, i in tags {
+		if val, ok := reflect.struct_tag_lookup(tag, "json"); ok {
+			fmt.printf("json: %s -> %s\n", names[i], val);
+		}
+	}
+}
+
+quaternions :: proc() {
+	fmt.println("\n# quaternions");
+
+	{ // Quaternion operations
+		q := 1 + 2i + 3j + 4k;
+		r := quaternion(5, 6, 7, 8);
+		t := q * r;
+		fmt.printf("(%v) * (%v) = %v\n", q, r, t);
+		v := q / r;
+		fmt.printf("(%v) / (%v) = %v\n", q, r, v);
+		u := q + r;
+		fmt.printf("(%v) + (%v) = %v\n", q, r, u);
+		s := q - r;
+		fmt.printf("(%v) - (%v) = %v\n", q, r, s);
+	}
+	{ // The quaternion types
+		q128: quaternion128; // 4xf32
+		q256: quaternion256; // 4xf64
+		q128 = quaternion(1, 0, 0, 0);
+		q256 = 1; // quaternion(1, 0, 0, 0);
+	}
+	{ // Built-in procedures
+		q := 1 + 2i + 3j + 4k;
+		fmt.println("q =", q);
+		fmt.println("real(q) =", real(q));
+		fmt.println("imag(q) =", imag(q));
+		fmt.println("jmag(q) =", jmag(q));
+		fmt.println("kmag(q) =", kmag(q));
+		fmt.println("conj(q) =", conj(q));
+		fmt.println("abs(q)  =", abs(q));
+	}
+	{ // Conversion of a complex type to a quaternion type
+		c := 1 + 2i;
+		q := quaternion256(c);
+		fmt.println(c);
+		fmt.println(q);
+	}
+	{ // Memory layout of Quaternions
+		q := 1 + 2i + 3j + 4k;
+		a := transmute([4]f64)q;
+		fmt.println("Quaternion memory layout: xyzw/(ijkr)");
+		fmt.println(q); // 1.000+2.000i+3.000j+4.000k
+		fmt.println(a); // [2.000, 3.000, 4.000, 1.000]
+	}
+}
+
+inline_for_statement :: proc() {
+	fmt.println("\n#inline for statements");
+
+	// 'inline for' works the same as if the 'inline' prefix did not
+	// exist but these ranged loops are explicitly unrolled which can
+	// be very very useful for certain optimizations
+
+	fmt.println("Ranges");
+	inline for x, i in 1..<4 {
+		fmt.println(x, i);
+	}
+
+	fmt.println("Strings");
+	inline for r, i in "Hello, 世界" {
+		fmt.println(r, i);
+	}
+
+	fmt.println("Arrays");
+	inline for elem, idx in ([4]int{1, 4, 9, 16}) {
+		fmt.println(elem, idx);
+	}
+
+
+	Foo_Enum :: enum {
+		A = 1,
+		B,
+		C = 6,
+		D,
+	};
+	fmt.println("Enum types");
+	inline for elem, idx in Foo_Enum {
+		fmt.println(elem, idx);
+	}
+}
+
+where_clauses :: proc() {
+	fmt.println("\n#procedure 'where' clauses");
+
+	{ // Sanity checks
+		simple_sanity_check :: proc(x: [2]int)
+			where len(x) > 1,
+			      type_of(x) == [2]int {
+			fmt.println(x);
+		}
+	}
+	{ // Parametric polymorphism checks
+		cross_2d :: proc(a, b: $T/[2]$E) -> E
+			where intrinsics.type_is_numeric(E) {
+			return a.x*b.y - a.y*b.x;
+		}
+		cross_3d :: proc(a, b: $T/[3]$E) -> T
+			where intrinsics.type_is_numeric(E) {
+			x := a.y*b.z - a.z*b.y;
+			y := a.z*b.x - a.x*b.z;
+			z := a.x*b.y - a.y*b.z;
+			return T{x, y, z};
+		}
+
+		a := [2]int{1, 2};
+		b := [2]int{5, -3};
+		fmt.println(cross_2d(a, b));
+
+		x := [3]f32{1, 4, 9};
+		y := [3]f32{-5, 0, 3};
+		fmt.println(cross_3d(x, y));
+
+		// Failure case
+		// i := [2]bool{true, false};
+		// j := [2]bool{false, true};
+		// fmt.println(cross_2d(i, j));
+
+	}
+
+	{ // Procedure groups usage
+		foo :: proc(x: [$N]int) -> bool
+			where N > 2 {
+			fmt.println(#procedure, "was called with the parameter", x);
+			return true;
+		}
+
+		bar :: proc(x: [$N]int) -> bool
+			where 0 < N,
+			      N <= 2 {
+			fmt.println(#procedure, "was called with the parameter", x);
+			return false;
+		}
+
+		baz :: proc{foo, bar};
+
+		x := [3]int{1, 2, 3};
+		y := [2]int{4, 9};
+		ok_x := baz(x);
+		ok_y := baz(y);
+		assert(ok_x == true);
+		assert(ok_y == false);
+	}
+
+	{ // Record types
+		Foo :: struct(T: typeid, N: int)
+			where intrinsics.type_is_integer(T),
+			      N > 2 {
+			x: [N]T,
+			y: [N-2]T,
+		};
+
+		T :: i32;
+		N :: 5;
+		f: Foo(T, N);
+		#assert(size_of(f) == (N+N-2)*size_of(T));
+	}
+}
+
+ranged_fields_for_array_compound_literals :: proc() {
+	fmt.println("\n#ranged fields for array compound literals");
+	{ // Normal Array Literal
+		foo := [?]int{1, 4, 9, 16};
+		fmt.println(foo);
+	}
+	{ // Indexed
+		foo := [?]int{
+			3 = 16,
+			1 = 4,
+			2 = 9,
+			0 = 1,
+		};
+		fmt.println(foo);
+	}
+	{ // Ranges
+		i := 2;
+		foo := [?]int {
+			0 = 123,
+			5..9 = 54,
+			10..<16 = i*3 + (i-1)*2,
+		};
+		#assert(len(foo) == 16);
+		fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
+	}
+	{ // Slice and Dynamic Array support
+		i := 2;
+		foo_slice := []int {
+			0 = 123,
+			5..9 = 54,
+			10..<16 = i*3 + (i-1)*2,
+		};
+		assert(len(foo_slice) == 16);
+		fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
+
+		foo_dynamic_array := [dynamic]int {
+			0 = 123,
+			5..9 = 54,
+			10..<16 = i*3 + (i-1)*2,
+		};
+		assert(len(foo_dynamic_array) == 16);
+		fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
+	}
+}
+
 main :: proc() {
 main :: proc() {
 	when true {
 	when true {
-		general_stuff();
+		extra_general_stuff();
 		union_type();
 		union_type();
 		parametric_polymorphism();
 		parametric_polymorphism();
 		threading_example();
 		threading_example();
@@ -963,5 +1251,11 @@ main :: proc() {
 		bit_set_type();
 		bit_set_type();
 		diverging_procedures();
 		diverging_procedures();
 		deferred_procedure_associations();
 		deferred_procedure_associations();
+		reflection();
+		quaternions();
+		inline_for_statement();
+		where_clauses();
+		ranged_fields_for_array_compound_literals();
 	}
 	}
 }
 }
+

BIN
misc/logo-slim.png


+ 0 - 0
examples/old_demos/demo001.odin → misc/old_demos/demo001.odin


+ 0 - 0
examples/old_demos/demo002.odin → misc/old_demos/demo002.odin


+ 0 - 0
examples/old_demos/demo004.odin → misc/old_demos/demo004.odin


+ 0 - 0
examples/old_demos/demo005.odin → misc/old_demos/demo005.odin


+ 0 - 0
examples/old_demos/demo006.odin → misc/old_demos/demo006.odin


+ 0 - 0
examples/old_demos/demo007.odin → misc/old_demos/demo007.odin


+ 0 - 0
examples/old_demos/demo008.odin → misc/old_demos/demo008.odin


+ 0 - 0
examples/old_demos/old_runtime.odin → misc/old_demos/old_runtime.odin


+ 0 - 0
examples/old_stuff/demo_backup.odin → misc/old_stuff/demo_backup.odin


+ 2 - 2
misc/shell.bat

@@ -1,8 +1,8 @@
 @echo off
 @echo off
 
 
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
-call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
-rem call "C:\Program Files (x86)\Microsoft Visual Studio 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" x86 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
 rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
 set _NO_DEBUG_HEAP=1
 set _NO_DEBUG_HEAP=1

+ 42 - 14
src/build_settings.cpp

@@ -2,7 +2,7 @@ enum TargetOsKind {
 	TargetOs_Invalid,
 	TargetOs_Invalid,
 
 
 	TargetOs_windows,
 	TargetOs_windows,
-	TargetOs_osx,
+	TargetOs_darwin,
 	TargetOs_linux,
 	TargetOs_linux,
 	TargetOs_essence,
 	TargetOs_essence,
 
 
@@ -30,7 +30,7 @@ enum TargetEndianKind {
 String target_os_names[TargetOs_COUNT] = {
 String target_os_names[TargetOs_COUNT] = {
 	str_lit(""),
 	str_lit(""),
 	str_lit("windows"),
 	str_lit("windows"),
-	str_lit("osx"),
+	str_lit("darwin"),
 	str_lit("linux"),
 	str_lit("linux"),
 	str_lit("essence"),
 	str_lit("essence"),
 };
 };
@@ -55,9 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
 
 
 
 
 
 
-String const ODIN_VERSION = str_lit("0.10.1");
-String 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;
 	TargetArchKind arch;
 	isize          word_size;
 	isize          word_size;
 	isize          max_align;
 	isize          max_align;
+	String         target_triplet;
 };
 };
 
 
 
 
@@ -109,6 +108,7 @@ struct BuildContext {
 	bool   has_resource;
 	bool   has_resource;
 	String opt_flags;
 	String opt_flags;
 	String llc_flags;
 	String llc_flags;
+	String target_triplet;
 	String link_flags;
 	String link_flags;
 	bool   is_dll;
 	bool   is_dll;
 	bool   generate_docs;
 	bool   generate_docs;
@@ -121,6 +121,7 @@ struct BuildContext {
 	bool   no_crt;
 	bool   no_crt;
 	bool   use_lld;
 	bool   use_lld;
 	bool   vet;
 	bool   vet;
+	bool   cross_compiling;
 
 
 	QueryDataSetSettings query_data_set_settings;
 	QueryDataSetSettings query_data_set_settings;
 
 
@@ -135,18 +136,19 @@ struct BuildContext {
 gb_global BuildContext build_context = {0};
 gb_global BuildContext build_context = {0};
 
 
 
 
-
 gb_global TargetMetrics target_windows_386 = {
 gb_global TargetMetrics target_windows_386 = {
 	TargetOs_windows,
 	TargetOs_windows,
 	TargetArch_386,
 	TargetArch_386,
 	4,
 	4,
 	8,
 	8,
+	str_lit("i686-pc-windows"),
 };
 };
 gb_global TargetMetrics target_windows_amd64 = {
 gb_global TargetMetrics target_windows_amd64 = {
 	TargetOs_windows,
 	TargetOs_windows,
 	TargetArch_amd64,
 	TargetArch_amd64,
 	8,
 	8,
 	16,
 	16,
+	str_lit("x86_64-pc-windows-gnu"),
 };
 };
 
 
 gb_global TargetMetrics target_linux_386 = {
 gb_global TargetMetrics target_linux_386 = {
@@ -154,23 +156,47 @@ gb_global TargetMetrics target_linux_386 = {
 	TargetArch_386,
 	TargetArch_386,
 	4,
 	4,
 	8,
 	8,
+	str_lit("i686-pc-linux-gnu"),
 };
 };
 gb_global TargetMetrics target_linux_amd64 = {
 gb_global TargetMetrics target_linux_amd64 = {
 	TargetOs_linux,
 	TargetOs_linux,
 	TargetArch_amd64,
 	TargetArch_amd64,
 	8,
 	8,
 	16,
 	16,
+	str_lit("x86_64-pc-linux-gnu"),
+};
+
+gb_global TargetMetrics target_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,
 	TargetArch_amd64,
 	8,
 	8,
 	16,
 	16,
+	str_lit("x86_64-pc-none-elf"),
 };
 };
 
 
+struct NamedTargetMetrics {
+	String name;
+	TargetMetrics *metrics;
+};
 
 
+gb_global NamedTargetMetrics named_targets[] = {
+	{ str_lit("essence_amd64"), &target_essence_amd64 },
+	{ str_lit("darwin_amd64"),   &target_darwin_amd64 },
+	{ str_lit("linux_386"),     &target_linux_386 },
+	{ str_lit("linux_amd64"),   &target_linux_amd64 },
+	{ str_lit("windows_386"),   &target_windows_386 },
+	{ str_lit("windows_amd64"), &target_windows_amd64 },
+};
 
 
+NamedTargetMetrics *selected_target_metrics;
 
 
 TargetOsKind get_target_os_from_string(String str) {
 TargetOsKind get_target_os_from_string(String str) {
 	for (isize i = 0; i < TargetOs_COUNT; i++) {
 	for (isize i = 0; i < TargetOs_COUNT; i++) {
@@ -522,7 +548,7 @@ String get_fullpath_core(gbAllocator a, String path) {
 
 
 
 
 
 
-void init_build_context(void) {
+void init_build_context(TargetMetrics *cross_target) {
 	BuildContext *bc = &build_context;
 	BuildContext *bc = &build_context;
 
 
 	gb_affinity_init(&bc->affinity);
 	gb_affinity_init(&bc->affinity);
@@ -540,7 +566,7 @@ void init_build_context(void) {
 		#if defined(GB_SYSTEM_WINDOWS)
 		#if defined(GB_SYSTEM_WINDOWS)
 			metrics = target_windows_amd64;
 			metrics = target_windows_amd64;
 		#elif defined(GB_SYSTEM_OSX)
 		#elif defined(GB_SYSTEM_OSX)
-			metrics = target_osx_amd64;
+			metrics = target_darwin_amd64;
 		#else
 		#else
 			metrics = target_linux_amd64;
 			metrics = target_linux_amd64;
 		#endif
 		#endif
@@ -554,8 +580,9 @@ void init_build_context(void) {
 		#endif
 		#endif
 	#endif
 	#endif
 
 
-	if (cross_compile_target.len) {
-		bc->ODIN_OS = cross_compile_target;
+	if (cross_target) {
+		metrics = *cross_target;
+		bc->cross_compiling = true;
 	}
 	}
 
 
 	GB_ASSERT(metrics.os != TargetOs_Invalid);
 	GB_ASSERT(metrics.os != TargetOs_Invalid);
@@ -573,6 +600,7 @@ void init_build_context(void) {
 	bc->max_align   = metrics.max_align;
 	bc->max_align   = metrics.max_align;
 	bc->link_flags  = str_lit(" ");
 	bc->link_flags  = str_lit(" ");
 	bc->opt_flags   = str_lit(" ");
 	bc->opt_flags   = str_lit(" ");
+	bc->target_triplet = metrics.target_triplet;
 
 
 
 
 	gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
 	gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
@@ -590,7 +618,7 @@ void init_build_context(void) {
 		case TargetOs_windows:
 		case TargetOs_windows:
 			bc->link_flags = str_lit("/machine:x64 ");
 			bc->link_flags = str_lit("/machine:x64 ");
 			break;
 			break;
-		case TargetOs_osx:
+		case TargetOs_darwin:
 			break;
 			break;
 		case TargetOs_linux:
 		case TargetOs_linux:
 			bc->link_flags = str_lit("-arch x86-64 ");
 			bc->link_flags = str_lit("-arch x86-64 ");
@@ -603,7 +631,7 @@ void init_build_context(void) {
 		case TargetOs_windows:
 		case TargetOs_windows:
 			bc->link_flags = str_lit("/machine:x86 ");
 			bc->link_flags = str_lit("/machine:x86 ");
 			break;
 			break;
-		case TargetOs_osx:
+		case TargetOs_darwin:
 			gb_printf_err("Unsupported architecture\n");
 			gb_printf_err("Unsupported architecture\n");
 			gb_exit(1);
 			gb_exit(1);
 			break;
 			break;

+ 163 - 84
src/check_decl.cpp

@@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
 	}
 	}
 
 
 	if (operand->mode == Addressing_Type) {
 	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;
 	isize rhs_count = operands.count;
 	for_array(i, operands) {
 	for_array(i, operands) {
 		if (operands[i].mode == Addressing_Invalid) {
 		if (operands[i].mode == Addressing_Invalid) {
-			rhs_count--;
+			// TODO(bill): Should I ignore invalid parameters?
+			// rhs_count--;
 		}
 		}
 	}
 	}
 
 
@@ -239,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
 }
 }
 
 
 
 
-void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
+void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
 	GB_ASSERT(e->type == nullptr);
 	GB_ASSERT(e->type == nullptr);
 
 
 	DeclInfo *decl = decl_info_of_entity(e);
 	DeclInfo *decl = decl_info_of_entity(e);
@@ -247,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
 		check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
 		check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
 	}
 	}
 
 
-
-	bool is_distinct = is_type_distinct(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;
 	e->type = t_invalid;
 	String name = e->token.string;
 	String name = e->token.string;
 	Type *named = alloc_type_named(name, nullptr, e);
 	Type *named = alloc_type_named(name, nullptr, e);
@@ -265,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
 	named->Named.base = base_type(bt);
 	named->Named.base = base_type(bt);
 
 
 	if (is_distinct && is_type_typeid(e->type)) {
 	if (is_distinct && is_type_typeid(e->type)) {
-		error(type_expr, "'distinct' cannot be applied to 'typeid'");
+		error(init_expr, "'distinct' cannot be applied to 'typeid'");
 		is_distinct = false;
 		is_distinct = false;
 	}
 	}
 	if (!is_distinct) {
 	if (!is_distinct) {
@@ -274,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
 		e->TypeName.is_type_alias = true;
 		e->TypeName.is_type_alias = true;
 	}
 	}
 
 
+
+	if (decl->type_expr != nullptr) {
+		Type *t = check_type(ctx, decl->type_expr);
+		if (t != nullptr && !is_type_typeid(t)) {
+			Operand operand = {};
+			operand.mode = Addressing_Type;
+			operand.type = e->type;
+			operand.expr = init_expr;
+			check_assignment(ctx, &operand, t, str_lit("constant declaration"));
+		}
+	}
+
+
 	// using decl
 	// using decl
 	if (decl->is_using) {
 	if (decl->is_using) {
 		// NOTE(bill): Must be an enum declaration
 		// NOTE(bill): Must be an enum declaration
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
 
 
 		switch (operand.mode) {
 		switch (operand.mode) {
 		case Addressing_Type: {
 		case Addressing_Type: {
+			if (e->type != nullptr && !is_type_typeid(e->type)) {
+				check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
+			}
+
 			e->kind = Entity_TypeName;
 			e->kind = Entity_TypeName;
 			e->type = nullptr;
 			e->type = nullptr;
 
 
-			DeclInfo *d = ctx->decl;
-			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;
 			return;
 		}
 		}
 
 
@@ -654,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 
 
 	bool is_foreign         = e->Procedure.is_foreign;
 	bool is_foreign         = e->Procedure.is_foreign;
 	bool is_export          = e->Procedure.is_export;
 	bool is_export          = e->Procedure.is_export;
-	bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
 
 
 	if (e->pkg != nullptr && e->token.string == "main") {
 	if (e->pkg != nullptr && e->token.string == "main") {
 		if (pt->param_count != 0 ||
 		if (pt->param_count != 0 ||
@@ -714,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 		}
 		}
 	}
 	}
 
 
-	if (pt->result_count == 0 && is_require_results) {
-		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 {
 	} else {
-		pt->require_results = is_require_results;
+		pt->require_results = ac.require_results;
 	}
 	}
 
 
 	if (ac.link_name.len > 0) {
 	if (ac.link_name.len > 0) {
@@ -791,7 +811,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 	}
 	}
 }
 }
 
 
-void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
+void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
 	GB_ASSERT(e->type == nullptr);
 	GB_ASSERT(e->type == nullptr);
 	GB_ASSERT(e->kind == Entity_Variable);
 	GB_ASSERT(e->kind == Entity_Variable);
 
 
@@ -805,6 +825,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
 	ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
 	ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
 
 
 	DeclInfo *decl = decl_info_of_entity(e);
 	DeclInfo *decl = decl_info_of_entity(e);
+	GB_ASSERT(decl == ctx->decl);
 	if (decl != nullptr) {
 	if (decl != nullptr) {
 		check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
 		check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
 	}
 	}
@@ -936,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
 
 
 	ptr_set_destroy(&entity_set);
 	ptr_set_destroy(&entity_set);
 
 
-
 	for_array(j, pge->entities) {
 	for_array(j, pge->entities) {
 		Entity *p = pge->entities[j];
 		Entity *p = pge->entities[j];
 		if (p->type == t_invalid) {
 		if (p->type == t_invalid) {
@@ -962,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
 			defer (end_error_block());
 			defer (end_error_block());
 
 
 			ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
 			ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
-			switch (kind) {
+			bool both_have_where_clauses = false;
+			if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
+				GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
+				GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
+				auto pl = &p->decl_info->proc_lit->ProcLit;
+				auto ql = &q->decl_info->proc_lit->ProcLit;
+
+				// Allow collisions if the procedures both have 'where' clauses and are both polymorphic
+				bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
+				bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
+				both_have_where_clauses = pw && qw;
+			}
+
+			if (!both_have_where_clauses) switch (kind) {
 			case ProcOverload_Identical:
 			case ProcOverload_Identical:
-				error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+				error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
 				is_invalid = true;
 				is_invalid = true;
 				break;
 				break;
 			// case ProcOverload_CallingConvention:
 			// case ProcOverload_CallingConvention:
-				// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+				// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
 				// is_invalid = true;
 				// is_invalid = true;
 				// break;
 				// break;
 			case ProcOverload_ParamVariadic:
 			case ProcOverload_ParamVariadic:
-				error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name));
+				error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
 				is_invalid = true;
 				is_invalid = true;
 				break;
 				break;
 			case ProcOverload_ResultCount:
 			case ProcOverload_ResultCount:
 			case ProcOverload_ResultTypes:
 			case ProcOverload_ResultTypes:
-				error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name));
+				error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
 				is_invalid = true;
 				is_invalid = true;
 				break;
 				break;
 			case ProcOverload_Polymorphic:
 			case ProcOverload_Polymorphic:
 				#if 0
 				#if 0
-				error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name));
+				error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
 				is_invalid = true;
 				is_invalid = true;
 				#endif
 				#endif
 				break;
 				break;
@@ -1051,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
 
 
 	switch (e->kind) {
 	switch (e->kind) {
 	case Entity_Variable:
 	case Entity_Variable:
-		check_var_decl(&c, e, d->type_expr, d->init_expr);
+		check_global_variable_decl(&c, e, d->type_expr, d->init_expr);
 		break;
 		break;
 	case Entity_Constant:
 	case Entity_Constant:
 		check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
 		check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
 		break;
 		break;
 	case Entity_TypeName: {
 	case Entity_TypeName: {
-		check_type_decl(&c, e, d->type_expr, named_type);
+		check_type_decl(&c, e, d->init_expr, named_type);
 		break;
 		break;
 	}
 	}
 	case Entity_Procedure:
 	case Entity_Procedure:
@@ -1074,6 +1107,11 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
 }
 }
 
 
 
 
+struct ProcUsingVar {
+	Entity *e;
+	Entity *uvar;
+};
+
 
 
 void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
 void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
 	if (body == nullptr) {
 	if (body == nullptr) {
@@ -1098,76 +1136,117 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
 	ctx->curr_proc_decl = decl;
 	ctx->curr_proc_decl = decl;
 	ctx->curr_proc_sig  = type;
 	ctx->curr_proc_sig  = type;
 
 
-	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);
 	check_scope_usage(ctx->checker, ctx->scope);
 
 
+#if 1
 	if (decl->parent != nullptr) {
 	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
 }
 }
 
 
 
 

File diff suppressed because it is too large
+ 602 - 48
src/check_expr.cpp


+ 192 - 29
src/check_stmt.cpp

@@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) {
 		}
 		}
 	case_end;
 	case_end;
 
 
+	case_ast_node(rs, InlineRangeStmt, node);
+		return false;
+	case_end;
+
 	case_ast_node(rs, RangeStmt, node);
 	case_ast_node(rs, RangeStmt, node);
 		return false;
 		return false;
 	case_end;
 	case_end;
@@ -492,8 +496,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
 			for_array(i, found->elements.entries) {
 			for_array(i, found->elements.entries) {
 				Entity *f = found->elements.entries[i].value;
 				Entity *f = found->elements.entries[i].value;
 				if (f->kind == Entity_Variable) {
 				if (f->kind == Entity_Variable) {
-					Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
-					uvar->using_expr = expr;
+					Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
 					Entity *prev = scope_insert(ctx->scope, uvar);
 					Entity *prev = scope_insert(ctx->scope, uvar);
 					if (prev != nullptr) {
 					if (prev != nullptr) {
 						gbString expr_str = expr_to_string(expr);
 						gbString expr_str = expr_to_string(expr);
@@ -587,6 +590,162 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
 	multi_map_insert(seen, key, tap);
 	multi_map_insert(seen, key, tap);
 }
 }
 
 
+void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
+	ast_node(irs, InlineRangeStmt, node);
+	check_open_scope(ctx, node);
+
+	Type *val0 = nullptr;
+	Type *val1 = nullptr;
+	Entity *entities[2] = {};
+	isize entity_count = 0;
+
+	Ast *expr = unparen_expr(irs->expr);
+
+	ExactValue inline_for_depth = exact_value_i64(0);
+
+	if (is_ast_range(expr)) {
+		ast_node(ie, BinaryExpr, expr);
+		Operand x = {};
+		Operand y = {};
+
+		bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
+		if (!ok) {
+			goto skip_expr;
+		}
+
+		val0 = x.type;
+		val1 = t_int;
+	} else {
+		Operand operand = {Addressing_Invalid};
+		check_expr_or_type(ctx, &operand, irs->expr);
+
+		if (operand.mode == Addressing_Type) {
+			if (!is_type_enum(operand.type)) {
+				gbString t = type_to_string(operand.type);
+				error(operand.expr, "Cannot iterate over the type '%s'", t);
+				gb_string_free(t);
+				goto skip_expr;
+			} else {
+				val0 = operand.type;
+				val1 = t_int;
+				add_type_info_type(ctx, operand.type);
+
+				Type *bt = base_type(operand.type);
+				inline_for_depth = exact_value_i64(bt->Enum.fields.count);
+				goto skip_expr;
+			}
+		} else if (operand.mode != Addressing_Invalid) {
+			Type *t = base_type(operand.type);
+			switch (t->kind) {
+			case Type_Basic:
+				if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
+					val0 = t_rune;
+					val1 = t_int;
+					inline_for_depth = exact_value_i64(operand.value.value_string.len);
+				}
+				break;
+			case Type_Array:
+				val0 = t->Array.elem;
+				val1 = t_int;
+				inline_for_depth = exact_value_i64(t->Array.count);
+				break;
+			}
+		}
+
+		if (val0 == nullptr) {
+			gbString s = expr_to_string(operand.expr);
+			gbString t = type_to_string(operand.type);
+			error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t);
+			gb_string_free(t);
+			gb_string_free(s);
+		} else if (operand.mode != Addressing_Constant) {
+			error(operand.expr, "An 'inline for' expression must be known at compile time");
+		}
+	}
+
+	skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
+
+	Ast * lhs[2] = {irs->val0, irs->val1};
+	Type *rhs[2] = {val0, val1};
+
+	for (isize i = 0; i < 2; i++) {
+		if (lhs[i] == nullptr) {
+			continue;
+		}
+		Ast * name = lhs[i];
+		Type *type = rhs[i];
+
+		Entity *entity = nullptr;
+		if (name->kind == Ast_Ident) {
+			Token token = name->Ident.token;
+			String str = token.string;
+			Entity *found = nullptr;
+
+			if (!is_blank_ident(str)) {
+				found = scope_lookup_current(ctx->scope, str);
+			}
+			if (found == nullptr) {
+				bool is_immutable = true;
+				entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved);
+				entity->flags |= EntityFlag_Value;
+				add_entity_definition(&ctx->checker->info, name, entity);
+			} else {
+				TokenPos pos = found->token.pos;
+				error(token,
+				      "Redeclaration of '%.*s' in this scope\n"
+				      "\tat %.*s(%td:%td)",
+				      LIT(str), LIT(pos.file), pos.line, pos.column);
+				entity = found;
+			}
+		} else {
+			error(name, "A variable declaration must be an identifier");
+		}
+
+		if (entity == nullptr) {
+			entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name));
+		}
+
+		entities[entity_count++] = entity;
+
+		if (type == nullptr) {
+			entity->type = t_invalid;
+			entity->flags |= EntityFlag_Used;
+		}
+	}
+
+	for (isize i = 0; i < entity_count; i++) {
+		add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
+	}
+
+
+	// NOTE(bill): Minimize the amount of nesting of an 'inline for'
+	i64 prev_inline_for_depth = ctx->inline_for_depth;
+	defer (ctx->inline_for_depth = prev_inline_for_depth);
+	{
+		i64 v = exact_value_to_i64(inline_for_depth);
+		if (v <= 0) {
+			// Do nothing
+		} else {
+			ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v;
+		}
+
+		if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
+			if (prev_inline_for_depth > 0) {
+				error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
+			} else {
+				error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
+			}
+			error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n");
+			ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH;
+		}
+	}
+
+	check_stmt(ctx, irs->body, mod_flags);
+
+
+	check_close_scope(ctx);
+}
+
 void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 	ast_node(ss, SwitchStmt, node);
 	ast_node(ss, SwitchStmt, node);
 
 
@@ -971,7 +1130,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 					GB_PANIC("Unknown type to type switch statement");
 					GB_PANIC("Unknown type to type switch statement");
 				}
 				}
 
 
-				if (ptr_set_exists(&seen, y.type)) {
+				if (type_ptr_set_exists(&seen, y.type)) {
 					TokenPos pos = cc->token.pos;
 					TokenPos pos = cc->token.pos;
 					gbString expr_str = expr_to_string(y.expr);
 					gbString expr_str = expr_to_string(y.expr);
 					error(y.expr,
 					error(y.expr,
@@ -1023,7 +1182,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 
 
 		for_array(i, variants) {
 		for_array(i, variants) {
 			Type *t = variants[i];
 			Type *t = variants[i];
-			if (!ptr_set_exists(&seen, t)) {
+			if (!type_ptr_set_exists(&seen, t)) {
 				array_add(&unhandled, t);
 				array_add(&unhandled, t);
 			}
 			}
 		}
 		}
@@ -1132,7 +1291,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 			isize rhs_count = rhs_operands.count;
 			isize rhs_count = rhs_operands.count;
 			for_array(i, rhs_operands) {
 			for_array(i, rhs_operands) {
 				if (rhs_operands[i].mode == Addressing_Invalid) {
 				if (rhs_operands[i].mode == Addressing_Invalid) {
-					rhs_count--;
+					// TODO(bill): Should I ignore invalid parameters?
+					// rhs_count--;
 				}
 				}
 			}
 			}
 
 
@@ -1168,7 +1328,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 			be->right = as->rhs[0];
 			be->right = as->rhs[0];
 
 
 			check_expr(ctx, &lhs, as->lhs[0]);
 			check_expr(ctx, &lhs, as->lhs[0]);
-			check_binary_expr(ctx, &rhs, &binary_expr, true);
+			check_binary_expr(ctx, &rhs, &binary_expr, nullptr, true);
 			if (rhs.mode == Addressing_Invalid) {
 			if (rhs.mode == Addressing_Invalid) {
 				return;
 				return;
 			}
 			}
@@ -1298,6 +1458,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 		check_close_scope(ctx);
 		check_close_scope(ctx);
 	case_end;
 	case_end;
 
 
+
 	case_ast_node(rs, RangeStmt, node);
 	case_ast_node(rs, RangeStmt, node);
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
 
 
@@ -1320,29 +1481,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 
 
 			check_expr(ctx, &x, ie->left);
 			check_expr(ctx, &x, ie->left);
 			if (x.mode == Addressing_Invalid) {
 			if (x.mode == Addressing_Invalid) {
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 			check_expr(ctx, &y, ie->right);
 			check_expr(ctx, &y, ie->right);
 			if (y.mode == Addressing_Invalid) {
 			if (y.mode == Addressing_Invalid) {
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 
 
 			convert_to_typed(ctx, &x, y.type);
 			convert_to_typed(ctx, &x, y.type);
 			if (x.mode == Addressing_Invalid) {
 			if (x.mode == Addressing_Invalid) {
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 			convert_to_typed(ctx, &y, x.type);
 			convert_to_typed(ctx, &y, x.type);
 			if (y.mode == Addressing_Invalid) {
 			if (y.mode == Addressing_Invalid) {
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 
 
 			convert_to_typed(ctx, &x, default_type(y.type));
 			convert_to_typed(ctx, &x, default_type(y.type));
 			if (x.mode == Addressing_Invalid) {
 			if (x.mode == Addressing_Invalid) {
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 			convert_to_typed(ctx, &y, default_type(x.type));
 			convert_to_typed(ctx, &y, default_type(x.type));
 			if (y.mode == Addressing_Invalid) {
 			if (y.mode == Addressing_Invalid) {
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 
 
 			if (!are_types_identical(x.type, y.type)) {
 			if (!are_types_identical(x.type, y.type)) {
@@ -1356,13 +1517,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					gb_string_free(yt);
 					gb_string_free(yt);
 					gb_string_free(xt);
 					gb_string_free(xt);
 				}
 				}
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 
 
 			Type *type = x.type;
 			Type *type = x.type;
 			if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
 			if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
 				error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
 				error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
-				goto skip_expr;
+				goto skip_expr_range_stmt;
 			}
 			}
 
 
 			if (x.mode == Addressing_Constant &&
 			if (x.mode == Addressing_Constant &&
@@ -1382,18 +1543,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 				if (!ok) {
 				if (!ok) {
 					// TODO(bill): Better error message
 					// TODO(bill): Better error message
 					error(ie->op, "Invalid interval range");
 					error(ie->op, "Invalid interval range");
-					goto skip_expr;
+					goto skip_expr_range_stmt;
 				}
 				}
 			}
 			}
 
 
-			if (x.mode != Addressing_Constant) {
-				x.value = empty_exact_value;
-			}
-			if (y.mode != Addressing_Constant) {
-				y.value = empty_exact_value;
-			}
-
-
 			add_type_and_value(&ctx->checker->info, ie->left,  x.mode, x.type, x.value);
 			add_type_and_value(&ctx->checker->info, ie->left,  x.mode, x.type, x.value);
 			add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
 			add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
 			val0 = type;
 			val0 = type;
@@ -1407,12 +1560,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					gbString t = type_to_string(operand.type);
 					gbString t = type_to_string(operand.type);
 					error(operand.expr, "Cannot iterate over the type '%s'", t);
 					error(operand.expr, "Cannot iterate over the type '%s'", t);
 					gb_string_free(t);
 					gb_string_free(t);
-					goto skip_expr;
+					goto skip_expr_range_stmt;
 				} else {
 				} else {
 					val0 = operand.type;
 					val0 = operand.type;
 					val1 = t_int;
 					val1 = t_int;
 					add_type_info_type(ctx, operand.type);
 					add_type_info_type(ctx, operand.type);
-					goto skip_expr;
+					goto skip_expr_range_stmt;
 				}
 				}
 			} else if (operand.mode != Addressing_Invalid) {
 			} else if (operand.mode != Addressing_Invalid) {
 				bool is_ptr = is_type_pointer(operand.type);
 				bool is_ptr = is_type_pointer(operand.type);
@@ -1457,7 +1610,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 			}
 			}
 		}
 		}
 
 
-	skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
+		skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
+
 		Ast * lhs[2] = {rs->val0, rs->val1};
 		Ast * lhs[2] = {rs->val0, rs->val1};
 		Type *rhs[2] = {val0, val1};
 		Type *rhs[2] = {val0, val1};
 
 
@@ -1507,7 +1661,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 		}
 		}
 
 
 		for (isize i = 0; i < entity_count; i++) {
 		for (isize i = 0; i < entity_count; i++) {
-			add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
+			Entity *e = entities[i];
+			DeclInfo *d = decl_info_of_entity(e);
+			GB_ASSERT(d == nullptr);
+			add_entity(ctx->checker, ctx->scope, e->identifier, e);
+			d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl);
+			add_entity_and_decl_info(ctx, e->identifier, e, d);
 		}
 		}
 
 
 		check_stmt(ctx, rs->body, new_flags);
 		check_stmt(ctx, rs->body, new_flags);
@@ -1515,6 +1674,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 		check_close_scope(ctx);
 		check_close_scope(ctx);
 	case_end;
 	case_end;
 
 
+	case_ast_node(irs, InlineRangeStmt, node);
+		check_inline_range_stmt(ctx, node, mod_flags);
+	case_end;
+
 	case_ast_node(ss, SwitchStmt, node);
 	case_ast_node(ss, SwitchStmt, node);
 		check_switch_stmt(ctx, node, mod_flags);
 		check_switch_stmt(ctx, node, mod_flags);
 	case_end;
 	case_end;
@@ -1814,7 +1977,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 					// TODO(bill): Should a 'continue' happen here?
 					// TODO(bill): Should a 'continue' happen here?
 				}
 				}
 
 
-				for (isize entity_index = 0; entity_index < entity_count; entity_index++) {
+				for (isize entity_index = 0; entity_index < 1; entity_index++) {
 					Entity *e = entities[entity_index];
 					Entity *e = entities[entity_index];
 					if (e == nullptr) {
 					if (e == nullptr) {
 						continue;
 						continue;
@@ -1833,7 +1996,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 						for_array(i, scope->elements.entries) {
 						for_array(i, scope->elements.entries) {
 							Entity *f = scope->elements.entries[i].value;
 							Entity *f = scope->elements.entries[i].value;
 							if (f->kind == Entity_Variable) {
 							if (f->kind == Entity_Variable) {
-								Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
+								Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
 								uvar->Variable.is_immutable = is_immutable;
 								uvar->Variable.is_immutable = is_immutable;
 								Entity *prev = scope_insert(ctx->scope, uvar);
 								Entity *prev = scope_insert(ctx->scope, uvar);
 								if (prev != nullptr) {
 								if (prev != nullptr) {

+ 360 - 40
src/check_type.cpp

@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
 	return false;
 	return false;
 }
 }
 
 
-void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const &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) {
                          isize init_field_capacity, Type *struct_type, String context) {
 	*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
 	*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
+	*tags   = array_make<String>(heap_allocator(), 0, init_field_capacity);
 
 
 	GB_ASSERT(node->kind == Ast_StructType);
 	GB_ASSERT(node->kind == Ast_StructType);
 	GB_ASSERT(struct_type->kind == Type_Struct);
 	GB_ASSERT(struct_type->kind == Type_Struct);
@@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
 			Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
 			Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
 			add_entity(ctx->checker, ctx->scope, name, field);
 			add_entity(ctx->checker, ctx->scope, name, field);
 			array_add(fields, field);
 			array_add(fields, field);
+			array_add(tags, p->tag.string);
 
 
 			field_src_index += 1;
 			field_src_index += 1;
 		}
 		}
@@ -246,38 +248,51 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
 }
 }
 
 
 
 
-Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
+Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
 	auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
 	auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
 	if (found_gen_types != nullptr) {
 	if (found_gen_types != nullptr) {
 		for_array(i, *found_gen_types) {
 		for_array(i, *found_gen_types) {
 			Entity *e = (*found_gen_types)[i];
 			Entity *e = (*found_gen_types)[i];
 			Type *t = base_type(e->type);
 			Type *t = base_type(e->type);
 			TypeTuple *tuple = get_record_polymorphic_params(t);
 			TypeTuple *tuple = get_record_polymorphic_params(t);
-			bool ok = true;
 			GB_ASSERT(param_count == tuple->variables.count);
 			GB_ASSERT(param_count == tuple->variables.count);
+
+			bool skip = false;
+
 			for (isize j = 0; j < param_count; j++) {
 			for (isize j = 0; j < param_count; j++) {
 				Entity *p = tuple->variables[j];
 				Entity *p = tuple->variables[j];
 				Operand o = ordered_operands[j];
 				Operand o = ordered_operands[j];
+				Entity *oe = entity_of_node(o.expr);
+				if (p == oe) {
+					// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
+					// Saves on a lot of checking too below
+					continue;
+				}
+
 				if (p->kind == Entity_TypeName) {
 				if (p->kind == Entity_TypeName) {
 					if (is_type_polymorphic(o.type)) {
 					if (is_type_polymorphic(o.type)) {
 						// NOTE(bill): Do not add polymorphic version to the gen_types
 						// NOTE(bill): Do not add polymorphic version to the gen_types
-						ok = false;
+						skip = true;
+						break;
 					}
 					}
 					if (!are_types_identical(o.type, p->type)) {
 					if (!are_types_identical(o.type, p->type)) {
-						ok = false;
+						skip = true;
+						break;
 					}
 					}
 				} else if (p->kind == Entity_Constant) {
 				} else if (p->kind == Entity_Constant) {
-					if (!are_types_identical(o.type, p->type)) {
-						ok = false;
-					}
 					if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
 					if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
-						ok = false;
+						skip = true;
+						break;
+					}
+					if (!are_types_identical(o.type, p->type)) {
+						skip = true;
+						break;
 					}
 					}
 				} else {
 				} else {
 					GB_PANIC("Unknown entity kind");
 					GB_PANIC("Unknown entity kind");
 				}
 				}
 			}
 			}
-			if (ok) {
+			if (!skip) {
 				return e;
 				return e;
 			}
 			}
 		}
 		}
@@ -439,8 +454,6 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 					if (poly_operands != nullptr) {
 					if (poly_operands != nullptr) {
 						Operand operand = (*poly_operands)[entities.count];
 						Operand operand = (*poly_operands)[entities.count];
 						if (is_type_param) {
 						if (is_type_param) {
-							GB_ASSERT(operand.mode == Addressing_Type ||
-							          operand.mode == Addressing_Invalid);
 							if (is_type_polymorphic(base_type(operand.type))) {
 							if (is_type_polymorphic(base_type(operand.type))) {
 								is_polymorphic = true;
 								is_polymorphic = true;
 								can_check_fields = false;
 								can_check_fields = false;
@@ -448,6 +461,10 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 							e = alloc_entity_type_name(scope, token, operand.type);
 							e = alloc_entity_type_name(scope, token, operand.type);
 							e->TypeName.is_type_alias = true;
 							e->TypeName.is_type_alias = true;
 						} else {
 						} else {
+							if (is_type_polymorphic(base_type(operand.type))) {
+								is_polymorphic = true;
+								can_check_fields = false;
+							}
 							e = alloc_entity_constant(scope, token, operand.type, operand.value);
 							e = alloc_entity_constant(scope, token, operand.type, operand.value);
 						}
 						}
 					} else {
 					} else {
@@ -502,9 +519,13 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
 	struct_type->Struct.polymorphic_params      = polymorphic_params;
 	struct_type->Struct.polymorphic_params      = polymorphic_params;
 	struct_type->Struct.is_poly_specialized     = is_poly_specialized;
 	struct_type->Struct.is_poly_specialized     = is_poly_specialized;
 
 
-
 	if (!is_polymorphic) {
 	if (!is_polymorphic) {
-		check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context);
+		if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
+			error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters");
+		} else {
+			bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true);
+		}
+		check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
 	}
 	}
 
 
 	if (st->align != nullptr) {
 	if (st->align != nullptr) {
@@ -686,6 +707,13 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
 	union_type->Union.is_polymorphic          = is_polymorphic;
 	union_type->Union.is_polymorphic          = is_polymorphic;
 	union_type->Union.is_poly_specialized     = is_poly_specialized;
 	union_type->Union.is_poly_specialized     = is_poly_specialized;
 
 
+	if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
+		error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
+	} else {
+		bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true);
+	}
+
+
 	for_array(i, ut->variants) {
 	for_array(i, ut->variants) {
 		Ast *node = ut->variants[i];
 		Ast *node = ut->variants[i];
 		Type *t = check_type_expr(ctx, node, nullptr);
 		Type *t = check_type_expr(ctx, node, nullptr);
@@ -1252,20 +1280,21 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
 
 
 Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) {
 Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) {
 	bool modify_type = !ctx->no_polymorphic_errors;
 	bool modify_type = !ctx->no_polymorphic_errors;
+	bool show_error = modify_type && !ctx->hide_polymorphic_errors;
 	if (!is_operand_value(operand)) {
 	if (!is_operand_value(operand)) {
-		if (modify_type) {
+		if (show_error) {
 			error(operand.expr, "Cannot determine polymorphic type from parameter");
 			error(operand.expr, "Cannot determine polymorphic type from parameter");
 		}
 		}
 		return t_invalid;
 		return t_invalid;
 	}
 	}
 
 
 	if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
 	if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
-		if (modify_type) {
-			set_procedure_abi_types(ctx, poly_type);
+		if (show_error) {
+			set_procedure_abi_types(ctx->allocator, poly_type);
 		}
 		}
 		return poly_type;
 		return poly_type;
 	}
 	}
-	if (modify_type) {
+	if (show_error) {
 		gbString pts = type_to_string(poly_type);
 		gbString pts = type_to_string(poly_type);
 		gbString ots = type_to_string(operand.type);
 		gbString ots = type_to_string(operand.type);
 		defer (gb_string_free(pts));
 		defer (gb_string_free(pts));
@@ -1538,7 +1567,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
 			}
 			}
 
 
 			if (is_poly_name) {
 			if (is_poly_name) {
-				if (type != nullptr && type_expr->kind == Ast_TypeidType) {
+				if (type_expr != nullptr && type_expr->kind == Ast_TypeidType) {
 					is_type_param = true;
 					is_type_param = true;
 				} else {
 				} else {
 					if (param_value.kind != ParameterValue_Invalid)  {
 					if (param_value.kind != ParameterValue_Invalid)  {
@@ -1622,6 +1651,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
 						if (op.mode == Addressing_Constant) {
 						if (op.mode == Addressing_Constant) {
 							poly_const = op.value;
 							poly_const = op.value;
 						} else {
 						} else {
+							error(op.expr, "Expected a constant value for this polymorphic name parameter");
 							success = false;
 							success = false;
 						}
 						}
 					}
 					}
@@ -1825,6 +1855,282 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
 	return tuple;
 	return tuple;
 }
 }
 
 
+Array<Type *> systemv_distribute_struct_fields(Type *t) {
+	Type *bt = core_type(t);
+
+
+	isize distributed_cap = 1;
+	if (bt->kind == Type_Struct) {
+		distributed_cap = bt->Struct.fields.count;
+	}
+	auto distributed = array_make<Type *>(heap_allocator(), 0, distributed_cap);
+
+	i64 sz = type_size_of(bt);
+	switch (bt->kind) {
+	case Type_Basic:
+		switch (bt->Basic.kind){
+		case Basic_complex64:
+			array_add(&distributed, t_f32);
+			array_add(&distributed, t_f32);
+			break;
+		case Basic_complex128:
+			array_add(&distributed, t_f64);
+			array_add(&distributed, t_f64);
+			break;
+		case Basic_quaternion128:
+			array_add(&distributed, t_f32);
+			array_add(&distributed, t_f32);
+			array_add(&distributed, t_f32);
+			array_add(&distributed, t_f32);
+			break;
+		case Basic_quaternion256:
+			goto DEFAULT;
+		case Basic_string:
+			array_add(&distributed, t_u8_ptr);
+			array_add(&distributed, t_int);
+			break;
+		case Basic_any:
+			GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid));
+			array_add(&distributed, t_rawptr);
+			array_add(&distributed, t_uintptr);
+			break;
+
+		case Basic_u128:
+		case Basic_i128:
+			if (build_context.ODIN_OS == "windows") {
+				array_add(&distributed, alloc_type_simd_vector(2, t_u64));
+			} else {
+				array_add(&distributed, bt);
+			}
+			break;
+
+		default:
+			goto DEFAULT;
+		}
+		break;
+
+	case Type_Struct:
+		if (bt->Struct.is_raw_union) {
+			goto DEFAULT;
+		} else {
+			// IMPORTANT TOOD(bill): handle #packed structs correctly
+			// IMPORTANT TODO(bill): handle #align structs correctly
+			for_array(field_index, bt->Struct.fields) {
+				Entity *f = bt->Struct.fields[field_index];
+				auto nested = systemv_distribute_struct_fields(f->type);
+				array_add_elems(&distributed, nested.data, nested.count);
+				array_free(&nested);
+			}
+		}
+		break;
+
+	case Type_Array:
+		for (i64 i = 0; i < bt->Array.count; i++) {
+			array_add(&distributed, bt->Array.elem);
+		}
+		break;
+
+	case Type_BitSet:
+		array_add(&distributed, bit_set_to_int(bt));
+		break;
+
+	case Type_Tuple:
+		GB_PANIC("Invalid struct field type");
+		break;
+
+	case Type_Slice:
+		array_add(&distributed, t_rawptr);
+		array_add(&distributed, t_int);
+		break;
+
+	case Type_Union:
+	case Type_DynamicArray:
+	case Type_Map:
+	case Type_BitField: // TODO(bill): Ignore?
+		// NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet
+		goto DEFAULT;
+
+	case Type_Pointer:
+	case Type_Proc:
+	case Type_SimdVector: // TODO(bill): Is this correct logic?
+	default:
+	DEFAULT:;
+		if (sz > 0) {
+			array_add(&distributed, bt);
+		}
+		break;
+	}
+
+	return distributed;
+}
+
+Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) {
+	GB_ASSERT(is_type_tuple(abi_type));
+	Type *final_type = alloc_type_struct();
+	final_type->Struct.fields = abi_type->Tuple.variables;
+	return final_type;
+}
+
+
+Type *handle_single_distributed_type_parameter(Array<Type *> const &types, bool packed, isize *offset) {
+	GB_ASSERT(types.count > 0);
+
+	if (types.count == 1) {
+		if (offset) *offset = 1;
+
+		i64 sz = type_size_of(types[0]);
+
+		if (is_type_float(types[0])) {
+			return types[0];
+		}
+		switch (sz) {
+		case 0:
+			GB_PANIC("Zero sized type found!");
+		case 1: return t_u8;
+		case 2: return t_u16;
+		case 4: return t_u32;
+		case 8: return t_u64;
+		default:
+			return types[0];
+		}
+	} else if (types.count >= 2) {
+	    if (types[0] == t_f32 && types[1] == t_f32) {
+	    	if (offset) *offset = 2;
+			return alloc_type_simd_vector(2, t_f32);
+		} else if (type_size_of(types[0]) == 8) {
+	    	if (offset) *offset = 1;
+			return types[0];
+		}
+
+		i64 total_size = 0;
+		isize i = 0;
+		if (packed) {
+			for (; i < types.count && total_size < 8; i += 1) {
+				Type *t = types[i];
+				i64 s = type_size_of(t);
+				total_size += s;
+			}
+		} else {
+			for (; i < types.count && total_size < 8; i += 1) {
+				Type *t = types[i];
+				i64 s = gb_max(type_size_of(t), 0);
+				i64 a = gb_max(type_align_of(t), 1);
+				isize ts = align_formula(total_size, a);
+				if (ts >= 8) {
+					break;
+				}
+				total_size = ts + s;
+			}
+		}
+		if (offset) *offset = i;
+		switch (total_size) {
+		case 1: return t_u8;
+		case 2: return t_u16;
+		case 4: return t_u32;
+		case 8: return t_u64;
+		}
+		return t_u64;
+	}
+
+	return nullptr;
+}
+
+Type *handle_struct_system_v_amd64_abi_type(Type *t) {
+	if (type_size_of(t) > 16) {
+		return alloc_type_pointer(t);
+	}
+	Type *original_type = t;
+	Type *bt = core_type(t);
+	t = base_type(t);
+	i64 size = type_size_of(bt);
+
+	switch (t->kind) {
+	case Type_Slice:
+	case Type_Struct:
+		break;
+
+	case Type_Basic:
+		switch (bt->Basic.kind) {
+		case Basic_string:
+		case Basic_any:
+		case Basic_complex64:
+		case Basic_complex128:
+		case Basic_quaternion128:
+			break;
+		default:
+			return original_type;
+		}
+		break;
+
+	default:
+		return original_type;
+	}
+
+	bool is_packed = false;
+	if (is_type_struct(bt)) {
+		is_packed = bt->Struct.is_packed;
+	}
+
+	if (is_type_raw_union(bt)) {
+		// TODO(bill): Handle raw union correctly for
+		return t;
+	} else {
+		auto field_types = systemv_distribute_struct_fields(bt);
+		defer (array_free(&field_types));
+
+		GB_ASSERT(field_types.count <= 16);
+
+		Type *final_type = nullptr;
+
+		if (field_types.count == 0) {
+			final_type = t;
+		} else if (field_types.count == 1) {
+			final_type = field_types[0];
+		} else {
+			if (size <= 8) {
+				isize offset = 0;
+				final_type = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
+			} else {
+				isize offset = 0;
+				isize next_offset = 0;
+				Type *two_types[2] = {};
+
+				two_types[0] = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
+				auto remaining = array_slice(field_types, offset, field_types.count);
+				two_types[1] = handle_single_distributed_type_parameter(remaining, is_packed, &next_offset);
+				GB_ASSERT(offset + next_offset == field_types.count);
+
+				auto variables = array_make<Entity *>(heap_allocator(), 2);
+				variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false);
+				variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false);
+				final_type = alloc_type_tuple();
+				final_type->Tuple.variables = variables;
+				if (t->kind == Type_Struct) {
+					// NOTE(bill): Make this packed
+					final_type->Tuple.is_packed = t->Struct.is_packed;
+				}
+			}
+		}
+
+
+		GB_ASSERT(final_type != nullptr);
+		i64 ftsz = type_size_of(final_type);
+		i64 otsz = type_size_of(original_type);
+		if (ftsz != otsz) {
+			// TODO(bill): Handle this case which will be caused by #packed most likely
+			switch (otsz) {
+			case 1:
+			case 2:
+			case 4:
+			case 8:
+				GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %s %lld vs %s %lld", type_to_string(final_type), ftsz, type_to_string(original_type), otsz);
+			}
+		}
+
+		return final_type;
+	}
+}
+
 Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
 Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
 	Type *new_type = original_type;
 	Type *new_type = original_type;
 
 
@@ -1889,6 +2195,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
 		{
 		{
 			i64 align = type_align_of(original_type);
 			i64 align = type_align_of(original_type);
 			i64 size  = type_size_of(original_type);
 			i64 size  = type_size_of(original_type);
+
 			switch (8*size) {
 			switch (8*size) {
 			case 8:  new_type = t_u8;  break;
 			case 8:  new_type = t_u8;  break;
 			case 16: new_type = t_u16; break;
 			case 16: new_type = t_u16; break;
@@ -1903,7 +2210,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
 		}
 		}
 		}
 		}
 	} else if (build_context.ODIN_OS == "linux" ||
 	} else if (build_context.ODIN_OS == "linux" ||
-	           build_context.ODIN_OS == "osx") {
+	           build_context.ODIN_OS == "darwin") {
 		Type *bt = core_type(original_type);
 		Type *bt = core_type(original_type);
 		switch (bt->kind) {
 		switch (bt->kind) {
 		// Okay to pass by value (usually)
 		// Okay to pass by value (usually)
@@ -1920,18 +2227,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
 		case Type_Pointer: break;
 		case Type_Pointer: break;
 		case Type_Proc:    break; // NOTE(bill): Just a pointer
 		case Type_Proc:    break; // NOTE(bill): Just a pointer
 
 
-		// Odin specific
-		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);
 				new_type = alloc_type_pointer(original_type);
+			} else if (build_context.ODIN_ARCH == "amd64") {
+				// NOTE(bill): System V AMD64 ABI
+				new_type = handle_struct_system_v_amd64_abi_type(bt);
+				if (are_types_identical(core_type(original_type), new_type)) {
+					new_type = original_type;
+				}
+				return new_type;
 			}
 			}
 
 
 			break;
 			break;
@@ -2004,8 +2310,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
 			break;
 			break;
 		}
 		}
 		}
 		}
-	} else if (build_context.ODIN_OS == "linux") {
+	} else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") {
+		if (build_context.ODIN_ARCH == "amd64") {
 
 
+		}
 	} else {
 	} else {
 		// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
 		// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
 		// their architectures
 		// their architectures
@@ -2071,25 +2379,39 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
 	return false;
 	return false;
 }
 }
 
 
-void set_procedure_abi_types(CheckerContext *c, Type *type) {
+void set_procedure_abi_types(gbAllocator allocator, Type *type) {
 	type = base_type(type);
 	type = base_type(type);
 	if (type->kind != Type_Proc) {
 	if (type->kind != Type_Proc) {
 		return;
 		return;
 	}
 	}
 
 
-	type->Proc.abi_compat_params = array_make<Type *>(c->allocator, cast(isize)type->Proc.param_count);
+	if (type->Proc.abi_types_set) {
+		return;
+	}
+
+	type->Proc.abi_compat_params = array_make<Type *>(allocator, cast(isize)type->Proc.param_count);
 	for (i32 i = 0; i < type->Proc.param_count; i++) {
 	for (i32 i = 0; i < type->Proc.param_count; i++) {
 		Entity *e = type->Proc.params->Tuple.variables[i];
 		Entity *e = type->Proc.params->Tuple.variables[i];
 		if (e->kind == Entity_Variable) {
 		if (e->kind == Entity_Variable) {
 			Type *original_type = e->type;
 			Type *original_type = e->type;
-			Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention);
+			Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention);
 			type->Proc.abi_compat_params[i] = new_type;
 			type->Proc.abi_compat_params[i] = new_type;
+			switch (type->Proc.calling_convention) {
+			case ProcCC_Odin:
+			case ProcCC_Contextless:
+				if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
+					e->flags |= EntityFlag_ImplicitReference;
+				}
+				break;
+			}
 		}
 		}
 	}
 	}
 
 
 	// NOTE(bill): The types are the same
 	// NOTE(bill): The types are the same
-	type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention);
-	type->Proc.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
 // NOTE(bill): 'operands' is for generating non generic procedure type
@@ -2187,8 +2509,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
 	}
 	}
 	type->Proc.is_polymorphic = is_polymorphic;
 	type->Proc.is_polymorphic = is_polymorphic;
 
 
-	set_procedure_abi_types(c, type);
-
 	return success;
 	return success;
 }
 }
 
 
@@ -2537,7 +2857,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 				generic_type = o.type;
 				generic_type = o.type;
 			}
 			}
 			if (count < 0) {
 			if (count < 0) {
-				error(at->count, "... can only be used in conjuction with compound literals");
+				error(at->count, "? can only be used in conjuction with compound literals");
 				count = 0;
 				count = 0;
 			}
 			}
 			Type *elem = check_type_expr(ctx, at->elem, nullptr);
 			Type *elem = check_type_expr(ctx, at->elem, nullptr);

+ 119 - 47
src/checker.cpp

@@ -85,9 +85,13 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) {
 	EntityGraphNode *y = data[j];
 	EntityGraphNode *y = data[j];
 	isize a = x->entity->order_in_src;
 	isize a = x->entity->order_in_src;
 	isize b = y->entity->order_in_src;
 	isize b = y->entity->order_in_src;
-	if (x->dep_count < y->dep_count) return -1;
-	if (x->dep_count > y->dep_count) 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) {
 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) {
 	if (found) {
 		return *found;
 		return *found;
 	}
 	}
+	if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
+		Entity **found = map_get(&s->parent->elements, key);
+		if (found) {
+			if ((*found)->flags & EntityFlag_Result) {
+				return *found;
+			}
+		}
+	}
+
 	map_set(&s->elements, key, entity);
 	map_set(&s->elements, key, entity);
 	if (entity->scope == nullptr) {
 	if (entity->scope == nullptr) {
 		entity->scope = s;
 		entity->scope = s;
@@ -1044,21 +1057,37 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) {
 			// NOTE(bill): Error should have been handled already
 			// NOTE(bill): Error should have been handled already
 			return false;
 			return false;
 		}
 		}
-		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 {
 	} else {
 		if (pos == prev->token.pos) {
 		if (pos == prev->token.pos) {
 			// NOTE(bill): Error should have been handled already
 			// NOTE(bill): Error should have been handled already
 			return false;
 			return false;
 		}
 		}
-		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;
 	return false;
 }
 }
@@ -1139,6 +1168,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec
 	add_entity_definition(&c->checker->info, identifier, e);
 	add_entity_definition(&c->checker->info, identifier, e);
 	GB_ASSERT(e->decl_info == nullptr);
 	GB_ASSERT(e->decl_info == nullptr);
 	e->decl_info = d;
 	e->decl_info = d;
+	d->entity = e;
 	array_add(&c->checker->info.entities, e);
 	array_add(&c->checker->info.entities, e);
 	e->order_in_src = c->checker->info.entities.count;
 	e->order_in_src = c->checker->info.entities.count;
 	e->pkg = c->pkg;
 	e->pkg = c->pkg;
@@ -1415,6 +1445,14 @@ void add_min_dep_type_info(Checker *c, Type *t) {
 			add_min_dep_type_info(c, t_type_info_float);
 			add_min_dep_type_info(c, t_type_info_float);
 			add_min_dep_type_info(c, t_f64);
 			add_min_dep_type_info(c, t_f64);
 			break;
 			break;
+		case Basic_quaternion128:
+			add_min_dep_type_info(c, t_type_info_float);
+			add_min_dep_type_info(c, t_f32);
+			break;
+		case Basic_quaternion256:
+			add_min_dep_type_info(c, t_type_info_float);
+			add_min_dep_type_info(c, t_f64);
+			break;
 		}
 		}
 		break;
 		break;
 
 
@@ -1577,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 
 
 		str_lit("args__"),
 		str_lit("args__"),
 		str_lit("type_table"),
 		str_lit("type_table"),
+		str_lit("__type_info_of"),
 		str_lit("global_scratch_allocator"),
 		str_lit("global_scratch_allocator"),
 
 
 		str_lit("Type_Info"),
 		str_lit("Type_Info"),
@@ -1585,9 +1624,17 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 
 
 		str_lit("quo_complex64"),
 		str_lit("quo_complex64"),
 		str_lit("quo_complex128"),
 		str_lit("quo_complex128"),
+		str_lit("mul_quaternion128"),
+		str_lit("mul_quaternion256"),
+		str_lit("quo_quaternion128"),
+		str_lit("quo_quaternion256"),
+		str_lit("cstring_to_string"),
 
 
 		str_lit("umodti3"),
 		str_lit("umodti3"),
 		str_lit("udivti3"),
 		str_lit("udivti3"),
+
+		str_lit("memory_compare"),
+		str_lit("memory_compare_zero"),
 	};
 	};
 	for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
 	for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
 		add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
 		add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
@@ -1656,9 +1703,10 @@ bool is_entity_a_dependency(Entity *e) {
 	if (e == nullptr) return false;
 	if (e == nullptr) return false;
 	switch (e->kind) {
 	switch (e->kind) {
 	case Entity_Procedure:
 	case Entity_Procedure:
-	case Entity_Variable:
-	case Entity_Constant:
 		return true;
 		return true;
+	case Entity_Constant:
+	case Entity_Variable:
+		return e->pkg != nullptr;
 	}
 	}
 	return false;
 	return false;
 }
 }
@@ -1685,18 +1733,17 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
 		EntityGraphNode *n = M.entries[i].value;
 		EntityGraphNode *n = M.entries[i].value;
 
 
 		DeclInfo *decl = decl_info_of_entity(e);
 		DeclInfo *decl = decl_info_of_entity(e);
-		if (decl != nullptr) {
-			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];
 		EntityGraphNode *n = G[i];
 		n->index = i;
 		n->index = i;
 		n->dep_count = n->succ.entries.count;
 		n->dep_count = n->succ.entries.count;
+
 		GB_ASSERT(n->dep_count >= 0);
 		GB_ASSERT(n->dep_count >= 0);
 	}
 	}
 
 
@@ -1863,6 +1911,7 @@ void init_core_type_info(Checker *c) {
 	t_type_info_integer       = find_core_type(c, str_lit("Type_Info_Integer"));
 	t_type_info_integer       = find_core_type(c, str_lit("Type_Info_Integer"));
 	t_type_info_rune          = find_core_type(c, str_lit("Type_Info_Rune"));
 	t_type_info_rune          = find_core_type(c, str_lit("Type_Info_Rune"));
 	t_type_info_float         = find_core_type(c, str_lit("Type_Info_Float"));
 	t_type_info_float         = find_core_type(c, str_lit("Type_Info_Float"));
+	t_type_info_quaternion    = find_core_type(c, str_lit("Type_Info_Quaternion"));
 	t_type_info_complex       = find_core_type(c, str_lit("Type_Info_Complex"));
 	t_type_info_complex       = find_core_type(c, str_lit("Type_Info_Complex"));
 	t_type_info_string        = find_core_type(c, str_lit("Type_Info_String"));
 	t_type_info_string        = find_core_type(c, str_lit("Type_Info_String"));
 	t_type_info_boolean       = find_core_type(c, str_lit("Type_Info_Boolean"));
 	t_type_info_boolean       = find_core_type(c, str_lit("Type_Info_Boolean"));
@@ -1887,6 +1936,7 @@ void init_core_type_info(Checker *c) {
 	t_type_info_integer_ptr       = alloc_type_pointer(t_type_info_integer);
 	t_type_info_integer_ptr       = alloc_type_pointer(t_type_info_integer);
 	t_type_info_rune_ptr          = alloc_type_pointer(t_type_info_rune);
 	t_type_info_rune_ptr          = alloc_type_pointer(t_type_info_rune);
 	t_type_info_float_ptr         = alloc_type_pointer(t_type_info_float);
 	t_type_info_float_ptr         = alloc_type_pointer(t_type_info_float);
+	t_type_info_quaternion_ptr    = alloc_type_pointer(t_type_info_quaternion);
 	t_type_info_complex_ptr       = alloc_type_pointer(t_type_info_complex);
 	t_type_info_complex_ptr       = alloc_type_pointer(t_type_info_complex);
 	t_type_info_string_ptr        = alloc_type_pointer(t_type_info_string);
 	t_type_info_string_ptr        = alloc_type_pointer(t_type_info_string);
 	t_type_info_boolean_ptr       = alloc_type_pointer(t_type_info_boolean);
 	t_type_info_boolean_ptr       = alloc_type_pointer(t_type_info_boolean);
@@ -2138,6 +2188,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 			error(elem, "Expected a string value for '%.*s'", LIT(name));
 			error(elem, "Expected a string value for '%.*s'", LIT(name));
 		}
 		}
 		return true;
 		return true;
+	} else if (name == "require_results") {
+		if (value != nullptr) {
+			error(elem, "Expected no value for '%.*s'", LIT(name));
+		}
+		ac->require_results = true;
+		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
@@ -2528,6 +2584,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 
 
 			Ast *init_expr = value;
 			Ast *init_expr = value;
 			DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
 			DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
+			d->entity    = e;
 			d->type_expr = vd->type;
 			d->type_expr = vd->type;
 			d->init_expr = init_expr;
 			d->init_expr = init_expr;
 			d->attributes = vd->attributes;
 			d->attributes = vd->attributes;
@@ -2557,14 +2614,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 			Entity *e = nullptr;
 			Entity *e = nullptr;
 
 
 			d->attributes = vd->attributes;
 			d->attributes = vd->attributes;
+			d->type_expr = vd->type;
+			d->init_expr = init;
 
 
 			if (is_ast_type(init)) {
 			if (is_ast_type(init)) {
 				e = alloc_entity_type_name(d->scope, token, nullptr);
 				e = alloc_entity_type_name(d->scope, token, nullptr);
-				if (vd->type != nullptr) {
-					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) {
 			} else if (init->kind == Ast_ProcLit) {
 				if (c->scope->flags&ScopeFlag_Type) {
 				if (c->scope->flags&ScopeFlag_Type) {
 					error(name, "Procedure declarations are not allowed within a struct");
 					error(name, "Procedure declarations are not allowed within a struct");
@@ -2591,19 +2648,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 					pl->type->ProcType.calling_convention = cc;
 					pl->type->ProcType.calling_convention = cc;
 				}
 				}
 				d->proc_lit = init;
 				d->proc_lit = init;
-				d->type_expr = vd->type;
+				d->init_expr = init;
 			} else if (init->kind == Ast_ProcGroup) {
 			} else if (init->kind == Ast_ProcGroup) {
 				ast_node(pg, ProcGroup, init);
 				ast_node(pg, ProcGroup, init);
 				e = alloc_entity_proc_group(d->scope, token, nullptr);
 				e = alloc_entity_proc_group(d->scope, token, nullptr);
 				if (fl != nullptr) {
 				if (fl != nullptr) {
 					error(name, "Procedure groups are not allowed within a foreign block");
 					error(name, "Procedure groups are not allowed within a foreign block");
 				}
 				}
-				d->init_expr = init;
-				d->type_expr = vd->type;
 			} else {
 			} else {
 				e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
 				e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
-				d->type_expr = vd->type;
-				d->init_expr = init;
 			}
 			}
 			e->identifier = name;
 			e->identifier = name;
 
 
@@ -3101,7 +3154,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
 			Entity *e = scope->elements.entries[elem_index].value;
 			Entity *e = scope->elements.entries[elem_index].value;
 			if (e->scope == parent_scope) continue;
 			if (e->scope == parent_scope) continue;
 
 
-			if (is_entity_exported(e)) {
+			if (is_entity_exported(e, true)) {
 				Entity *found = scope_lookup_current(parent_scope, name);
 				Entity *found = scope_lookup_current(parent_scope, name);
 				if (found != nullptr) {
 				if (found != nullptr) {
 					// NOTE(bill):
 					// NOTE(bill):
@@ -3315,8 +3368,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
 			if (es->expr->kind == Ast_CallExpr) {
 			if (es->expr->kind == Ast_CallExpr) {
 				ast_node(ce, CallExpr, es->expr);
 				ast_node(ce, CallExpr, es->expr);
 				if (ce->proc->kind == Ast_BasicDirective) {
 				if (ce->proc->kind == Ast_BasicDirective) {
-					Operand o = {};
-					check_expr(ctx, &o, es->expr);
+					if (ctx->collect_delayed_decls) {
+						array_add(&ctx->scope->delayed_directives, es->expr);
+					}
 				}
 				}
 			}
 			}
 		case_end;
 		case_end;
@@ -3473,12 +3527,18 @@ void check_import_entities(Checker *c) {
 		for_array(i, pkg->files) {
 		for_array(i, pkg->files) {
 			AstFile *f = pkg->files[i];
 			AstFile *f = pkg->files[i];
 			CheckerContext ctx = c->init_ctx;
 			CheckerContext ctx = c->init_ctx;
-
 			add_curr_ast_file(&ctx, f);
 			add_curr_ast_file(&ctx, f);
+
 			for_array(j, f->scope->delayed_imports) {
 			for_array(j, f->scope->delayed_imports) {
 				Ast *decl = f->scope->delayed_imports[j];
 				Ast *decl = f->scope->delayed_imports[j];
 				check_add_import_decl(&ctx, decl);
 				check_add_import_decl(&ctx, decl);
 			}
 			}
+		}
+		for_array(i, pkg->files) {
+			AstFile *f = pkg->files[i];
+			CheckerContext ctx = c->init_ctx;
+			add_curr_ast_file(&ctx, f);
+
 			for_array(j, f->scope->delayed_directives) {
 			for_array(j, f->scope->delayed_directives) {
 				Ast *expr = f->scope->delayed_directives[j];
 				Ast *expr = f->scope->delayed_directives[j];
 				Operand o = {};
 				Operand o = {};
@@ -3542,7 +3602,6 @@ void calculate_global_init_order(Checker *c) {
 #define TIME_SECTION(str)
 #define TIME_SECTION(str)
 #endif
 #endif
 
 
-
 	CheckerInfo *info = &c->info;
 	CheckerInfo *info = &c->info;
 
 
 	TIME_SECTION("generate entity dependency graph");
 	TIME_SECTION("generate entity dependency graph");
@@ -3584,21 +3643,26 @@ void calculate_global_init_order(Checker *c) {
 
 
 		for_array(i, n->pred.entries) {
 		for_array(i, n->pred.entries) {
 			EntityGraphNode *p = n->pred.entries[i].ptr;
 			EntityGraphNode *p = n->pred.entries[i].ptr;
-			p->dep_count -= gb_max(p->dep_count-1, 0);
+			p->dep_count -= 1;
+			p->dep_count = gb_max(p->dep_count, 0);
 			priority_queue_fix(&pq, p->index);
 			priority_queue_fix(&pq, p->index);
 		}
 		}
 
 
-		if (e == nullptr || e->kind != Entity_Variable) {
+		DeclInfo *d = decl_info_of_entity(e);
+		if (e->kind != Entity_Variable) {
 			continue;
 			continue;
 		}
 		}
-		DeclInfo *d = decl_info_of_entity(e);
-
+		// IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering
+		// because it does not need any initialization other than zero
+		// if (!decl_info_has_init(d)) {
+		// 	continue;
+		// }
 		if (ptr_set_exists(&emitted, d)) {
 		if (ptr_set_exists(&emitted, d)) {
 			continue;
 			continue;
 		}
 		}
 		ptr_set_add(&emitted, d);
 		ptr_set_add(&emitted, d);
 
 
-		d->entity = e;
+
 		array_add(&info->variable_init_order, d);
 		array_add(&info->variable_init_order, d);
 	}
 	}
 
 
@@ -3637,6 +3701,14 @@ void check_proc_info(Checker *c, ProcInfo pi) {
 		return;
 		return;
 	}
 	}
 
 
+	if (pt->is_polymorphic && pt->is_poly_specialized) {
+		Entity *e = pi.decl->entity;
+		if ((e->flags & EntityFlag_Used) == 0) {
+			// NOTE(bill, 2019-08-31): It was never used, don't check
+			return;
+		}
+	}
+
 	bool bounds_check    = (pi.tags & ProcTag_bounds_check)    != 0;
 	bool bounds_check    = (pi.tags & ProcTag_bounds_check)    != 0;
 	bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
 	bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
 
 

+ 8 - 212
src/checker.hpp

@@ -59,218 +59,8 @@ struct BuiltinProc {
 	BuiltinProcPkg pkg;
 	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
 // Operand is used as an intermediate value whilst checking
@@ -307,6 +97,7 @@ struct DeferredProcedure {
 struct AttributeContext {
 struct AttributeContext {
 	bool    is_export;
 	bool    is_export;
 	bool    is_static;
 	bool    is_static;
+	bool    require_results;
 	String  link_name;
 	String  link_name;
 	String  link_prefix;
 	String  link_prefix;
 	isize   init_expr_list_count;
 	isize   init_expr_list_count;
@@ -431,6 +222,7 @@ struct ForeignContext {
 typedef Array<Entity *> CheckerTypePath;
 typedef Array<Entity *> CheckerTypePath;
 typedef Array<Type *>   CheckerPolyPath;
 typedef Array<Type *>   CheckerPolyPath;
 
 
+
 // CheckerInfo stores all the symbol information for a type-checked program
 // CheckerInfo stores all the symbol information for a type-checked program
 struct CheckerInfo {
 struct CheckerInfo {
 	Map<ExprInfo>         untyped; // Key: Ast * | Expression -> ExprInfo
 	Map<ExprInfo>         untyped; // Key: Ast * | Expression -> ExprInfo
@@ -486,10 +278,14 @@ struct CheckerContext {
 	CheckerPolyPath *poly_path;
 	CheckerPolyPath *poly_path;
 	isize            poly_level; // TODO(bill): Actually handle correctly
 	isize            poly_level; // TODO(bill): Actually handle correctly
 
 
+#define MAX_INLINE_FOR_DEPTH 1024ll
+	i64 inline_for_depth;
+
 	bool       in_enum_type;
 	bool       in_enum_type;
 	bool       collect_delayed_decls;
 	bool       collect_delayed_decls;
 	bool       allow_polymorphic_types;
 	bool       allow_polymorphic_types;
 	bool       no_polymorphic_errors;
 	bool       no_polymorphic_errors;
+	bool       hide_polymorphic_errors;
 	bool       in_polymorphic_specialization;
 	bool       in_polymorphic_specialization;
 	Scope *    polymorphic_scope;
 	Scope *    polymorphic_scope;
 };
 };

+ 320 - 0
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},
+};

+ 4 - 4
src/common.cpp

@@ -10,13 +10,11 @@
 #define GB_IMPLEMENTATION
 #define GB_IMPLEMENTATION
 #include "gb/gb.h"
 #include "gb/gb.h"
 
 
-
 #include <wchar.h>
 #include <wchar.h>
 #include <stdio.h>
 #include <stdio.h>
 
 
 #include <math.h>
 #include <math.h>
 
 
-
 template <typename U, typename V>
 template <typename U, typename V>
 gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
 gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
 
 
@@ -145,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
 
 
 #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
 #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
 
 
+#include "range_cache.cpp"
+
+
 
 
 u64 fnv64a(void const *data, isize len) {
 u64 fnv64a(void const *data, isize len) {
 	u8 const *bytes = cast(u8 const *)data;
 	u8 const *bytes = cast(u8 const *)data;
@@ -331,7 +332,7 @@ void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
 #include "ptr_set.cpp"
 #include "ptr_set.cpp"
 #include "string_set.cpp"
 #include "string_set.cpp"
 #include "priority_queue.cpp"
 #include "priority_queue.cpp"
-
+#include "thread_pool.cpp"
 
 
 
 
 gb_global String global_module_path = {0};
 gb_global String global_module_path = {0};
@@ -873,7 +874,6 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
 		info.size = size;
 		info.size = size;
 		info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 		info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
 		array_add(fi, info);
 		array_add(fi, info);
-
 	} while (FindNextFileW(find_file, &file_data));
 	} while (FindNextFileW(find_file, &file_data));
 
 
 	if (fi->count == 0) {
 	if (fi->count == 0) {

+ 8 - 5
src/entity.cpp

@@ -48,7 +48,8 @@ enum EntityFlag {
 	EntityFlag_NotExported   = 1<<14,
 	EntityFlag_NotExported   = 1<<14,
 
 
 	EntityFlag_Static        = 1<<16,
 	EntityFlag_Static        = 1<<16,
-	// EntityFlag_Reference     = 1<<17,
+
+	EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++
 
 
 	EntityFlag_CVarArg       = 1<<20,
 	EntityFlag_CVarArg       = 1<<20,
 	EntityFlag_AutoCast      = 1<<21,
 	EntityFlag_AutoCast      = 1<<21,
@@ -183,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
 	}
 	}
 
 
 	String name = e->token.string;
 	String name = e->token.string;
-	if (name.len == 0) {
-		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) {
 bool entity_has_deferred_procedure(Entity *e) {
@@ -219,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm
 	return entity;
 	return entity;
 }
 }
 
 
-Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) {
+Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
 	GB_ASSERT(parent != nullptr);
 	GB_ASSERT(parent != nullptr);
 	token.pos = parent->token.pos;
 	token.pos = parent->token.pos;
 	Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
 	Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
 	entity->using_parent = parent;
 	entity->using_parent = parent;
 	entity->parent_proc_decl = parent->parent_proc_decl;
 	entity->parent_proc_decl = parent->parent_proc_decl;
+	entity->using_expr = using_expr;
 	entity->flags |= EntityFlag_Using;
 	entity->flags |= EntityFlag_Using;
 	entity->flags |= EntityFlag_Used;
 	entity->flags |= EntityFlag_Used;
 	entity->state = EntityState_Resolved;
 	entity->state = EntityState_Resolved;

+ 249 - 15
src/exact_value.cpp

@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
 struct Complex128 {
 struct Complex128 {
 	f64 real, imag;
 	f64 real, imag;
 };
 };
+struct Quaternion256 {
+	f64 imag, jmag, kmag, real;
+};
+
+Quaternion256 quaternion256_inverse(Quaternion256 x) {
+	f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
+	x.real = +x.real * invmag2;
+	x.imag = -x.imag * invmag2;
+	x.jmag = -x.jmag * invmag2;
+	x.kmag = -x.kmag * invmag2;
+	return x;
+}
+
 
 
 enum ExactValueKind {
 enum ExactValueKind {
 	ExactValue_Invalid,
 	ExactValue_Invalid,
@@ -21,9 +34,11 @@ enum ExactValueKind {
 	ExactValue_Integer,
 	ExactValue_Integer,
 	ExactValue_Float,
 	ExactValue_Float,
 	ExactValue_Complex,
 	ExactValue_Complex,
+	ExactValue_Quaternion,
 	ExactValue_Pointer,
 	ExactValue_Pointer,
 	ExactValue_Compound,  // TODO(bill): Is this good enough?
 	ExactValue_Compound,  // TODO(bill): Is this good enough?
 	ExactValue_Procedure, // TODO(bill): Is this good enough?
 	ExactValue_Procedure, // TODO(bill): Is this good enough?
+	ExactValue_Typeid,
 
 
 	ExactValue_Count,
 	ExactValue_Count,
 };
 };
@@ -37,8 +52,10 @@ struct ExactValue {
 		f64           value_float;
 		f64           value_float;
 		i64           value_pointer;
 		i64           value_pointer;
 		Complex128    value_complex;
 		Complex128    value_complex;
+		Quaternion256 value_quaternion;
 		Ast *         value_compound;
 		Ast *         value_compound;
 		Ast *         value_procedure;
 		Ast *         value_procedure;
+		Type *        value_typeid;
 	};
 	};
 };
 };
 
 
@@ -53,25 +70,22 @@ HashKey hash_exact_value(ExactValue v) {
 		return hash_integer(u64(v.value_bool));
 		return hash_integer(u64(v.value_bool));
 	case ExactValue_String:
 	case ExactValue_String:
 		return hash_string(v.value_string);
 		return hash_string(v.value_string);
-	case ExactValue_Integer: {
-		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:
 	case ExactValue_Float:
 		return hash_f64(v.value_float);
 		return hash_f64(v.value_float);
 	case ExactValue_Pointer:
 	case ExactValue_Pointer:
 		return hash_integer(v.value_pointer);
 		return hash_integer(v.value_pointer);
 	case ExactValue_Complex:
 	case ExactValue_Complex:
 		return hashing_proc(&v.value_complex, gb_size_of(Complex128));
 		return hashing_proc(&v.value_complex, gb_size_of(Complex128));
-
+	case ExactValue_Quaternion:
+		return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
 	case ExactValue_Compound:
 	case ExactValue_Compound:
 		return hash_pointer(v.value_compound);
 		return hash_pointer(v.value_compound);
 	case ExactValue_Procedure:
 	case ExactValue_Procedure:
 		return hash_pointer(v.value_procedure);
 		return hash_pointer(v.value_procedure);
+	case ExactValue_Typeid:
+		return hash_pointer(v.value_typeid);
 	}
 	}
 	return hashing_proc(&v, gb_size_of(ExactValue));
 	return hashing_proc(&v, gb_size_of(ExactValue));
 
 
@@ -122,6 +136,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
 	return result;
 	return result;
 }
 }
 
 
+ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
+	ExactValue result = {ExactValue_Quaternion};
+	result.value_quaternion.real = real;
+	result.value_quaternion.imag = imag;
+	result.value_quaternion.jmag = jmag;
+	result.value_quaternion.kmag = kmag;
+	return result;
+}
+
 ExactValue exact_value_pointer(i64 ptr) {
 ExactValue exact_value_pointer(i64 ptr) {
 	ExactValue result = {ExactValue_Pointer};
 	ExactValue result = {ExactValue_Pointer};
 	result.value_pointer = ptr;
 	result.value_pointer = ptr;
@@ -135,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) {
 }
 }
 
 
 
 
+ExactValue exact_value_typeid(Type *type) {
+	ExactValue result = {ExactValue_Typeid};
+	result.value_typeid = type;
+	return result;
+}
+
+
 ExactValue exact_value_integer_from_string(String const &string) {
 ExactValue exact_value_integer_from_string(String const &string) {
 	ExactValue result = {ExactValue_Integer};
 	ExactValue result = {ExactValue_Integer};
 	big_int_from_string(&result.value_integer, string);
 	big_int_from_string(&result.value_integer, string);
@@ -259,14 +289,16 @@ ExactValue exact_value_from_basic_literal(Token token) {
 		str.len--; // Ignore the 'i|j|k'
 		str.len--; // Ignore the 'i|j|k'
 		f64 imag = float_from_string(str);
 		f64 imag = float_from_string(str);
 
 
-		if (last_rune == 'i') {
-			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: {
 	case Token_Rune: {
 		Rune r = GB_RUNE_INVALID;
 		Rune r = GB_RUNE_INVALID;
 		gb_utf8_decode(token.string.text, token.string.len, &r);
 		gb_utf8_decode(token.string.text, token.string.len, &r);
-		// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
 		return exact_value_i64(r);
 		return exact_value_i64(r);
 	}
 	}
 	default:
 	default:
@@ -324,11 +356,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
 		return exact_value_complex(v.value_float, 0);
 		return exact_value_complex(v.value_float, 0);
 	case ExactValue_Complex:
 	case ExactValue_Complex:
 		return v;
 		return v;
+	// case ExactValue_Quaternion:
+		// return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
+	}
+	ExactValue r = {ExactValue_Invalid};
+	return r;
+}
+ExactValue exact_value_to_quaternion(ExactValue v) {
+	switch (v.kind) {
+	case ExactValue_Integer:
+		return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
+	case ExactValue_Float:
+		return exact_value_quaternion(v.value_float, 0, 0, 0);
+	case ExactValue_Complex:
+		return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
+	case ExactValue_Quaternion:
+		return v;
 	}
 	}
 	ExactValue r = {ExactValue_Invalid};
 	ExactValue r = {ExactValue_Invalid};
 	return r;
 	return r;
 }
 }
-
 
 
 ExactValue exact_value_real(ExactValue v) {
 ExactValue exact_value_real(ExactValue v) {
 	switch (v.kind) {
 	switch (v.kind) {
@@ -337,6 +384,8 @@ ExactValue exact_value_real(ExactValue v) {
 		return v;
 		return v;
 	case ExactValue_Complex:
 	case ExactValue_Complex:
 		return exact_value_float(v.value_complex.real);
 		return exact_value_float(v.value_complex.real);
+	case ExactValue_Quaternion:
+		return exact_value_float(v.value_quaternion.real);
 	}
 	}
 	ExactValue r = {ExactValue_Invalid};
 	ExactValue r = {ExactValue_Invalid};
 	return r;
 	return r;
@@ -349,6 +398,34 @@ ExactValue exact_value_imag(ExactValue v) {
 		return exact_value_i64(0);
 		return exact_value_i64(0);
 	case ExactValue_Complex:
 	case ExactValue_Complex:
 		return exact_value_float(v.value_complex.imag);
 		return exact_value_float(v.value_complex.imag);
+	case ExactValue_Quaternion:
+		return exact_value_float(v.value_quaternion.imag);
+	}
+	ExactValue r = {ExactValue_Invalid};
+	return r;
+}
+
+ExactValue exact_value_jmag(ExactValue v) {
+	switch (v.kind) {
+	case ExactValue_Integer:
+	case ExactValue_Float:
+	case ExactValue_Complex:
+		return exact_value_i64(0);
+	case ExactValue_Quaternion:
+		return exact_value_float(v.value_quaternion.jmag);
+	}
+	ExactValue r = {ExactValue_Invalid};
+	return r;
+}
+
+ExactValue exact_value_kmag(ExactValue v) {
+	switch (v.kind) {
+	case ExactValue_Integer:
+	case ExactValue_Float:
+	case ExactValue_Complex:
+		return exact_value_i64(0);
+	case ExactValue_Quaternion:
+		return exact_value_float(v.value_quaternion.kmag);
 	}
 	}
 	ExactValue r = {ExactValue_Invalid};
 	ExactValue r = {ExactValue_Invalid};
 	return r;
 	return r;
@@ -367,6 +444,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
 	return r;
 	return r;
 }
 }
 
 
+ExactValue exact_value_make_jmag(ExactValue v) {
+	switch (v.kind) {
+	case ExactValue_Integer:
+		return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
+	case ExactValue_Float:
+		return exact_value_quaternion(0, 0, v.value_float, 0);
+	default:
+		GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
+	}
+	ExactValue r = {ExactValue_Invalid};
+	return r;
+}
+
+ExactValue exact_value_make_kmag(ExactValue v) {
+	switch (v.kind) {
+	case ExactValue_Integer:
+		return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
+	case ExactValue_Float:
+		return exact_value_quaternion(0, 0, 0, v.value_float);
+	default:
+		GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
+	}
+	ExactValue r = {ExactValue_Invalid};
+	return r;
+}
+
 i64 exact_value_to_i64(ExactValue v) {
 i64 exact_value_to_i64(ExactValue v) {
 	v = exact_value_to_integer(v);
 	v = exact_value_to_integer(v);
 	if (v.kind == ExactValue_Integer) {
 	if (v.kind == ExactValue_Integer) {
@@ -395,6 +498,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
 		case ExactValue_Integer:
 		case ExactValue_Integer:
 		case ExactValue_Float:
 		case ExactValue_Float:
 		case ExactValue_Complex:
 		case ExactValue_Complex:
+		case ExactValue_Quaternion:
 			return v;
 			return v;
 		}
 		}
 		break;
 		break;
@@ -419,6 +523,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
 			f64 imag = v.value_complex.imag;
 			f64 imag = v.value_complex.imag;
 			return exact_value_complex(-real, -imag);
 			return exact_value_complex(-real, -imag);
 		}
 		}
+		case ExactValue_Quaternion: {
+			f64 real = v.value_quaternion.real;
+			f64 imag = v.value_quaternion.imag;
+			f64 jmag = v.value_quaternion.jmag;
+			f64 kmag = v.value_quaternion.kmag;
+			return exact_value_quaternion(-real, -imag, -jmag, -kmag);
+		}
 		}
 		}
 		break;
 		break;
 	}
 	}
@@ -469,8 +580,10 @@ i32 exact_value_order(ExactValue const &v) {
 		return 3;
 		return 3;
 	case ExactValue_Complex:
 	case ExactValue_Complex:
 		return 4;
 		return 4;
-	case ExactValue_Pointer:
+	case ExactValue_Quaternion:
 		return 5;
 		return 5;
+	case ExactValue_Pointer:
+		return 6;
 
 
 	default:
 	default:
 		GB_PANIC("How'd you get here? Invalid Value.kind");
 		GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -491,7 +604,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
 
 
 	case ExactValue_Bool:
 	case ExactValue_Bool:
 	case ExactValue_String:
 	case ExactValue_String:
-	case ExactValue_Complex:
+	case ExactValue_Quaternion:
 		return;
 		return;
 
 
 	case ExactValue_Integer:
 	case ExactValue_Integer:
@@ -505,6 +618,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
 		case ExactValue_Complex:
 		case ExactValue_Complex:
 			*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
 			*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
 			return;
 			return;
+		case ExactValue_Quaternion:
+			*x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
+			return;
 		}
 		}
 		break;
 		break;
 
 
@@ -515,6 +631,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
 		case ExactValue_Complex:
 		case ExactValue_Complex:
 			*x = exact_value_to_complex(*x);
 			*x = exact_value_to_complex(*x);
 			return;
 			return;
+		case ExactValue_Quaternion:
+			*x = exact_value_to_quaternion(*x);
+			return;
+		}
+		break;
+
+	case ExactValue_Complex:
+		switch (y->kind) {
+		case ExactValue_Quaternion:
+			*x = exact_value_to_quaternion(*x);
+			return;
 		}
 		}
 		break;
 		break;
 	}
 	}
@@ -612,6 +739,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
 		break;
 		break;
 	}
 	}
 
 
+	case ExactValue_Quaternion: {
+		y = exact_value_to_quaternion(y);
+		f64 xr = x.value_quaternion.real;
+		f64 xi = x.value_quaternion.imag;
+		f64 xj = x.value_quaternion.jmag;
+		f64 xk = x.value_quaternion.kmag;
+		f64 yr = y.value_quaternion.real;
+		f64 yi = y.value_quaternion.imag;
+		f64 yj = y.value_quaternion.jmag;
+		f64 yk = y.value_quaternion.kmag;
+
+
+		f64 real = 0;
+		f64 imag = 0;
+		f64 jmag = 0;
+		f64 kmag = 0;
+
+		switch (op) {
+		case Token_Add:
+			real = xr + yr;
+			imag = xi + yi;
+			jmag = xj + yj;
+			kmag = xk + yk;
+			break;
+		case Token_Sub:
+			real = xr - yr;
+			imag = xi - yi;
+			jmag = xj - yj;
+			kmag = xk - yk;
+			break;
+		case Token_Mul:
+			imag = xr * yi + xi * yr + xj * yk - xk * yj;
+			jmag = xr * yj - xi * yk + xj * yr + xk * yi;
+			kmag = xr * yk + xi * yj - xj * yi + xk * yr;
+			real = xr * yr - xi * yi - xj * yj - xk * yk;
+			break;
+		case Token_Quo: {
+			f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk);
+			imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2;
+			jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2;
+			kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2;
+			real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2;
+			break;
+		}
+		default: goto error;
+		}
+		return exact_value_quaternion(real, imag, jmag, kmag);
+		break;
+	}
+
 	case ExactValue_String: {
 	case ExactValue_String: {
 		if (op != Token_Add) goto error;
 		if (op != Token_Add) goto error;
 
 
@@ -647,6 +824,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV
 	return exact_binary_operator_value(op, x, y);
 	return exact_binary_operator_value(op, x, y);
 }
 }
 
 
+gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
+	return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
+}
+
 
 
 i32 cmp_f64(f64 a, f64 b) {
 i32 cmp_f64(f64 a, f64 b) {
 	return (a > b) - (a < b);
 	return (a > b) - (a < b);
@@ -719,8 +900,61 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
 		}
 		}
 		break;
 		break;
 	}
 	}
+
+	case ExactValue_Typeid:
+		switch (op) {
+		case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
+		case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
+		}
+		break;
 	}
 	}
 
 
 	GB_PANIC("Invalid comparison");
 	GB_PANIC("Invalid comparison");
 	return false;
 	return false;
 }
 }
+
+
+gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
+	switch (v.kind) {
+	case ExactValue_Invalid:
+		return str;
+	case ExactValue_Bool:
+		return gb_string_appendc(str, v.value_bool ? "true" : "false");
+	case ExactValue_String: {
+		String s = quote_to_ascii(heap_allocator(), v.value_string);
+		string_limit = gb_max(string_limit, 36);
+		if (s.len <= string_limit) {
+			str = gb_string_append_length(str, s.text, s.len);
+		} else {
+			isize n = string_limit/5;
+			str = gb_string_append_length(str, s.text, n);
+			str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n));
+			str = gb_string_append_length(str, s.text+s.len-n, n);
+		}
+		gb_free(heap_allocator(), s.text);
+		return str;
+	}
+	case ExactValue_Integer: {
+		String s = big_int_to_string(heap_allocator(), &v.value_integer);
+		str = gb_string_append_length(str, s.text, s.len);
+		gb_free(heap_allocator(), s.text);
+		return str;
+	}
+	case ExactValue_Float:
+		return gb_string_append_fmt(str, "%f", v.value_float);
+	case ExactValue_Complex:
+		return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag);
+
+	case ExactValue_Pointer:
+		return str;
+	case ExactValue_Compound:
+		return str;
+	case ExactValue_Procedure:
+		return str;
+	}
+	return str;
+};
+
+gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
+	return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
+}

+ 19 - 11
src/gb/gb.h

@@ -918,7 +918,7 @@ GB_DEF void gb_lfence      (void);
 
 
 
 
 #if defined(GB_SYSTEM_WINDOWS)
 #if defined(GB_SYSTEM_WINDOWS)
-typedef struct gbSemaphore { void *win32_handle; }     gbSemaphore;
+typedef struct gbSemaphore { void *win32_handle;}      gbSemaphore;
 #elif defined(GB_SYSTEM_OSX)
 #elif defined(GB_SYSTEM_OSX)
 typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore;
 typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore;
 #elif defined(GB_SYSTEM_UNIX)
 #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_init   (gbSemaphore *s);
 GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
 GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
 GB_DEF void gb_semaphore_post   (gbSemaphore *s, i32 count);
 GB_DEF void gb_semaphore_post   (gbSemaphore *s, i32 count);
-GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1)
+GB_DEF void gb_semaphore_release(gbSemaphore *s);
 GB_DEF void gb_semaphore_wait   (gbSemaphore *s);
 GB_DEF void gb_semaphore_wait   (gbSemaphore *s);
 
 
 
 
@@ -975,10 +975,10 @@ typedef struct gbThread {
 	pthread_t     posix_handle;
 	pthread_t     posix_handle;
 #endif
 #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;
 	gbSemaphore   semaphore;
 	isize         stack_size;
 	isize         stack_size;
@@ -4588,10 +4588,18 @@ gb_inline void gb_lfence(void) {
 gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
 gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
 
 
 #if defined(GB_SYSTEM_WINDOWS)
 #if defined(GB_SYSTEM_WINDOWS)
-	gb_inline void gb_semaphore_init   (gbSemaphore *s)            { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); }
-	gb_inline void gb_semaphore_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)
 #elif defined(GB_SYSTEM_OSX)
 	gb_inline void gb_semaphore_init   (gbSemaphore *s)            { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
 	gb_inline void gb_semaphore_init   (gbSemaphore *s)            { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
@@ -8975,7 +8983,7 @@ gb_inline void gb_exit(u32 code) { exit(code); }
 
 
 gb_inline void gb_yield(void) {
 gb_inline void gb_yield(void) {
 #if defined(GB_SYSTEM_WINDOWS)
 #if defined(GB_SYSTEM_WINDOWS)
-	Sleep(0);
+	YieldProcessor();
 #else
 #else
 	sched_yield();
 	sched_yield();
 #endif
 #endif

File diff suppressed because it is too large
+ 495 - 89
src/ir.cpp


+ 238 - 62
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) {
 void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
+	set_procedure_abi_types(heap_allocator(), t);
+
 	i64 word_bits = 8*build_context.word_size;
 	i64 word_bits = 8*build_context.word_size;
 	t = base_type(t);
 	t = base_type(t);
 	GB_ASSERT(is_type_proc(t));
 	GB_ASSERT(is_type_proc(t));
 
 
 	isize param_count = t->Proc.param_count;
 	isize param_count = t->Proc.param_count;
 	isize result_count = t->Proc.result_count;
 	isize result_count = t->Proc.result_count;
+
 	ir_print_proc_results(f, m, t);
 	ir_print_proc_results(f, m, t);
 	ir_write_string(f, str_lit(" ("));
 	ir_write_string(f, str_lit(" ("));
 	if (t->Proc.return_by_pointer) {
 	if (t->Proc.return_by_pointer) {
@@ -418,20 +421,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
 			}
 			}
 			return;
 			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;
 		break;
 
 
@@ -767,15 +773,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 	case ExactValue_Float: {
 	case ExactValue_Float: {
 		GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
 		GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
 		type = core_type(type);
 		type = core_type(type);
-		u64 u = bit_cast<u64>(value.value_float);
+		u64 u_64 = bit_cast<u64>(value.value_float);
+		u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
+	#if 0
 		switch (type->Basic.kind) {
 		switch (type->Basic.kind) {
 		case Basic_f32:
 		case Basic_f32:
 			// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
 			// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
 			// a 64 bit number if bits_of(float type) <= 64.
 			// a 64 bit number if bits_of(float type) <= 64.
 			// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
 			// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
-			// 64 bit mantissa: 52 bits
-			// 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
 			// 29 == 52-23
 			u >>= 29;
 			u >>= 29;
 			u <<= 29;
 			u <<= 29;
@@ -792,9 +800,24 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 			ir_fprintf(f, "0x%016llx", u);
 			ir_fprintf(f, "0x%016llx", u);
 			break;
 			break;
 		}
 		}
+	#else
+		switch (type->Basic.kind) {
+		case Basic_f32: {
+			ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
+			break;
+		}
+		case Basic_f64:
+			ir_fprintf(f, "0x%016llx", u_64);
+			break;
+		default:
+			ir_fprintf(f, "0x%016llx", u_64);
+			break;
+		}
+	#endif
 		break;
 		break;
 	}
 	}
 	case ExactValue_Complex: {
 	case ExactValue_Complex: {
+		// xy/ri format
 		type = core_type(type);
 		type = core_type(type);
 		GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
 		GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
 		Type *ft = base_complex_elem_type(type);
 		Type *ft = base_complex_elem_type(type);
@@ -807,6 +830,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 		ir_write_byte(f, '}');
 		ir_write_byte(f, '}');
 		break;
 		break;
 	}
 	}
+
+	case ExactValue_Quaternion: {
+		// xyzw/ijkr format
+		type = core_type(type);
+		GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
+		Type *ft = base_complex_elem_type(type);
+		ir_write_byte(f, ' ');
+		ir_write_byte(f, '{');
+		ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+		ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
+		ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+		ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
+		ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+		ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
+		ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
+		ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
+		ir_write_byte(f, '}');
+		break;
+	}
+
 	case ExactValue_Pointer:
 	case ExactValue_Pointer:
 		if (value.value_pointer == 0) {
 		if (value.value_pointer == 0) {
 			if (is_type_typeid(type)) {
 			if (is_type_typeid(type)) {
@@ -836,22 +879,86 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 				ir_write_str_lit(f, "zeroinitializer");
 				ir_write_str_lit(f, "zeroinitializer");
 				break;
 				break;
 			}
 			}
-			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)) {
 		} else if (is_type_simd_vector(type)) {
 			ast_node(cl, CompoundLit, value.value_compound);
 			ast_node(cl, CompoundLit, value.value_compound);
 
 
@@ -927,7 +1034,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 			if (type->Struct.is_packed) ir_write_byte(f, '<');
 			if (type->Struct.is_packed) ir_write_byte(f, '<');
 			ir_write_byte(f, '{');
 			ir_write_byte(f, '{');
 			if (type->Struct.custom_align > 0) {
 			if (type->Struct.custom_align > 0) {
-				ir_fprintf(f, "[0 x <%lld x i8>] zeroinitializer", cast(i64)type->Struct.custom_align);
+				ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align);
+				ir_write_str_lit(f, " zeroinitializer");
 				if (value_count > 0) {
 				if (value_count > 0) {
 					ir_write_string(f, str_lit(", "));
 					ir_write_string(f, str_lit(", "));
 				}
 				}
@@ -1089,7 +1197,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
 		break;
 		break;
 	}
 	}
 	case irValue_Param:
 	case irValue_Param:
-		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;
 		break;
 	case irValue_SourceCodeLocation: {
 	case irValue_SourceCodeLocation: {
 		irValue *file      = value->SourceCodeLocation.file;
 		irValue *file      = value->SourceCodeLocation.file;
@@ -1124,7 +1236,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
 	switch (cc) {
 	switch (cc) {
 	case ProcCC_Odin:        ir_write_str_lit(f, "");       break;
 	case ProcCC_Odin:        ir_write_str_lit(f, "");       break;
 	case ProcCC_Contextless: ir_write_str_lit(f, "");       break;
 	case ProcCC_Contextless: ir_write_str_lit(f, "");       break;
-	case ProcCC_CDecl:       ir_write_str_lit(f, "ccc ");   break;
+	// case ProcCC_CDecl:       ir_write_str_lit(f, "ccc ");   break;
+	case ProcCC_CDecl:       ir_write_str_lit(f, "");   break;
 	case ProcCC_StdCall:     ir_write_str_lit(f, "cc 64 "); break;
 	case ProcCC_StdCall:     ir_write_str_lit(f, "cc 64 "); break;
 	case ProcCC_FastCall:    ir_write_str_lit(f, "cc 65 "); break;
 	case ProcCC_FastCall:    ir_write_str_lit(f, "cc 65 "); break;
 	case ProcCC_None:        ir_write_str_lit(f, "");       break;
 	case ProcCC_None:        ir_write_str_lit(f, "");       break;
@@ -1134,8 +1247,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
 
 
 void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
 void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
 	ir_print_type(f, m, t_context_ptr);
 	ir_print_type(f, m, t_context_ptr);
-	ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
-	// ir_write_str_lit(f, " noalias nonnull nocapture ");
+	// 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) {
 void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
@@ -1186,6 +1299,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		ir_write_str_lit(f, ", ");
 		ir_write_str_lit(f, ", ");
 		ir_print_type(f, m, type);
 		ir_print_type(f, m, type);
 		ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
 		ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
+		// ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
 		break;
 		break;
 	}
 	}
 
 
@@ -1888,11 +2002,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 					if (e->flags&EntityFlag_NoAlias) {
 					if (e->flags&EntityFlag_NoAlias) {
 						ir_write_str_lit(f, " noalias");
 						ir_write_str_lit(f, " noalias");
 					}
 					}
+					if (e->flags&EntityFlag_ImplicitReference) {
+						ir_write_str_lit(f, " nonnull dereferenceable");
+					}
 					ir_write_byte(f, ' ');
 					ir_write_byte(f, ' ');
 					irValue *arg = call->args[i];
 					irValue *arg = call->args[i];
-					if (is_type_boolean(t)) {
-
-					}
 					ir_print_value(f, m, arg, t);
 					ir_print_value(f, m, arg, t);
 					param_index++;
 					param_index++;
 				}
 				}
@@ -1907,24 +2021,43 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 					param_index++;
 					param_index++;
 				}
 				}
 			} else {
 			} else {
-				GB_ASSERT(call->args.count == params->variables.count);
+				// GB_ASSERT(call->args.count == params->variables.count);
+				isize arg_index = 0;
 				for_array(i, params->variables) {
 				for_array(i, params->variables) {
 					Entity *e = params->variables[i];
 					Entity *e = params->variables[i];
 					GB_ASSERT(e != nullptr);
 					GB_ASSERT(e != nullptr);
-					if (e->kind != Entity_Variable) continue;
+					if (e->kind != Entity_Variable) {
+						arg_index++;
+						continue;
+					}
 
 
 					if (param_index > 0) ir_write_str_lit(f, ", ");
 					if (param_index > 0) ir_write_str_lit(f, ", ");
 
 
-					irValue *arg = call->args[i];
 					Type *t = proc_type->Proc.abi_compat_params[i];
 					Type *t = proc_type->Proc.abi_compat_params[i];
-
-					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) {
 void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
+	set_procedure_abi_types(heap_allocator(), proc->type);
+
 	if (proc->body == nullptr) {
 	if (proc->body == nullptr) {
 		ir_write_str_lit(f, "declare ");
 		ir_write_str_lit(f, "declare ");
 		// if (proc->tags & ProcTag_dll_import) {
 		// if (proc->tags & ProcTag_dll_import) {
@@ -2043,7 +2178,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 
 
 	if (param_count > 0) {
 	if (param_count > 0) {
 		TypeTuple *params = &proc_type->params->Tuple;
 		TypeTuple *params = &proc_type->params->Tuple;
-		for (isize i = 0; i < param_count; i++) {
+		isize parameter_index = 0;
+		for (isize i = 0; i < param_count; i++, parameter_index++) {
 			Entity *e = params->variables[i];
 			Entity *e = params->variables[i];
 			Type *original_type = e->type;
 			Type *original_type = e->type;
 			Type *abi_type = proc_type->abi_compat_params[i];
 			Type *abi_type = proc_type->abi_compat_params[i];
@@ -2053,16 +2189,29 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 			if (i+1 == params->variables.count && proc_type->c_vararg) {
 			if (i+1 == params->variables.count && proc_type->c_vararg) {
 				ir_write_str_lit(f, " ...");
 				ir_write_str_lit(f, " ...");
 			} else {
 			} 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');
 	ir_write_byte(f, '\n');
 }
 }
 
 
+bool ir_print_global_type_allowed(Type *t) {
+	if (t == nullptr) {
+		return true;
+	}
+	t = core_type(t);
+	switch (t->kind) {
+	case Type_DynamicArray:
+	case Type_Map:
+	case Type_Union:
+	case Type_BitField:
+		return false;
+	}
+
+	return true;
+}
+
 void print_llvm_ir(irGen *ir) {
 void print_llvm_ir(irGen *ir) {
 	irModule *m = &ir->module;
 	irModule *m = &ir->module;
 
 
@@ -2184,9 +2349,11 @@ void print_llvm_ir(irGen *ir) {
 	defer (ir_file_buffer_destroy(f));
 	defer (ir_file_buffer_destroy(f));
 
 
 	i32 word_bits = cast(i32)(8*build_context.word_size);
 	i32 word_bits = cast(i32)(8*build_context.word_size);
-	if (build_context.ODIN_OS == "osx" || build_context.ODIN_OS == "macos") {
+	if (build_context.ODIN_OS == "darwin") {
 		GB_ASSERT(word_bits == 64);
 		GB_ASSERT(word_bits == 64);
-		ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n\n");
+		ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n");
+		ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n");
+		ir_write_str_lit(f, "\n");
 	} else if (build_context.ODIN_OS == "windows") {
 	} else if (build_context.ODIN_OS == "windows") {
 		ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
 		ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
 		if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
 		if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
@@ -2210,6 +2377,13 @@ void print_llvm_ir(irGen *ir) {
 	ir_print_encoded_local(f, str_lit("..complex128"));
 	ir_print_encoded_local(f, str_lit("..complex128"));
 	ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
 	ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
 
 
+	ir_print_encoded_local(f, str_lit("..quaternion64"));
+	ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
+	ir_print_encoded_local(f, str_lit("..quaternion128"));
+	ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
+	ir_print_encoded_local(f, str_lit("..quaternion256"));
+	ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
+
 	ir_print_encoded_local(f, str_lit("..typeid"));
 	ir_print_encoded_local(f, str_lit("..typeid"));
 	ir_write_str_lit(f, " = type ");
 	ir_write_str_lit(f, " = type ");
 	ir_print_type(f, m, t_uintptr);
 	ir_print_type(f, m, t_uintptr);
@@ -2339,7 +2513,7 @@ void print_llvm_ir(irGen *ir) {
 		ir_print_type(f, m, g->entity->type);
 		ir_print_type(f, m, g->entity->type);
 		ir_write_byte(f, ' ');
 		ir_write_byte(f, ' ');
 		if (!g->is_foreign) {
 		if (!g->is_foreign) {
-			if (g->value != nullptr) {
+			if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) {
 				ir_print_value(f, m, g->value, g->entity->type);
 				ir_print_value(f, m, g->value, g->entity->type);
 			} else {
 			} else {
 				ir_write_string(f, str_lit("zeroinitializer"));
 				ir_write_string(f, str_lit("zeroinitializer"));
@@ -2383,11 +2557,13 @@ void print_llvm_ir(irGen *ir) {
 
 
 		for_array(di_index, m->debug_info.entries) {
 		for_array(di_index, m->debug_info.entries) {
 			irDebugInfo *di = m->debug_info.entries[di_index].value;
 			irDebugInfo *di = m->debug_info.entries[di_index].value;
+			GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
 			ir_fprintf(f, "!%d = ", di->id);
 			ir_fprintf(f, "!%d = ", di->id);
-
 			switch (di->kind) {
 			switch (di->kind) {
 			case irDebugInfo_CompileUnit: {
 			case irDebugInfo_CompileUnit: {
-				irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
+				irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
+				GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath));
+				irDebugInfo *file = *found;
 				ir_fprintf(f,
 				ir_fprintf(f,
 				            "distinct !DICompileUnit("
 				            "distinct !DICompileUnit("
 				              "language: DW_LANG_C_plus_plus" // Is this good enough?
 				              "language: DW_LANG_C_plus_plus" // Is this good enough?

+ 55 - 60
src/main.cpp

@@ -75,7 +75,7 @@ i32 system_exec_command_line_app(char *name, char *fmt, ...) {
 	va_end(va);
 	va_end(va);
 	cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
 	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]);
 	exit_code = system(&cmd_line[0]);
 
 
 	// pid_t pid = fork();
 	// pid_t pid = fork();
@@ -160,8 +160,9 @@ void usage(String argv0) {
 	print_usage_line(0, "Usage:");
 	print_usage_line(0, "Usage:");
 	print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
 	print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
 	print_usage_line(0, "Commands:");
 	print_usage_line(0, "Commands:");
-	print_usage_line(1, "build     compile .odin file as executable");
-	print_usage_line(1, "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, "check     parse and type check .odin file");
 	print_usage_line(1, "query     parse, type check, and output a .json file containing information about the program");
 	print_usage_line(1, "query     parse, type check, and output a .json file containing information about the program");
 	print_usage_line(1, "docs      generate documentation for a .odin file");
 	print_usage_line(1, "docs      generate documentation for a .odin file");
@@ -210,9 +211,8 @@ enum BuildFlagKind {
 	BuildFlag_Collection,
 	BuildFlag_Collection,
 	BuildFlag_Define,
 	BuildFlag_Define,
 	BuildFlag_BuildMode,
 	BuildFlag_BuildMode,
+	BuildFlag_Target,
 	BuildFlag_Debug,
 	BuildFlag_Debug,
-	BuildFlag_CrossCompile,
-	BuildFlag_CrossLibDir,
 	BuildFlag_NoBoundsCheck,
 	BuildFlag_NoBoundsCheck,
 	BuildFlag_NoCRT,
 	BuildFlag_NoCRT,
 	BuildFlag_UseLLD,
 	BuildFlag_UseLLD,
@@ -298,9 +298,8 @@ bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_Collection,        str_lit("collection"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_Collection,        str_lit("collection"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_Define,            str_lit("define"),          BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_Define,            str_lit("define"),          BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_BuildMode,         str_lit("build-mode"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_BuildMode,         str_lit("build-mode"),      BuildFlagParam_String);
+	add_flag(&build_flags, BuildFlag_Target,            str_lit("target"),          BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_Debug,             str_lit("debug"),           BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_Debug,             str_lit("debug"),           BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_CrossCompile,      str_lit("cross-compile"),   BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_CrossLibDir,       str_lit("cross-lib-dir"),   BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_NoBoundsCheck,     str_lit("no-bounds-check"), BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_NoBoundsCheck,     str_lit("no-bounds-check"), BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_NoCRT,             str_lit("no-crt"),          BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_NoCRT,             str_lit("no-crt"),          BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_UseLLD,            str_lit("lld"),             BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_UseLLD,            str_lit("lld"),             BuildFlagParam_None);
@@ -447,7 +446,7 @@ bool parse_build_flags(Array<String> args) {
 										path = substring(path, 0, string_extension_position(path));
 										path = substring(path, 0, string_extension_position(path));
 									}
 									}
 								#endif
 								#endif
-								build_context.out_filepath = path;
+								build_context.out_filepath = path_to_full_path(heap_allocator(), path);
 							} else {
 							} else {
 								gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
 								gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
 								bad_flags = true;
 								bad_flags = true;
@@ -478,33 +477,6 @@ bool parse_build_flags(Array<String> args) {
 							build_context.keep_temp_files = true;
 							build_context.keep_temp_files = true;
 							break;
 							break;
 
 
-						case BuildFlag_CrossCompile: {
-							GB_ASSERT(value.kind == ExactValue_String);
-							cross_compile_target = value.value_string;
-						#if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
-							if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
-
-							} else
-						#endif
-							{
-								gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
-								gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
-								bad_flags = true;
-							}
-							break;
-						}
-
-						case BuildFlag_CrossLibDir: {
-							GB_ASSERT(value.kind == ExactValue_String);
-							if (cross_compile_lib_dir.len) {
-								gb_printf_err("Multiple cross compilation library directories\n");
-								bad_flags = true;
-							} else {
-								cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
-							}
-							break;
-						}
-
 						case BuildFlag_Collection: {
 						case BuildFlag_Collection: {
 							GB_ASSERT(value.kind == ExactValue_String);
 							GB_ASSERT(value.kind == ExactValue_String);
 							String str = value.value_string;
 							String str = value.value_string;
@@ -623,7 +595,25 @@ bool parse_build_flags(Array<String> args) {
 							break;
 							break;
 						}
 						}
 
 
+						case BuildFlag_Target: {
+							String str = value.value_string;
+							bool found = false;
+
+							for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) {
+								if (str_eq_ignore_case(str, named_targets[i].name)) {
+									found = true;
+									selected_target_metrics = named_targets + i;
+									break;
+								}
+							}
+
+							if (!found) {
+								gb_printf_err("Unknown target '%.*s'\n", LIT(str));
+								bad_flags = true;
+							}
 
 
+							break;
+						}
 
 
 						case BuildFlag_BuildMode: {
 						case BuildFlag_BuildMode: {
 							GB_ASSERT(value.kind == ExactValue_String);
 							GB_ASSERT(value.kind == ExactValue_String);
@@ -635,7 +625,7 @@ bool parse_build_flags(Array<String> args) {
 								break;
 								break;
 							}
 							}
 
 
-							if (str == "dll") {
+							if (str == "dll" || str == "shared") {
 								build_context.is_dll = true;
 								build_context.is_dll = true;
 							} else if (str == "exe") {
 							} else if (str == "exe") {
 								build_context.is_dll = false;
 								build_context.is_dll = false;
@@ -889,8 +879,8 @@ i32 exec_llvm_opt(String output_base) {
 }
 }
 
 
 i32 exec_llvm_llc(String output_base) {
 i32 exec_llvm_llc(String output_base) {
-#if defined(GB_SYSTEM_WINDOWS)
 	// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
 	// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
+#if defined(GB_SYSTEM_WINDOWS)
 	return system_exec_command_line_app("llvm-llc",
 	return system_exec_command_line_app("llvm-llc",
 		"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
 		"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
 		"-o \"%.*s.obj\" "
 		"-o \"%.*s.obj\" "
@@ -903,21 +893,19 @@ i32 exec_llvm_llc(String output_base) {
 		LIT(build_context.llc_flags));
 		LIT(build_context.llc_flags));
 #else
 #else
 	// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
 	// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
-	// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
 	return system_exec_command_line_app("llc",
 	return system_exec_command_line_app("llc",
 		"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
 		"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
 		"%.*s "
 		"%.*s "
-		"%s"
-		"",
+		"%s%.*s",
 		LIT(output_base),
 		LIT(output_base),
 		build_context.optimization_level,
 		build_context.optimization_level,
 		LIT(build_context.llc_flags),
 		LIT(build_context.llc_flags),
-		str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
+		build_context.cross_compiling ? "-mtriple=" : "",
+		(int) (build_context.cross_compiling ? build_context.target_triplet.len : 0),
+		build_context.target_triplet.text);
 #endif
 #endif
 }
 }
 
 
-
-
 int main(int arg_count, char **arg_ptr) {
 int main(int arg_count, char **arg_ptr) {
 	if (arg_count < 2) {
 	if (arg_count < 2) {
 		usage(make_string_c(arg_ptr[0]));
 		usage(make_string_c(arg_ptr[0]));
@@ -1026,7 +1014,7 @@ int main(int arg_count, char **arg_ptr) {
 	}
 	}
 
 
 
 
-	init_build_context();
+	init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr);
 	if (build_context.word_size == 4) {
 	if (build_context.word_size == 4) {
 		print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
 		print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
 		return 1;
 		return 1;
@@ -1121,6 +1109,17 @@ int main(int arg_count, char **arg_ptr) {
 		return exit_code;
 		return exit_code;
 	}
 	}
 
 
+	if (build_context.cross_compiling) {
+		if (0) {
+#ifdef GB_SYSTEM_UNIX
+		} else if (selected_target_metrics->metrics == &target_essence_amd64) {
+			system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
+					LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
+#endif
+		} else {
+			gb_printf_err("Don't know how to cross compile to selected target.\n");
+		}
+	} else {
 	#if defined(GB_SYSTEM_WINDOWS)
 	#if defined(GB_SYSTEM_WINDOWS)
 		timings_start_section(&timings, str_lit("msvc-link"));
 		timings_start_section(&timings, str_lit("msvc-link"));
 
 
@@ -1219,7 +1218,7 @@ int main(int arg_count, char **arg_ptr) {
 		remove_temp_files(output_base);
 		remove_temp_files(output_base);
 
 
 		if (run_output) {
 		if (run_output) {
-			system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
+			return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
 		}
 		}
 	#else
 	#else
 		timings_start_section(&timings, str_lit("ld-link"));
 		timings_start_section(&timings, str_lit("ld-link"));
@@ -1241,15 +1240,17 @@ int main(int arg_count, char **arg_ptr) {
 			//   This allows you to specify '-f' in a #foreign_system_library,
 			//   This allows you to specify '-f' in a #foreign_system_library,
 			//   without having to implement any new syntax specifically for MacOS.
 			//   without having to implement any new syntax specifically for MacOS.
 			#if defined(GB_SYSTEM_OSX)
 			#if defined(GB_SYSTEM_OSX)
-				if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
+				if (string_ends_with(lib, str_lit(".framework"))) {
 					// framework thingie
 					// framework thingie
-					lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
+					String lib_name = lib;
+					lib_name = remove_extension_from_path(lib_name);
+					lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
 				} else if (string_ends_with(lib, str_lit(".a"))) {
 				} else if (string_ends_with(lib, str_lit(".a"))) {
 					// static libs, absolute full path relative to the file in which the lib was imported from
 					// static libs, absolute full path relative to the file in which the lib was imported from
 					lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
 					lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
 				} else if (string_ends_with(lib, str_lit(".dylib"))) {
 				} else if (string_ends_with(lib, str_lit(".dylib"))) {
-					// dynamic lib, relative path to executable
-					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 {
 				} else {
 					// dynamic or static system lib, just link regularly searching system library paths
 					// dynamic or static system lib, just link regularly searching system library paths
 					lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
 					lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -1309,11 +1310,7 @@ int main(int arg_count, char **arg_ptr) {
 			//   It probably has to do with including the entire CRT, but
 			//   It probably has to do with including the entire CRT, but
 			//   that's quite a complicated issue to solve while remaining distro-agnostic.
 			//   that's quite a complicated issue to solve while remaining distro-agnostic.
 			//   Clang can figure out linker flags for us, and that's good enough _for now_.
 			//   Clang can figure out linker flags for us, and that's good enough _for now_.
-			if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
-				linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
-			} else {
-				linker = "clang -Wno-unused-command-line-argument";
-			}
+			linker = "clang -Wno-unused-command-line-argument";
 		#endif
 		#endif
 
 
 		exit_code = system_exec_command_line_app("ld-link",
 		exit_code = system_exec_command_line_app("ld-link",
@@ -1321,7 +1318,6 @@ int main(int arg_count, char **arg_ptr) {
 			" %s "
 			" %s "
 			" %.*s "
 			" %.*s "
 			" %s "
 			" %s "
-			" %.*s "
 			#if defined(GB_SYSTEM_OSX)
 			#if defined(GB_SYSTEM_OSX)
 				// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
 				// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
 				// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
 				// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
@@ -1332,11 +1328,9 @@ int main(int arg_count, char **arg_ptr) {
 			#endif
 			#endif
 			, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
 			, linker, LIT(output_base), LIT(output_base), LIT(output_ext),
 			lib_str,
 			lib_str,
-			str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm",
+			"-lc -lm",
 			LIT(build_context.link_flags),
 			LIT(build_context.link_flags),
-			link_settings,
-			LIT(cross_compile_lib_dir)
-			);
+			link_settings);
 		if (exit_code != 0) {
 		if (exit_code != 0) {
 			return exit_code;
 			return exit_code;
 		}
 		}
@@ -1366,9 +1360,10 @@ int main(int arg_count, char **arg_ptr) {
 			//NOTE(thebirk): This whole thing is a little leaky
 			//NOTE(thebirk): This whole thing is a little leaky
 			String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
 			String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
 			complete_path = path_to_full_path(heap_allocator(), complete_path);
 			complete_path = path_to_full_path(heap_allocator(), complete_path);
-			system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
+			return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
 		}
 		}
 	#endif
 	#endif
+	}
 
 
 	return 0;
 	return 0;
 }
 }

+ 301 - 223
src/parser.cpp

@@ -51,6 +51,7 @@ Token ast_token(Ast *node) {
 	case Ast_ReturnStmt:         return node->ReturnStmt.token;
 	case Ast_ReturnStmt:         return node->ReturnStmt.token;
 	case Ast_ForStmt:            return node->ForStmt.token;
 	case Ast_ForStmt:            return node->ForStmt.token;
 	case Ast_RangeStmt:          return node->RangeStmt.token;
 	case Ast_RangeStmt:          return node->RangeStmt.token;
+	case Ast_InlineRangeStmt:    return node->InlineRangeStmt.inline_token;
 	case Ast_CaseClause:         return node->CaseClause.token;
 	case Ast_CaseClause:         return node->CaseClause.token;
 	case Ast_SwitchStmt:         return node->SwitchStmt.token;
 	case Ast_SwitchStmt:         return node->SwitchStmt.token;
 	case Ast_TypeSwitchStmt:     return node->TypeSwitchStmt.token;
 	case Ast_TypeSwitchStmt:     return node->TypeSwitchStmt.token;
@@ -143,6 +144,7 @@ Ast *clone_ast(Ast *node) {
 	case Ast_ProcLit:
 	case Ast_ProcLit:
 		n->ProcLit.type = clone_ast(n->ProcLit.type);
 		n->ProcLit.type = clone_ast(n->ProcLit.type);
 		n->ProcLit.body = clone_ast(n->ProcLit.body);
 		n->ProcLit.body = clone_ast(n->ProcLit.body);
+		n->ProcLit.where_clauses = clone_ast_array(n->ProcLit.where_clauses);
 		break;
 		break;
 	case Ast_CompoundLit:
 	case Ast_CompoundLit:
 		n->CompoundLit.type  = clone_ast(n->CompoundLit.type);
 		n->CompoundLit.type  = clone_ast(n->CompoundLit.type);
@@ -257,6 +259,12 @@ Ast *clone_ast(Ast *node) {
 		n->RangeStmt.expr  = clone_ast(n->RangeStmt.expr);
 		n->RangeStmt.expr  = clone_ast(n->RangeStmt.expr);
 		n->RangeStmt.body  = clone_ast(n->RangeStmt.body);
 		n->RangeStmt.body  = clone_ast(n->RangeStmt.body);
 		break;
 		break;
+	case Ast_InlineRangeStmt:
+		n->InlineRangeStmt.val0  = clone_ast(n->InlineRangeStmt.val0);
+		n->InlineRangeStmt.val1  = clone_ast(n->InlineRangeStmt.val1);
+		n->InlineRangeStmt.expr  = clone_ast(n->InlineRangeStmt.expr);
+		n->InlineRangeStmt.body  = clone_ast(n->InlineRangeStmt.body);
+		break;
 	case Ast_CaseClause:
 	case Ast_CaseClause:
 		n->CaseClause.list  = clone_ast_array(n->CaseClause.list);
 		n->CaseClause.list  = clone_ast_array(n->CaseClause.list);
 		n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts);
 		n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts);
@@ -341,10 +349,12 @@ Ast *clone_ast(Ast *node) {
 		n->StructType.fields = clone_ast_array(n->StructType.fields);
 		n->StructType.fields = clone_ast_array(n->StructType.fields);
 		n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params);
 		n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params);
 		n->StructType.align  = clone_ast(n->StructType.align);
 		n->StructType.align  = clone_ast(n->StructType.align);
+		n->StructType.where_clauses  = clone_ast_array(n->StructType.where_clauses);
 		break;
 		break;
 	case Ast_UnionType:
 	case Ast_UnionType:
 		n->UnionType.variants = clone_ast_array(n->UnionType.variants);
 		n->UnionType.variants = clone_ast_array(n->UnionType.variants);
 		n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params);
 		n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params);
+		n->UnionType.where_clauses = clone_ast_array(n->UnionType.where_clauses);
 		break;
 		break;
 	case Ast_EnumType:
 	case Ast_EnumType:
 		n->EnumType.base_type = clone_ast(n->EnumType.base_type);
 		n->EnumType.base_type = clone_ast(n->EnumType.base_type);
@@ -417,7 +427,7 @@ void syntax_error(Ast *node, char *fmt, ...) {
 
 
 bool ast_node_expect(Ast *node, AstKind kind) {
 bool ast_node_expect(Ast *node, AstKind kind) {
 	if (node->kind != kind) {
 	if (node->kind != kind) {
-		error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind]));
+		syntax_error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind]));
 		return false;
 		return false;
 	}
 	}
 	return true;
 	return true;
@@ -578,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) {
 Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
 Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
 	Ast *result = alloc_ast_node(f, Ast_BasicLit);
 	Ast *result = alloc_ast_node(f, Ast_BasicLit);
 	result->BasicLit.token = basic_lit;
 	result->BasicLit.token = basic_lit;
+	result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
 	return result;
 	return result;
 }
 }
 
 
@@ -605,11 +616,13 @@ Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<Ast
 	return result;
 	return result;
 }
 }
 
 
-Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags) {
+Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags, Token where_token, Array<Ast *> const &where_clauses) {
 	Ast *result = alloc_ast_node(f, Ast_ProcLit);
 	Ast *result = alloc_ast_node(f, Ast_ProcLit);
 	result->ProcLit.type = type;
 	result->ProcLit.type = type;
 	result->ProcLit.body = body;
 	result->ProcLit.body = body;
 	result->ProcLit.tags = tags;
 	result->ProcLit.tags = tags;
+	result->ProcLit.where_token = where_token;
+	result->ProcLit.where_clauses = where_clauses;
 	return result;
 	return result;
 }
 }
 
 
@@ -748,6 +761,18 @@ Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_toke
 	return result;
 	return result;
 }
 }
 
 
+Ast *ast_inline_range_stmt(AstFile *f, Token inline_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) {
+	Ast *result = alloc_ast_node(f, Ast_InlineRangeStmt);
+	result->InlineRangeStmt.inline_token = inline_token;
+	result->InlineRangeStmt.for_token = for_token;
+	result->InlineRangeStmt.val0 = val0;
+	result->InlineRangeStmt.val1 = val1;
+	result->InlineRangeStmt.in_token = in_token;
+	result->InlineRangeStmt.expr  = expr;
+	result->InlineRangeStmt.body  = body;
+	return result;
+}
+
 Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) {
 Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) {
 	Ast *result = alloc_ast_node(f, Ast_SwitchStmt);
 	Ast *result = alloc_ast_node(f, Ast_SwitchStmt);
 	result->SwitchStmt.token = token;
 	result->SwitchStmt.token = token;
@@ -805,13 +830,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
 	return result;
 	return result;
 }
 }
 
 
-Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags,
-                   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);
 	Ast *result = alloc_ast_node(f, Ast_Field);
 	result->Field.names         = names;
 	result->Field.names         = names;
 	result->Field.type          = type;
 	result->Field.type          = type;
 	result->Field.default_value = default_value;
 	result->Field.default_value = default_value;
 	result->Field.flags         = flags;
 	result->Field.flags         = flags;
+	result->Field.tag           = tag;
 	result->Field.docs = docs;
 	result->Field.docs = docs;
 	result->Field.comment       = comment;
 	result->Field.comment       = comment;
 	return result;
 	return result;
@@ -898,7 +924,8 @@ Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
 
 
 Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count,
 Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count,
                      Ast *polymorphic_params, bool is_packed, bool is_raw_union,
                      Ast *polymorphic_params, bool is_packed, bool is_raw_union,
-                     Ast *align) {
+                     Ast *align,
+                     Token where_token, Array<Ast *> const &where_clauses) {
 	Ast *result = alloc_ast_node(f, Ast_StructType);
 	Ast *result = alloc_ast_node(f, Ast_StructType);
 	result->StructType.token              = token;
 	result->StructType.token              = token;
 	result->StructType.fields             = fields;
 	result->StructType.fields             = fields;
@@ -907,17 +934,22 @@ Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_c
 	result->StructType.is_packed          = is_packed;
 	result->StructType.is_packed          = is_packed;
 	result->StructType.is_raw_union       = is_raw_union;
 	result->StructType.is_raw_union       = is_raw_union;
 	result->StructType.align              = align;
 	result->StructType.align              = align;
+	result->StructType.where_token        = where_token;
+	result->StructType.where_clauses      = where_clauses;
 	return result;
 	return result;
 }
 }
 
 
 
 
-Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil) {
+Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil,
+                    Token where_token, Array<Ast *> const &where_clauses) {
 	Ast *result = alloc_ast_node(f, Ast_UnionType);
 	Ast *result = alloc_ast_node(f, Ast_UnionType);
 	result->UnionType.token              = token;
 	result->UnionType.token              = token;
 	result->UnionType.variants           = variants;
 	result->UnionType.variants           = variants;
 	result->UnionType.polymorphic_params = polymorphic_params;
 	result->UnionType.polymorphic_params = polymorphic_params;
 	result->UnionType.align              = align;
 	result->UnionType.align              = align;
 	result->UnionType.no_nil             = no_nil;
 	result->UnionType.no_nil             = no_nil;
+	result->UnionType.where_token        = where_token;
+	result->UnionType.where_clauses      = where_clauses;
 	return result;
 	return result;
 }
 }
 
 
@@ -1118,6 +1150,17 @@ Token advance_token(AstFile *f) {
 	return prev;
 	return prev;
 }
 }
 
 
+bool peek_token_kind(AstFile *f, TokenKind kind) {
+	for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) {
+		Token tok = f->tokens[i];
+		if (kind != Token_Comment && tok.kind == Token_Comment) {
+			continue;
+		}
+		return tok.kind == kind;
+	}
+	return false;
+}
+
 Token expect_token(AstFile *f, TokenKind kind) {
 Token expect_token(AstFile *f, TokenKind kind) {
 	Token prev = f->curr_token;
 	Token prev = f->curr_token;
 	if (prev.kind != kind) {
 	if (prev.kind != kind) {
@@ -1302,7 +1345,8 @@ bool is_semicolon_optional_for_node(AstFile *f, Ast *s) {
 	case Ast_UnionType:
 	case Ast_UnionType:
 	case Ast_EnumType:
 	case Ast_EnumType:
 	case Ast_BitFieldType:
 	case Ast_BitFieldType:
-		return true;
+		// Require semicolon within a procedure body
+		return f->curr_proc == nullptr;
 	case Ast_ProcLit:
 	case Ast_ProcLit:
 		return true;
 		return true;
 
 
@@ -1336,10 +1380,6 @@ void expect_semicolon(AstFile *f, Ast *s) {
 		return;
 		return;
 	}
 	}
 
 
-	switch (f->curr_token.kind) {
-	case Token_EOF:
-		return;
-	}
 
 
 	if (s != nullptr) {
 	if (s != nullptr) {
 		if (prev_token.pos.line != f->curr_token.pos.line) {
 		if (prev_token.pos.line != f->curr_token.pos.line) {
@@ -1352,12 +1392,21 @@ void expect_semicolon(AstFile *f, Ast *s) {
 			case Token_CloseParen:
 			case Token_CloseParen:
 			case Token_else:
 			case Token_else:
 				return;
 				return;
+			case Token_EOF:
+				if (is_semicolon_optional_for_node(f, s)) {
+					return;
+				}
+				break;
 			}
 			}
 		}
 		}
 		String node_string = ast_strings[s->kind];
 		String node_string = ast_strings[s->kind];
 		syntax_error(prev_token, "Expected ';' after %.*s, got %.*s",
 		syntax_error(prev_token, "Expected ';' after %.*s, got %.*s",
-		             LIT(node_string), LIT(token_strings[prev_token.kind]));
+		             LIT(node_string), LIT(token_strings[f->curr_token.kind]));
 	} else {
 	} else {
+		switch (f->curr_token.kind) {
+		case Token_EOF:
+			return;
+		}
 		syntax_error(prev_token, "Expected ';'");
 		syntax_error(prev_token, "Expected ';'");
 	}
 	}
 	fix_advance_to_next_stmt(f);
 	fix_advance_to_next_stmt(f);
@@ -1461,8 +1510,11 @@ Ast *parse_value(AstFile *f) {
 	if (f->curr_token.kind == Token_OpenBrace) {
 	if (f->curr_token.kind == Token_OpenBrace) {
 		return parse_literal_value(f, nullptr);
 		return parse_literal_value(f, nullptr);
 	}
 	}
-
-	Ast *value = 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;
 	return value;
 }
 }
 
 
@@ -1614,7 +1666,7 @@ void check_polymorphic_params_for_type(AstFile *f, Ast *polymorphic_params, Toke
 		for_array(i, field->Field.names) {
 		for_array(i, field->Field.names) {
 			Ast *name = field->Field.names[i];
 			Ast *name = field->Field.names[i];
 			if (name->kind == Ast_PolyType) {
 			if (name->kind == Ast_PolyType) {
-				error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string));
+				syntax_error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string));
 				return; // TODO(bill): Err multiple times or just the once?
 				return; // TODO(bill): Err multiple times or just the once?
 			}
 			}
 		}
 		}
@@ -1687,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 				operand = ast_bad_expr(f, token, f->curr_token);
 				operand = ast_bad_expr(f, token, f->curr_token);
 			}
 			}
 			operand->stmt_state_flags |= StmtStateFlag_no_deferred;
 			operand->stmt_state_flags |= StmtStateFlag_no_deferred;
-		} */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string);
+		} */ else if (name.string == "file") {
+			return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
@@ -1796,15 +1849,41 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 		}
 		}
 
 
 		Ast *type = parse_proc_type(f, token);
 		Ast *type = parse_proc_type(f, token);
+		Token where_token = {};
+		Array<Ast *> where_clauses = {};
+		u64 tags = 0;
+
+		if (f->curr_token.kind == Token_where) {
+			where_token = expect_token(f, Token_where);
+			isize prev_level = f->expr_level;
+			f->expr_level = -1;
+			where_clauses = parse_rhs_expr_list(f);
+			f->expr_level = prev_level;
+		}
+
+		parse_proc_tags(f, &tags);
+		if ((tags & ProcTag_require_results) != 0) {
+			syntax_error(f->curr_token, "#require_results has now been replaced as an attribute @(require_results) on the declaration");
+			tags &= ~ProcTag_require_results;
+		}
+		GB_ASSERT(type->kind == Ast_ProcType);
+		type->ProcType.tags = tags;
 
 
 		if (f->allow_type && f->expr_level < 0) {
 		if (f->allow_type && f->expr_level < 0) {
+			if (tags != 0) {
+				syntax_error(token, "A procedure type cannot have suffix tags");
+			}
+			if (where_token.kind != Token_Invalid) {
+				syntax_error(where_token, "'where' clauses are not allowed on procedure types");
+			}
 			return type;
 			return type;
 		}
 		}
 
 
-		u64 tags = type->ProcType.tags;
-
 		if (allow_token(f, Token_Undef)) {
 		if (allow_token(f, Token_Undef)) {
-			return ast_proc_lit(f, type, nullptr, tags);
+			if (where_token.kind != Token_Invalid) {
+				syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)");
+			}
+			return ast_proc_lit(f, type, nullptr, tags, where_token, where_clauses);
 		} else if (f->curr_token.kind == Token_OpenBrace) {
 		} else if (f->curr_token.kind == Token_OpenBrace) {
 			Ast *curr_proc = f->curr_proc;
 			Ast *curr_proc = f->curr_proc;
 			Ast *body = nullptr;
 			Ast *body = nullptr;
@@ -1812,7 +1891,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 			body = parse_body(f);
 			body = parse_body(f);
 			f->curr_proc = curr_proc;
 			f->curr_proc = curr_proc;
 
 
-			return ast_proc_lit(f, type, body, tags);
+			return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
 		} else if (allow_token(f, Token_do)) {
 		} else if (allow_token(f, Token_do)) {
 			Ast *curr_proc = f->curr_proc;
 			Ast *curr_proc = f->curr_proc;
 			Ast *body = nullptr;
 			Ast *body = nullptr;
@@ -1820,11 +1899,14 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 			body = convert_stmt_to_body(f, parse_stmt(f));
 			body = convert_stmt_to_body(f, parse_stmt(f));
 			f->curr_proc = curr_proc;
 			f->curr_proc = curr_proc;
 
 
-			return ast_proc_lit(f, type, body, tags);
+			return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
 		}
 		}
 
 
 		if (tags != 0) {
 		if (tags != 0) {
-			syntax_error(token, "A procedure type cannot have tags");
+			syntax_error(token, "A procedure type cannot have suffix tags");
+		}
+		if (where_token.kind != Token_Invalid) {
+			syntax_error(where_token, "'where' clauses are not allowed on procedure types");
 		}
 		}
 
 
 		return type;
 		return type;
@@ -1847,10 +1929,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 
 
 	case Token_typeid: {
 	case Token_typeid: {
 		Token token = expect_token(f, Token_typeid);
 		Token token = expect_token(f, Token_typeid);
-		// Ast *specialization = nullptr;
-		// if (allow_token(f, Token_Quo)) {
-		// 	specialization = parse_type(f);
-		// }
 		return ast_typeid_type(f, token, nullptr);
 		return ast_typeid_type(f, token, nullptr);
 	} break;
 	} break;
 
 
@@ -1952,6 +2030,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 			syntax_error(token, "'#raw_union' cannot also be '#packed'");
 			syntax_error(token, "'#raw_union' cannot also be '#packed'");
 		}
 		}
 
 
+		Token where_token = {};
+		Array<Ast *> where_clauses = {};
+
+		if (f->curr_token.kind == Token_where) {
+			where_token = expect_token(f, Token_where);
+			isize prev_level = f->expr_level;
+			f->expr_level = -1;
+			where_clauses = parse_rhs_expr_list(f);
+			f->expr_level = prev_level;
+		}
+
+
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 
 
 		isize    name_count = 0;
 		isize    name_count = 0;
@@ -1964,7 +2054,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 			decls = fields->FieldList.list;
 			decls = fields->FieldList.list;
 		}
 		}
 
 
-		return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align);
+		return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align, where_token, where_clauses);
 	} break;
 	} break;
 
 
 	case Token_union: {
 	case Token_union: {
@@ -2005,6 +2095,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 			}
 			}
 		}
 		}
 
 
+		Token where_token = {};
+		Array<Ast *> where_clauses = {};
+
+		if (f->curr_token.kind == Token_where) {
+			where_token = expect_token(f, Token_where);
+			isize prev_level = f->expr_level;
+			f->expr_level = -1;
+			where_clauses = parse_rhs_expr_list(f);
+			f->expr_level = prev_level;
+		}
+
+
 		Token open = expect_token_after(f, Token_OpenBrace, "union");
 		Token open = expect_token_after(f, Token_OpenBrace, "union");
 
 
 		while (f->curr_token.kind != Token_CloseBrace &&
 		while (f->curr_token.kind != Token_CloseBrace &&
@@ -2020,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 
 
 		Token close = expect_token(f, Token_CloseBrace);
 		Token close = expect_token(f, Token_CloseBrace);
 
 
-		return ast_union_type(f, token, variants, polymorphic_params, align, no_nil);
+		return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, where_token, where_clauses);
 	} break;
 	} break;
 
 
 	case Token_enum: {
 	case Token_enum: {
@@ -2091,7 +2193,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 
 
 		bool prev_allow_range = f->allow_range;
 		bool prev_allow_range = f->allow_range;
 		f->allow_range = true;
 		f->allow_range = true;
-		elem = parse_expr(f, false);
+		elem = parse_expr(f, true);
 		f->allow_range = prev_allow_range;
 		f->allow_range = prev_allow_range;
 		if (allow_token(f, Token_Semicolon)) {
 		if (allow_token(f, Token_Semicolon)) {
 			underlying = parse_type(f);
 			underlying = parse_type(f);
@@ -2383,17 +2485,18 @@ i32 token_precedence(AstFile *f, TokenKind t) {
 	case Token_LtEq:
 	case Token_LtEq:
 	case Token_GtEq:
 	case Token_GtEq:
 		return 5;
 		return 5;
+
 	case Token_in:
 	case Token_in:
 	case Token_notin:
 	case Token_notin:
-		if (f->expr_level >= 0 || f->allow_in_expr) {
-			return 6;
+		if (f->expr_level < 0 && !f->allow_in_expr) {
+			return 0;
 		}
 		}
-		return 0;
+		/*fallthrough*/
 	case Token_Add:
 	case Token_Add:
 	case Token_Sub:
 	case Token_Sub:
 	case Token_Or:
 	case Token_Or:
 	case Token_Xor:
 	case Token_Xor:
-		return 7;
+		return 6;
 	case Token_Mul:
 	case Token_Mul:
 	case Token_Quo:
 	case Token_Quo:
 	case Token_Mod:
 	case Token_Mod:
@@ -2402,7 +2505,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
 	case Token_AndNot:
 	case Token_AndNot:
 	case Token_Shl:
 	case Token_Shl:
 	case Token_Shr:
 	case Token_Shr:
-		return 8;
+		return 7;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -2649,7 +2752,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) {
 			allow_token(f, Token_in);
 			allow_token(f, Token_in);
 			bool prev_allow_range = f->allow_range;
 			bool prev_allow_range = f->allow_range;
 			f->allow_range = true;
 			f->allow_range = true;
-			Ast *expr = parse_expr(f, false);
+			Ast *expr = parse_expr(f, true);
 			f->allow_range = prev_allow_range;
 			f->allow_range = prev_allow_range;
 
 
 			auto rhs = array_make<Ast *>(heap_allocator(), 0, 1);
 			auto rhs = array_make<Ast *>(heap_allocator(), 0, 1);
@@ -2740,7 +2843,8 @@ Ast *parse_results(AstFile *f, bool *diverging) {
 		Array<Ast *> empty_names = {};
 		Array<Ast *> empty_names = {};
 		auto list = array_make<Ast *>(heap_allocator(), 0, 1);
 		auto list = array_make<Ast *>(heap_allocator(), 0, 1);
 		Ast *type = parse_type(f);
 		Ast *type = parse_type(f);
-		array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr));
+		Token tag = {};
+		array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr));
 		return ast_field_list(f, begin_token, list);
 		return ast_field_list(f, begin_token, list);
 	}
 	}
 
 
@@ -2795,8 +2899,6 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) {
 	results = parse_results(f, &diverging);
 	results = parse_results(f, &diverging);
 
 
 	u64 tags = 0;
 	u64 tags = 0;
-	parse_proc_tags(f, &tags);
-
 	bool is_generic = false;
 	bool is_generic = false;
 
 
 	for_array(i, params->FieldList.list) {
 	for_array(i, params->FieldList.list) {
@@ -3095,6 +3197,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
 
 
 		Ast *type = nullptr;
 		Ast *type = nullptr;
 		Ast *default_value = nullptr;
 		Ast *default_value = nullptr;
+		Token tag = {};
 
 
 		expect_token_after(f, Token_Colon, "field list");
 		expect_token_after(f, Token_Colon, "field list");
 		if (f->curr_token.kind != Token_Eq) {
 		if (f->curr_token.kind != Token_Eq) {
@@ -3132,16 +3235,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
 			syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
 			syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
 		}
 		}
 
 
+		if (type != nullptr && default_value == nullptr) {
+			if (f->curr_token.kind == Token_String) {
+				tag = expect_token(f, Token_String);
+				if ((allowed_flags & FieldFlag_Tags) == 0) {
+					syntax_error(tag, "Field tags are only allowed within structures");
+				}
+			}
+		}
+
 		parse_expect_field_separator(f, type);
 		parse_expect_field_separator(f, type);
-		Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
+		Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
 		array_add(&params, param);
 		array_add(&params, param);
 
 
 
 
 		while (f->curr_token.kind != follow &&
 		while (f->curr_token.kind != follow &&
 		       f->curr_token.kind != Token_EOF) {
 		       f->curr_token.kind != Token_EOF) {
 			CommentGroup *docs = f->lead_comment;
 			CommentGroup *docs = f->lead_comment;
-
 			u32 set_flags = parse_field_prefixes(f);
 			u32 set_flags = parse_field_prefixes(f);
+			Token tag = {};
 			Array<Ast *> names = parse_ident_list(f, allow_poly_names);
 			Array<Ast *> names = parse_ident_list(f, allow_poly_names);
 			if (names.count == 0) {
 			if (names.count == 0) {
 				syntax_error(f->curr_token, "Empty field declaration");
 				syntax_error(f->curr_token, "Empty field declaration");
@@ -3184,9 +3296,18 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
 				syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
 				syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
 			}
 			}
 
 
+			if (type != nullptr && default_value == nullptr) {
+				if (f->curr_token.kind == Token_String) {
+					tag = expect_token(f, Token_String);
+					if ((allowed_flags & FieldFlag_Tags) == 0) {
+						syntax_error(tag, "Field tags are only allowed within structures");
+					}
+				}
+			}
+
 
 
 			bool ok = parse_expect_field_separator(f, param);
 			bool ok = parse_expect_field_separator(f, param);
-			Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
+			Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
 			array_add(&params, param);
 			array_add(&params, param);
 
 
 			if (!ok) {
 			if (!ok) {
@@ -3210,8 +3331,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
 		token.pos = ast_token(type).pos;
 		token.pos = ast_token(type).pos;
 		names[0] = ast_ident(f, token);
 		names[0] = ast_ident(f, token);
 		u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
 		u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
-
-		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);
 		array_add(&params, param);
 	}
 	}
 
 
@@ -3758,9 +3879,55 @@ Ast *parse_stmt(AstFile *f) {
 	Token token = f->curr_token;
 	Token token = f->curr_token;
 	switch (token.kind) {
 	switch (token.kind) {
 	// Operands
 	// Operands
-	case Token_context: // Also allows for `context =`
 	case Token_inline:
 	case Token_inline:
+		if (peek_token_kind(f, Token_for)) {
+			Token inline_token = expect_token(f, Token_inline);
+			Token for_token = expect_token(f, Token_for);
+			Ast *val0 = nullptr;
+			Ast *val1 = nullptr;
+			Token in_token = {};
+			Ast *expr = nullptr;
+			Ast *body = nullptr;
+
+			bool bad_stmt = false;
+
+			if (f->curr_token.kind != Token_in) {
+				Array<Ast *> idents = parse_ident_list(f, false);
+				switch (idents.count) {
+				case 1:
+					val0 = idents[0];
+					break;
+				case 2:
+					val0 = idents[0];
+					val1 = idents[1];
+					break;
+				default:
+					syntax_error(for_token, "Expected either 1 or 2 identifiers");
+					bad_stmt = true;
+					break;
+				}
+			}
+			in_token = expect_token(f, Token_in);
+
+			bool prev_allow_range = f->allow_range;
+			f->allow_range = true;
+			expr = parse_expr(f, true);
+			f->allow_range = prev_allow_range;
+
+			if (allow_token(f, Token_do)) {
+				body = convert_stmt_to_body(f, parse_stmt(f));
+			} else {
+				body = parse_block_stmt(f, false);
+			}
+			if (bad_stmt) {
+				return ast_bad_stmt(f, inline_token, f->curr_token);
+			}
+			return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body);
+		}
+		/* fallthrough */
 	case Token_no_inline:
 	case Token_no_inline:
+	case Token_context: // Also allows for `context =`
+	case Token_proc:
 	case Token_Ident:
 	case Token_Ident:
 	case Token_Integer:
 	case Token_Integer:
 	case Token_Float:
 	case Token_Float:
@@ -3808,34 +3975,6 @@ Ast *parse_stmt(AstFile *f) {
 		return s;
 		return s;
 	}
 	}
 
 
-	// case Token_static: {
-	// 	CommentGroup *docs = f->lead_comment;
-	// 	Token token = expect_token(f, Token_static);
-
-	// 	Ast *decl = nullptr;
-	// 	Array<Ast *> list = parse_lhs_expr_list(f);
-	// 	if (list.count == 0) {
-	// 		syntax_error(token, "Illegal use of 'static' statement");
-	// 		expect_semicolon(f, nullptr);
-	// 		return ast_bad_stmt(f, token, f->curr_token);
-	// 	}
-
-	// 	expect_token_after(f, Token_Colon, "identifier list");
-	// 	decl = parse_value_decl(f, list, docs);
-
-	// 	if (decl != nullptr && decl->kind == Ast_ValueDecl) {
-	// 		if (decl->ValueDecl.is_mutable) {
-	// 			decl->ValueDecl.is_static = true;
-	// 		} else {
-	// 			error(token, "'static' may only be currently used with variable declaration");
-	// 		}
-	// 		return decl;
-	// 	}
-
-	// 	syntax_error(token, "Illegal use of 'static' statement");
-	// 	return ast_bad_stmt(f, token, f->curr_token);
-	// } break;
-
 	case Token_using: {
 	case Token_using: {
 		CommentGroup *docs = f->lead_comment;
 		CommentGroup *docs = f->lead_comment;
 		Token token = expect_token(f, Token_using);
 		Token token = expect_token(f, Token_using);
@@ -3909,12 +4048,10 @@ Ast *parse_stmt(AstFile *f) {
 		} else if (tag == "assert") {
 		} else if (tag == "assert") {
 			Ast *t = ast_basic_directive(f, hash_token, tag);
 			Ast *t = ast_basic_directive(f, hash_token, tag);
 			return ast_expr_stmt(f, parse_call_expr(f, t));
 			return ast_expr_stmt(f, parse_call_expr(f, t));
-		} /* else if (name.string == "no_deferred") {
-			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'?");
 			syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
 			s = ast_bad_stmt(f, token, f->curr_token);
 			s = ast_bad_stmt(f, token, f->curr_token);
 		} else {
 		} else {
@@ -4037,7 +4174,6 @@ bool init_parser(Parser *p) {
 	map_init(&p->package_map, heap_allocator());
 	map_init(&p->package_map, heap_allocator());
 	array_init(&p->packages, heap_allocator());
 	array_init(&p->packages, heap_allocator());
 	array_init(&p->package_imports, heap_allocator());
 	array_init(&p->package_imports, heap_allocator());
-	array_init(&p->files_to_process, heap_allocator());
 	gb_mutex_init(&p->file_add_mutex);
 	gb_mutex_init(&p->file_add_mutex);
 	gb_mutex_init(&p->file_decl_mutex);
 	gb_mutex_init(&p->file_decl_mutex);
 	return true;
 	return true;
@@ -4060,7 +4196,6 @@ void destroy_parser(Parser *p) {
 #endif
 #endif
 	array_free(&p->packages);
 	array_free(&p->packages);
 	array_free(&p->package_imports);
 	array_free(&p->package_imports);
-	array_free(&p->files_to_process);
 	string_set_destroy(&p->imported_files);
 	string_set_destroy(&p->imported_files);
 	map_destroy(&p->package_map);
 	map_destroy(&p->package_map);
 	gb_mutex_destroy(&p->file_add_mutex);
 	gb_mutex_destroy(&p->file_add_mutex);
@@ -4077,19 +4212,32 @@ void parser_add_package(Parser *p, AstPackage *pkg) {
 		if (found) {
 		if (found) {
 			GB_ASSERT(pkg->files.count > 0);
 			GB_ASSERT(pkg->files.count > 0);
 			AstFile *f = pkg->files[0];
 			AstFile *f = pkg->files[0];
-			error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name));
+			syntax_error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name));
 			GB_ASSERT((*found)->files.count > 0);
 			GB_ASSERT((*found)->files.count > 0);
 			TokenPos pos = (*found)->files[0]->package_token.pos;
 			TokenPos pos = (*found)->files[0]->package_token.pos;
-			gb_printf_err("\tpreviously declared at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column);
+			error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
 		} else {
 		} else {
 			map_set(&p->package_map, key, pkg);
 			map_set(&p->package_map, key, pkg);
 		}
 		}
 	}
 	}
 }
 }
 
 
+ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file);
+
+WORKER_TASK_PROC(parser_worker_proc) {
+	ParserWorkerData *wd = cast(ParserWorkerData *)data;
+	ParseFileError err = process_imported_file(wd->parser, wd->imported_file);
+	return cast(isize)err;
+}
+
+
 void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
 void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
-	ImportedFile f = {pkg, fi, pos, p->files_to_process.count};
-	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) {
 	switch (rd_err) {
 	case ReadDirectory_InvalidPath:
 	case ReadDirectory_InvalidPath:
-		error(pos, "Invalid path: %.*s", LIT(rel_path));
+		syntax_error(pos, "Invalid path: %.*s", LIT(rel_path));
 		return false;
 		return false;
 	case ReadDirectory_NotExists:
 	case ReadDirectory_NotExists:
-		error(pos, "Path does not exist: %.*s", LIT(rel_path));
+		syntax_error(pos, "Path does not exist: %.*s", LIT(rel_path));
 		return false;
 		return false;
 	case ReadDirectory_Permission:
 	case ReadDirectory_Permission:
-		error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
+		syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
 		return false;
 		return false;
 	case ReadDirectory_NotDir:
 	case ReadDirectory_NotDir:
-		error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
+		syntax_error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
 		return false;
 		return false;
 	case ReadDirectory_Empty:
 	case ReadDirectory_Empty:
-		error(pos, "Empty directory: %.*s", LIT(rel_path));
+		syntax_error(pos, "Empty directory: %.*s", LIT(rel_path));
 		return false;
 		return false;
 	case ReadDirectory_Unknown:
 	case ReadDirectory_Unknown:
-		error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
+		syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
 		return false;
 		return false;
 	}
 	}
 
 
@@ -4257,7 +4405,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
 
 
 	String file_str = {};
 	String file_str = {};
 	if (colon_pos == 0) {
 	if (colon_pos == 0) {
-		error(node, "Expected a collection name");
+		syntax_error(node, "Expected a collection name");
 		return false;
 		return false;
 	}
 	}
 
 
@@ -4272,32 +4420,19 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
 	if (has_windows_drive) {
 	if (has_windows_drive) {
 		String sub_file_path = substring(file_str, 3, file_str.len);
 		String sub_file_path = substring(file_str, 3, file_str.len);
 		if (!is_import_path_valid(sub_file_path)) {
 		if (!is_import_path_valid(sub_file_path)) {
-			error(node, "Invalid import path: '%.*s'", LIT(file_str));
+			syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
 			return false;
 			return false;
 		}
 		}
 	} else if (!is_import_path_valid(file_str)) {
 	} else if (!is_import_path_valid(file_str)) {
-		error(node, "Invalid import path: '%.*s'", LIT(file_str));
+		syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
 		return false;
 		return false;
 	}
 	}
 
 
 
 
-	if (is_package_name_reserved(file_str)) {
-		*path = file_str;
-		return true;
-	}
-
-	if (file_mutex) gb_mutex_lock(file_mutex);
-	defer (if (file_mutex) gb_mutex_unlock(file_mutex));
-
-
-	if (node->kind == Ast_ForeignImportDecl) {
-		node->ForeignImportDecl.collection_name = collection_name;
-	}
-
 	if (collection_name.len > 0) {
 	if (collection_name.len > 0) {
 		if (collection_name == "system") {
 		if (collection_name == "system") {
 			if (node->kind != Ast_ForeignImportDecl) {
 			if (node->kind != Ast_ForeignImportDecl) {
-				error(node, "The library collection 'system' is restrict for 'foreign_library'");
+				syntax_error(node, "The library collection 'system' is restrict for 'foreign_library'");
 				return false;
 				return false;
 			} else {
 			} else {
 				*path = file_str;
 				*path = file_str;
@@ -4305,7 +4440,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
 			}
 			}
 		} else if (!find_library_collection_path(collection_name, &base_dir)) {
 		} else if (!find_library_collection_path(collection_name, &base_dir)) {
 			// NOTE(bill): It's a naughty name
 			// NOTE(bill): It's a naughty name
-			error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
+			syntax_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
 			return false;
 			return false;
 		}
 		}
 	} else {
 	} else {
@@ -4324,6 +4459,20 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
 #endif
 #endif
 	}
 	}
 
 
+
+	if (is_package_name_reserved(file_str)) {
+		*path = file_str;
+		return true;
+	}
+
+	if (file_mutex) gb_mutex_lock(file_mutex);
+	defer (if (file_mutex) gb_mutex_unlock(file_mutex));
+
+
+	if (node->kind == Ast_ForeignImportDecl) {
+		node->ForeignImportDecl.collection_name = collection_name;
+	}
+
 	if (has_windows_drive) {
 	if (has_windows_drive) {
 		*path = file_str;
 		*path = file_str;
 	} else {
 	} else {
@@ -4412,7 +4561,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *>
 				array_add(&fl->fullpaths, fullpath);
 				array_add(&fl->fullpaths, fullpath);
 			}
 			}
 			if (fl->fullpaths.count == 0) {
 			if (fl->fullpaths.count == 0) {
-				error(decls[i], "No foreign paths found");
+				syntax_error(decls[i], "No foreign paths found");
 				decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
 				decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
 				goto end;
 				goto end;
 			}
 			}
@@ -4461,7 +4610,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
 			is_notted = true;
 			is_notted = true;
 			p = substring(p, 1, p.len);
 			p = substring(p, 1, p.len);
 			if (p.len == 0) {
 			if (p.len == 0) {
-				error(token_for_pos, "Expected a build platform after '!'");
+				syntax_error(token_for_pos, "Expected a build platform after '!'");
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -4490,7 +4639,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
 				}
 				}
 			}
 			}
 			if (os == TargetOs_Invalid && arch == TargetArch_Invalid) {
 			if (os == TargetOs_Invalid && arch == TargetArch_Invalid) {
-				error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p));
+				syntax_error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p));
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -4536,11 +4685,11 @@ bool parse_file(Parser *p, AstFile *f) {
 	Token package_name = expect_token_after(f, Token_Ident, "package");
 	Token package_name = expect_token_after(f, Token_Ident, "package");
 	if (package_name.kind == Token_Ident) {
 	if (package_name.kind == Token_Ident) {
 		if (package_name.string == "_") {
 		if (package_name.string == "_") {
-			error(package_name, "Invalid package name '_'");
+			syntax_error(package_name, "Invalid package name '_'");
 		} else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") {
 		} else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") {
-			error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
+			syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
 		} else if (is_package_name_reserved(package_name.string)) {
 		} else if (is_package_name_reserved(package_name.string)) {
-			error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
+			syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
 		}
 		}
 	}
 	}
 	f->package_name = package_name.string;
 	f->package_name = package_name.string;
@@ -4590,9 +4739,9 @@ bool parse_file(Parser *p, AstFile *f) {
 }
 }
 
 
 
 
-ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) {
+ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file) {
 	AstPackage *pkg = imported_file.pkg;
 	AstPackage *pkg = imported_file.pkg;
-	FileInfo *fi = &imported_file.fi;
+	FileInfo const *fi = &imported_file.fi;
 	TokenPos pos = imported_file.pos;
 	TokenPos pos = imported_file.pos;
 
 
 	AstFile *file = gb_alloc_item(heap_allocator(), AstFile);
 	AstFile *file = gb_alloc_item(heap_allocator(), AstFile);
@@ -4607,38 +4756,35 @@ ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) {
 	if (err != ParseFile_None) {
 	if (err != ParseFile_None) {
 		if (err == ParseFile_EmptyFile) {
 		if (err == ParseFile_EmptyFile) {
 			if (fi->fullpath == p->init_fullpath) {
 			if (fi->fullpath == p->init_fullpath) {
-				error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath));
+				syntax_error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath));
 				gb_exit(1);
 				gb_exit(1);
 			}
 			}
-			goto skip;
-		}
+		} else {
+			switch (err) {
+			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)) {
 	if (parse_file(p, file)) {
 		gb_mutex_lock(&p->file_add_mutex);
 		gb_mutex_lock(&p->file_add_mutex);
 		defer (gb_mutex_unlock(&p->file_add_mutex));
 		defer (gb_mutex_unlock(&p->file_add_mutex));
@@ -4648,42 +4794,33 @@ skip:
 		if (pkg->name.len == 0) {
 		if (pkg->name.len == 0) {
 			pkg->name = file->package_name;
 			pkg->name = file->package_name;
 		} else if (file->tokens.count > 0 && pkg->name != file->package_name) {
 		} else if (file->tokens.count > 0 && pkg->name != file->package_name) {
-			error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name));
+			syntax_error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name));
 		}
 		}
 
 
 		p->total_line_count += file->tokenizer.line_count;
 		p->total_line_count += file->tokenizer.line_count;
 		p->total_token_count += file->tokens.count;
 		p->total_token_count += file->tokens.count;
 	}
 	}
+
 	return ParseFile_None;
 	return ParseFile_None;
 }
 }
 
 
 
 
-GB_THREAD_PROC(parse_worker_file_proc) {
-	if (thread == nullptr) return 0;
-	auto *p = cast(Parser *)thread->user_data;
-	isize index = thread->user_index;
-	gb_mutex_lock(&p->file_add_mutex);
-	auto file_to_process = p->files_to_process[index];
-	gb_mutex_unlock(&p->file_add_mutex);
-	ParseFileError err = process_imported_file(p, file_to_process);
-	return cast(isize)err;
-}
-
 ParseFileError parse_packages(Parser *p, String init_filename) {
 ParseFileError parse_packages(Parser *p, String init_filename) {
 	GB_ASSERT(init_filename.text[init_filename.len] == 0);
 	GB_ASSERT(init_filename.text[init_filename.len] == 0);
 
 
-	// char *fullpath_str = gb_path_get_full_name(heap_allocator(), cast(char const *)&init_filename[0]);
-	// 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);
 	String init_fullpath = path_to_full_path(heap_allocator(), init_filename);
 	if (!path_is_directory(init_fullpath)) {
 	if (!path_is_directory(init_fullpath)) {
 		String const ext = str_lit(".odin");
 		String const ext = str_lit(".odin");
 		if (!string_ends_with(init_fullpath, ext)) {
 		if (!string_ends_with(init_fullpath, ext)) {
-			gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
+			error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
 			return ParseFile_WrongExtension;
 			return ParseFile_WrongExtension;
 		}
 		}
 	}
 	}
 
 
-
 	TokenPos init_pos = {};
 	TokenPos init_pos = {};
 	if (!build_context.generate_docs) {
 	if (!build_context.generate_docs) {
 		String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
 		String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
@@ -4693,76 +4830,17 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
 	try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init);
 	try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init);
 	p->init_fullpath = init_fullpath;
 	p->init_fullpath = init_fullpath;
 
 
-#if 1
-	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) {
 		if (err != ParseFile_None) {
 			return err;
 			return err;
 		}
 		}
 	}
 	}
-#endif
 
 
 	return ParseFile_None;
 	return ParseFile_None;
 }
 }

+ 46 - 14
src/parser.hpp

@@ -134,13 +134,26 @@ struct Parser {
 	Map<AstPackage *>      package_map; // Key: String (package name)
 	Map<AstPackage *>      package_map; // Key: String (package name)
 	Array<AstPackage *>    packages;
 	Array<AstPackage *>    packages;
 	Array<ImportedPackage> package_imports;
 	Array<ImportedPackage> package_imports;
-	Array<ImportedFile>    files_to_process;
+	isize                  file_to_process_count;
 	isize                  total_token_count;
 	isize                  total_token_count;
 	isize                  total_line_count;
 	isize                  total_line_count;
 	gbMutex                file_add_mutex;
 	gbMutex                file_add_mutex;
 	gbMutex                file_decl_mutex;
 	gbMutex                file_decl_mutex;
 };
 };
 
 
+
+gb_global ThreadPool parser_thread_pool = {};
+
+struct ParserWorkerData {
+	Parser *parser;
+	ImportedFile imported_file;
+};
+
+
+
+
+
+
 enum ProcInlining {
 enum ProcInlining {
 	ProcInlining_none = 0,
 	ProcInlining_none = 0,
 	ProcInlining_inline = 1,
 	ProcInlining_inline = 1,
@@ -186,11 +199,12 @@ enum FieldFlag {
 	FieldFlag_c_vararg  = 1<<3,
 	FieldFlag_c_vararg  = 1<<3,
 	FieldFlag_auto_cast = 1<<4,
 	FieldFlag_auto_cast = 1<<4,
 
 
+	FieldFlag_Tags = 1<<10,
 
 
 	FieldFlag_Results   = 1<<16,
 	FieldFlag_Results   = 1<<16,
 
 
 	FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
 	FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
-	FieldFlag_Struct    = FieldFlag_using,
+	FieldFlag_Struct    = FieldFlag_using|FieldFlag_Tags,
 };
 };
 
 
 enum StmtAllowFlag {
 enum StmtAllowFlag {
@@ -208,6 +222,7 @@ enum StmtAllowFlag {
 	AST_KIND(Undef,          "undef",           Token) \
 	AST_KIND(Undef,          "undef",           Token) \
 	AST_KIND(BasicLit,       "basic literal",   struct { \
 	AST_KIND(BasicLit,       "basic literal",   struct { \
 		Token token; \
 		Token token; \
+		ExactValue value; \
 	}) \
 	}) \
 	AST_KIND(BasicDirective, "basic directive", struct { \
 	AST_KIND(BasicDirective, "basic directive", struct { \
 		Token  token; \
 		Token  token; \
@@ -228,11 +243,14 @@ enum StmtAllowFlag {
 		Ast *body; \
 		Ast *body; \
 		u64  tags; \
 		u64  tags; \
 		ProcInlining inlining; \
 		ProcInlining inlining; \
+		Token where_token; \
+		Array<Ast *> where_clauses; \
 	}) \
 	}) \
 	AST_KIND(CompoundLit, "compound literal", struct { \
 	AST_KIND(CompoundLit, "compound literal", struct { \
 		Ast *type; \
 		Ast *type; \
 		Array<Ast *> elems; \
 		Array<Ast *> elems; \
 		Token open, close; \
 		Token open, close; \
+		i64 max_count; \
 	}) \
 	}) \
 AST_KIND(_ExprBegin,  "",  bool) \
 AST_KIND(_ExprBegin,  "",  bool) \
 	AST_KIND(BadExpr,      "bad expression",         struct { Token begin, end; }) \
 	AST_KIND(BadExpr,      "bad expression",         struct { Token begin, end; }) \
@@ -325,6 +343,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
 		Ast *expr; \
 		Ast *expr; \
 		Ast *body; \
 		Ast *body; \
 	}) \
 	}) \
+	AST_KIND(InlineRangeStmt, "inline range statement", struct { \
+		Token inline_token; \
+		Token for_token; \
+		Ast *val0; \
+		Ast *val1; \
+		Token in_token; \
+		Ast *expr; \
+		Ast *body; \
+	}) \
 	AST_KIND(CaseClause, "case clause", struct { \
 	AST_KIND(CaseClause, "case clause", struct { \
 		Token token;             \
 		Token token;             \
 		Array<Ast *> list;   \
 		Array<Ast *> list;   \
@@ -412,6 +439,7 @@ AST_KIND(_DeclEnd,   "", bool) \
 		Array<Ast *> names;         \
 		Array<Ast *> names;         \
 		Ast *        type;          \
 		Ast *        type;          \
 		Ast *        default_value; \
 		Ast *        default_value; \
+		Token        tag;           \
 		u32              flags;     \
 		u32              flags;     \
 		CommentGroup *   docs;      \
 		CommentGroup *   docs;      \
 		CommentGroup *   comment;   \
 		CommentGroup *   comment;   \
@@ -465,20 +493,24 @@ AST_KIND(_TypeBegin, "", bool) \
 		Ast *elem; \
 		Ast *elem; \
 	}) \
 	}) \
 	AST_KIND(StructType, "struct type", struct { \
 	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 { \
 	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 { \
 	AST_KIND(EnumType, "enum type", struct { \
 		Token        token; \
 		Token        token; \

+ 2 - 2
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) {
 		if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) {
 			j = j2;
 			j = j2;
 		}
 		}
-		if (pq->cmp(&pq->queue[0], i, j) < 0) break;
+		if (pq->cmp(&pq->queue[0], j, i) >= 0) break;
 
 
 		pq->swap(&pq->queue[0], i, j);
 		pq->swap(&pq->queue[0], i, j);
 		i = j;
 		i = j;
@@ -32,7 +32,7 @@ template <typename T>
 void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
 void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
 	while (0 <= j && j < pq->queue.count) {
 	while (0 <= j && j < pq->queue.count) {
 		isize i = (j-1)/2;
 		isize i = (j-1)/2;
-		if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) {
+		if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
 			break;
 			break;
 		}
 		}
 		pq->swap(&pq->queue[0], i, j);
 		pq->swap(&pq->queue[0], i, j);

+ 70 - 0
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;
+}

+ 84 - 2
src/string.cpp

@@ -404,7 +404,7 @@ String16 string_to_string16(gbAllocator a, String s) {
 	}
 	}
 	text[len] = 0;
 	text[len] = 0;
 
 
-	return make_string16(text, len-1);
+	return make_string16(text, len);
 }
 }
 
 
 
 
@@ -440,12 +440,94 @@ String string16_to_string(gbAllocator a, String16 s) {
 
 
 
 
 
 
+bool is_printable(Rune r) {
+	if (r <= 0xff) {
+		if (0x20 <= r && r <= 0x7e) {
+			return true;
+		}
+		if (0xa1 <= r && r <= 0xff) {
+			return r != 0xad;
+		}
+		return false;
+	}
+	return false;
+}
 
 
+gb_global char const lower_hex[] = "0123456789abcdef";
+
+String quote_to_ascii(gbAllocator a, String str, u8 quote='"') {
+	u8 *s = str.text;
+	isize n = str.len;
+	auto buf = array_make<u8>(a, 0, n);
+	array_add(&buf, quote);
+	for (isize width = 0; n > 0; s += width, n -= width) {
+		Rune r = cast(Rune)s[0];
+		width = 1;
+		if (r >= 0x80) {
+			width = gb_utf8_decode(s, n, &r);
+		}
+		if (width == 1 && r == GB_RUNE_INVALID) {
+			array_add(&buf, cast(u8)'\\');
+			array_add(&buf, cast(u8)'x');
+			array_add(&buf, cast(u8)lower_hex[s[0]>>4]);
+			array_add(&buf, cast(u8)lower_hex[s[0]&0xf]);
+			continue;
+		}
 
 
+		if (r == quote || r == '\\') {
+			array_add(&buf, cast(u8)'\\');
+			array_add(&buf, u8(r));
+			continue;
+		}
+		if (r < 0x80 && is_printable(r)) {
+			array_add(&buf, u8(r));
+			continue;
+		}
+		switch (r) {
+		case '\a':
+		case '\b':
+		case '\f':
+		case '\n':
+		case '\r':
+		case '\t':
+		case '\v':
+		default:
+			if (r < ' ') {
+				u8 b = cast(u8)r;
+				array_add(&buf, cast(u8)'\\');
+				array_add(&buf, cast(u8)'x');
+				array_add(&buf, cast(u8)lower_hex[b>>4]);
+				array_add(&buf, cast(u8)lower_hex[b&0xf]);
+			}
+			if (r > GB_RUNE_MAX) {
+				r = 0XFFFD;
+			}
+			if (r < 0x10000) {
+				u8 b = cast(u8)r;
+				array_add(&buf, cast(u8)'\\');
+				array_add(&buf, cast(u8)'u');
+				for (isize i = 12; i >= 0; i -= 4) {
+					array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
+				}
+			} else {
+				u8 b = cast(u8)r;
+				array_add(&buf, cast(u8)'\\');
+				array_add(&buf, cast(u8)'U');
+				for (isize i = 28; i >= 0; i -= 4) {
+					array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]);
+				}
+			}
+		}
+	}
 
 
 
 
 
 
-
+	array_add(&buf, quote);
+	String res = {};
+	res.text = buf.data;
+	res.len = buf.count;
+	return res;
+}
 
 
 
 
 
 

+ 184 - 0
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;
+}
+

+ 13 - 1
src/tokenizer.cpp

@@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
 	TOKEN_KIND(Token_package,     "package"),     \
 	TOKEN_KIND(Token_package,     "package"),     \
 	TOKEN_KIND(Token_typeid,      "typeid"),      \
 	TOKEN_KIND(Token_typeid,      "typeid"),      \
 	TOKEN_KIND(Token_when,        "when"),        \
 	TOKEN_KIND(Token_when,        "when"),        \
+	TOKEN_KIND(Token_where,       "where"),       \
 	TOKEN_KIND(Token_if,          "if"),          \
 	TOKEN_KIND(Token_if,          "if"),          \
 	TOKEN_KIND(Token_else,        "else"),        \
 	TOKEN_KIND(Token_else,        "else"),        \
 	TOKEN_KIND(Token_for,         "for"),         \
 	TOKEN_KIND(Token_for,         "for"),         \
@@ -400,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) {
 	va_end(va);
 	va_end(va);
 }
 }
 
 
+void syntax_error(TokenPos pos, char *fmt, ...) {
+	va_list va;
+	va_start(va, fmt);
+	Token token = {};
+	token.pos = pos;
+	syntax_error_va(token, fmt, va);
+	va_end(va);
+}
+
 void syntax_warning(Token token, char *fmt, ...) {
 void syntax_warning(Token token, char *fmt, ...) {
 	va_list va;
 	va_list va;
 	va_start(va, fmt);
 	va_start(va, fmt);
@@ -745,9 +755,11 @@ exponent:
 		scan_mantissa(t, 10);
 		scan_mantissa(t, 10);
 	}
 	}
 
 
-	if (t->curr_rune == 'i') {
+	switch (t->curr_rune) {
+	case 'i': case 'j': case 'k':
 		token.kind = Token_Imag;
 		token.kind = Token_Imag;
 		advance_to_next_rune(t);
 		advance_to_next_rune(t);
+		break;
 	}
 	}
 
 
 end:
 end:

+ 202 - 70
src/types.cpp

@@ -32,6 +32,9 @@ enum BasicKind {
 	Basic_complex64,
 	Basic_complex64,
 	Basic_complex128,
 	Basic_complex128,
 
 
+	Basic_quaternion128,
+	Basic_quaternion256,
+
 	Basic_int,
 	Basic_int,
 	Basic_uint,
 	Basic_uint,
 	Basic_uintptr,
 	Basic_uintptr,
@@ -66,6 +69,7 @@ enum BasicKind {
 	Basic_UntypedInteger,
 	Basic_UntypedInteger,
 	Basic_UntypedFloat,
 	Basic_UntypedFloat,
 	Basic_UntypedComplex,
 	Basic_UntypedComplex,
+	Basic_UntypedQuaternion,
 	Basic_UntypedString,
 	Basic_UntypedString,
 	Basic_UntypedRune,
 	Basic_UntypedRune,
 	Basic_UntypedNil,
 	Basic_UntypedNil,
@@ -82,17 +86,18 @@ enum BasicFlag {
 	BasicFlag_Unsigned    = GB_BIT(2),
 	BasicFlag_Unsigned    = GB_BIT(2),
 	BasicFlag_Float       = GB_BIT(3),
 	BasicFlag_Float       = GB_BIT(3),
 	BasicFlag_Complex     = GB_BIT(4),
 	BasicFlag_Complex     = GB_BIT(4),
-	BasicFlag_Pointer     = GB_BIT(5),
-	BasicFlag_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_EndianLittle = GB_BIT(13),
 	BasicFlag_EndianBig    = GB_BIT(14),
 	BasicFlag_EndianBig    = GB_BIT(14),
 
 
-	BasicFlag_Numeric        = BasicFlag_Integer | BasicFlag_Float   | BasicFlag_Complex,
+	BasicFlag_Numeric        = BasicFlag_Integer | BasicFlag_Float   | BasicFlag_Complex | BasicFlag_Quaternion,
 	BasicFlag_Ordered        = BasicFlag_Integer | BasicFlag_Float   | BasicFlag_String  | BasicFlag_Pointer | BasicFlag_Rune,
 	BasicFlag_Ordered        = BasicFlag_Integer | BasicFlag_Float   | BasicFlag_String  | BasicFlag_Pointer | BasicFlag_Rune,
 	BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float   | BasicFlag_Rune,
 	BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float   | BasicFlag_Rune,
 	BasicFlag_ConstantType   = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String  | BasicFlag_Pointer | BasicFlag_Rune,
 	BasicFlag_ConstantType   = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String  | BasicFlag_Pointer | BasicFlag_Rune,
@@ -107,21 +112,23 @@ struct BasicType {
 
 
 struct TypeStruct {
 struct TypeStruct {
 	Array<Entity *> fields;
 	Array<Entity *> fields;
-	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_params; // Type_Tuple
 	Type *     polymorphic_parent;
 	Type *     polymorphic_parent;
 
 
-	i64      custom_align; // NOTE(bill): Only used in structs at the moment
+	i64      custom_align;
 	Entity * names;
 	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 {
 struct TypeUnion {
@@ -131,12 +138,11 @@ struct TypeUnion {
 	i64           variant_block_size;
 	i64           variant_block_size;
 	i64           custom_align;
 	i64           custom_align;
 	i64           tag_size;
 	i64           tag_size;
+	Type *        polymorphic_params; // Type_Tuple
+	Type *        polymorphic_parent;
 	bool          no_nil;
 	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                                        \
 #define TYPE_KINDS                                        \
@@ -184,7 +190,9 @@ struct TypeUnion {
 	TYPE_KIND(Tuple, struct {                             \
 	TYPE_KIND(Tuple, struct {                             \
 		Array<Entity *> variables; /* Entity_Variable */  \
 		Array<Entity *> variables; /* Entity_Variable */  \
 		Array<i64>      offsets;                          \
 		Array<i64>      offsets;                          \
+		bool            are_offsets_being_processed;      \
 		bool            are_offsets_set;                  \
 		bool            are_offsets_set;                  \
+		bool            is_packed;                        \
 	})                                                    \
 	})                                                    \
 	TYPE_KIND(Proc, struct {                              \
 	TYPE_KIND(Proc, struct {                              \
 		Ast *node;                                        \
 		Ast *node;                                        \
@@ -195,9 +203,9 @@ struct TypeUnion {
 		i32      result_count;                            \
 		i32      result_count;                            \
 		Array<Type *> abi_compat_params;                  \
 		Array<Type *> abi_compat_params;                  \
 		Type *   abi_compat_result_type;                  \
 		Type *   abi_compat_result_type;                  \
-		bool     return_by_pointer;                       \
-		bool     variadic;                                \
 		i32      variadic_index;                          \
 		i32      variadic_index;                          \
+		bool     variadic;                                \
+		bool     abi_types_set;                           \
 		bool     require_results;                         \
 		bool     require_results;                         \
 		bool     c_vararg;                                \
 		bool     c_vararg;                                \
 		bool     is_polymorphic;                          \
 		bool     is_polymorphic;                          \
@@ -205,6 +213,7 @@ struct TypeUnion {
 		bool     has_proc_default_values;                 \
 		bool     has_proc_default_values;                 \
 		bool     has_named_results;                       \
 		bool     has_named_results;                       \
 		bool     diverging; /* no return */               \
 		bool     diverging; /* no return */               \
+		bool     return_by_pointer;                       \
 		u64      tags;                                    \
 		u64      tags;                                    \
 		isize    specialization_count;                    \
 		isize    specialization_count;                    \
 		ProcCallingConvention calling_convention;         \
 		ProcCallingConvention calling_convention;         \
@@ -341,6 +350,9 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_complex64,         BasicFlag_Complex,                          8, STR_LIT("complex64")}},
 	{Type_Basic, {Basic_complex64,         BasicFlag_Complex,                          8, STR_LIT("complex64")}},
 	{Type_Basic, {Basic_complex128,        BasicFlag_Complex,                         16, STR_LIT("complex128")}},
 	{Type_Basic, {Basic_complex128,        BasicFlag_Complex,                         16, STR_LIT("complex128")}},
 
 
+	{Type_Basic, {Basic_quaternion128,     BasicFlag_Quaternion,                      16, STR_LIT("quaternion128")}},
+	{Type_Basic, {Basic_quaternion256,     BasicFlag_Quaternion,                      32, STR_LIT("quaternion256")}},
+
 	{Type_Basic, {Basic_int,               BasicFlag_Integer,                         -1, STR_LIT("int")}},
 	{Type_Basic, {Basic_int,               BasicFlag_Integer,                         -1, STR_LIT("int")}},
 	{Type_Basic, {Basic_uint,              BasicFlag_Integer | BasicFlag_Unsigned,    -1, STR_LIT("uint")}},
 	{Type_Basic, {Basic_uint,              BasicFlag_Integer | BasicFlag_Unsigned,    -1, STR_LIT("uint")}},
 	{Type_Basic, {Basic_uintptr,           BasicFlag_Integer | BasicFlag_Unsigned,    -1, STR_LIT("uintptr")}},
 	{Type_Basic, {Basic_uintptr,           BasicFlag_Integer | BasicFlag_Unsigned,    -1, STR_LIT("uintptr")}},
@@ -376,6 +388,7 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_UntypedInteger,    BasicFlag_Integer    | BasicFlag_Untyped,   0, STR_LIT("untyped integer")}},
 	{Type_Basic, {Basic_UntypedInteger,    BasicFlag_Integer    | BasicFlag_Untyped,   0, STR_LIT("untyped integer")}},
 	{Type_Basic, {Basic_UntypedFloat,      BasicFlag_Float      | BasicFlag_Untyped,   0, STR_LIT("untyped float")}},
 	{Type_Basic, {Basic_UntypedFloat,      BasicFlag_Float      | BasicFlag_Untyped,   0, STR_LIT("untyped float")}},
 	{Type_Basic, {Basic_UntypedComplex,    BasicFlag_Complex    | BasicFlag_Untyped,   0, STR_LIT("untyped complex")}},
 	{Type_Basic, {Basic_UntypedComplex,    BasicFlag_Complex    | BasicFlag_Untyped,   0, STR_LIT("untyped complex")}},
+	{Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped,   0, STR_LIT("untyped quaternion")}},
 	{Type_Basic, {Basic_UntypedString,     BasicFlag_String     | BasicFlag_Untyped,   0, STR_LIT("untyped string")}},
 	{Type_Basic, {Basic_UntypedString,     BasicFlag_String     | BasicFlag_Untyped,   0, STR_LIT("untyped string")}},
 	{Type_Basic, {Basic_UntypedRune,       BasicFlag_Integer    | BasicFlag_Untyped,   0, STR_LIT("untyped rune")}},
 	{Type_Basic, {Basic_UntypedRune,       BasicFlag_Integer    | BasicFlag_Untyped,   0, STR_LIT("untyped rune")}},
 	{Type_Basic, {Basic_UntypedNil,        BasicFlag_Untyped,                          0, STR_LIT("untyped nil")}},
 	{Type_Basic, {Basic_UntypedNil,        BasicFlag_Untyped,                          0, STR_LIT("untyped nil")}},
@@ -411,6 +424,9 @@ gb_global Type *t_f64             = &basic_types[Basic_f64];
 gb_global Type *t_complex64       = &basic_types[Basic_complex64];
 gb_global Type *t_complex64       = &basic_types[Basic_complex64];
 gb_global Type *t_complex128      = &basic_types[Basic_complex128];
 gb_global Type *t_complex128      = &basic_types[Basic_complex128];
 
 
+gb_global Type *t_quaternion128   = &basic_types[Basic_quaternion128];
+gb_global Type *t_quaternion256   = &basic_types[Basic_quaternion256];
+
 gb_global Type *t_int             = &basic_types[Basic_int];
 gb_global Type *t_int             = &basic_types[Basic_int];
 gb_global Type *t_uint            = &basic_types[Basic_uint];
 gb_global Type *t_uint            = &basic_types[Basic_uint];
 gb_global Type *t_uintptr         = &basic_types[Basic_uintptr];
 gb_global Type *t_uintptr         = &basic_types[Basic_uintptr];
@@ -445,6 +461,7 @@ gb_global Type *t_untyped_bool       = &basic_types[Basic_UntypedBool];
 gb_global Type *t_untyped_integer    = &basic_types[Basic_UntypedInteger];
 gb_global Type *t_untyped_integer    = &basic_types[Basic_UntypedInteger];
 gb_global Type *t_untyped_float      = &basic_types[Basic_UntypedFloat];
 gb_global Type *t_untyped_float      = &basic_types[Basic_UntypedFloat];
 gb_global Type *t_untyped_complex    = &basic_types[Basic_UntypedComplex];
 gb_global Type *t_untyped_complex    = &basic_types[Basic_UntypedComplex];
+gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
 gb_global Type *t_untyped_string     = &basic_types[Basic_UntypedString];
 gb_global Type *t_untyped_string     = &basic_types[Basic_UntypedString];
 gb_global Type *t_untyped_rune       = &basic_types[Basic_UntypedRune];
 gb_global Type *t_untyped_rune       = &basic_types[Basic_UntypedRune];
 gb_global Type *t_untyped_nil        = &basic_types[Basic_UntypedNil];
 gb_global Type *t_untyped_nil        = &basic_types[Basic_UntypedNil];
@@ -471,6 +488,7 @@ gb_global Type *t_type_info_integer           = nullptr;
 gb_global Type *t_type_info_rune              = nullptr;
 gb_global Type *t_type_info_rune              = nullptr;
 gb_global Type *t_type_info_float             = nullptr;
 gb_global Type *t_type_info_float             = nullptr;
 gb_global Type *t_type_info_complex           = nullptr;
 gb_global Type *t_type_info_complex           = nullptr;
+gb_global Type *t_type_info_quaternion        = nullptr;
 gb_global Type *t_type_info_any               = nullptr;
 gb_global Type *t_type_info_any               = nullptr;
 gb_global Type *t_type_info_typeid            = nullptr;
 gb_global Type *t_type_info_typeid            = nullptr;
 gb_global Type *t_type_info_string            = nullptr;
 gb_global Type *t_type_info_string            = nullptr;
@@ -495,6 +513,7 @@ gb_global Type *t_type_info_integer_ptr       = nullptr;
 gb_global Type *t_type_info_rune_ptr          = nullptr;
 gb_global Type *t_type_info_rune_ptr          = nullptr;
 gb_global Type *t_type_info_float_ptr         = nullptr;
 gb_global Type *t_type_info_float_ptr         = nullptr;
 gb_global Type *t_type_info_complex_ptr       = nullptr;
 gb_global Type *t_type_info_complex_ptr       = nullptr;
+gb_global Type *t_type_info_quaternion_ptr    = nullptr;
 gb_global Type *t_type_info_any_ptr           = nullptr;
 gb_global Type *t_type_info_any_ptr           = nullptr;
 gb_global Type *t_type_info_typeid_ptr        = nullptr;
 gb_global Type *t_type_info_typeid_ptr        = nullptr;
 gb_global Type *t_type_info_string_ptr        = nullptr;
 gb_global Type *t_type_info_string_ptr        = nullptr;
@@ -535,8 +554,27 @@ i64      type_offset_of             (Type *t, i32 index);
 gbString type_to_string             (Type *type);
 gbString type_to_string             (Type *type);
 void     init_map_internal_types(Type *type);
 void     init_map_internal_types(Type *type);
 Type *   bit_set_to_int(Type *t);
 Type *   bit_set_to_int(Type *t);
+bool are_types_identical(Type *x, Type *y);
 
 
 
 
+bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
+	if (ptr_set_exists(s, t)) {
+		return true;
+	}
+
+	// TODO(bill, 2019-10-05): This is very slow and it's probably a lot
+	// faster to cache types correctly
+	for_array(i, s->entries) {
+		Type *f = s->entries[i].ptr;
+		if (are_types_identical(t, f)) {
+			ptr_set_add(s, t);
+			return true;
+		}
+	}
+
+	return false;
+}
+
 Type *base_type(Type *t) {
 Type *base_type(Type *t) {
 	for (;;) {
 	for (;;) {
 		if (t == nullptr) {
 		if (t == nullptr) {
@@ -923,6 +961,13 @@ bool is_type_complex(Type *t) {
 	}
 	}
 	return false;
 	return false;
 }
 }
+bool is_type_quaternion(Type *t) {
+	t = core_type(t);
+	if (t->kind == Type_Basic) {
+		return (t->Basic.flags & BasicFlag_Quaternion) != 0;
+	}
+	return false;
+}
 bool is_type_f32(Type *t) {
 bool is_type_f32(Type *t) {
 	t = core_type(t);
 	t = core_type(t);
 	if (t->kind == Type_Basic) {
 	if (t->kind == Type_Basic) {
@@ -1037,14 +1082,40 @@ Type *core_array_type(Type *t) {
 	return t;
 	return t;
 }
 }
 
 
+// NOTE(bill): type can be easily compared using memcmp
+bool is_type_simple_compare(Type *t) {
+	t = core_type(t);
+	switch (t->kind) {
+	case Type_Array:
+		return is_type_simple_compare(t->Array.elem);
+
+	case Type_Basic:
+		if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) {
+			return true;
+		}
+		return false;
+
+	case Type_Pointer:
+	case Type_Proc:
+	case Type_BitSet:
+	case Type_BitField:
+		return true;
+	}
+
+	return false;
+}
+
 Type *base_complex_elem_type(Type *t) {
 Type *base_complex_elem_type(Type *t) {
 	t = core_type(t);
 	t = core_type(t);
-	if (is_type_complex(t)) {
+	if (t->kind == Type_Basic) {
 		switch (t->Basic.kind) {
 		switch (t->Basic.kind) {
-		// case Basic_complex32:      return t_f16;
-		case Basic_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");
 	GB_PANIC("Invalid complex type");
@@ -1099,12 +1170,11 @@ bool is_type_integer_endian_big(Type *t) {
 		return is_type_integer_endian_big(bit_set_to_int(t));
 		return is_type_integer_endian_big(bit_set_to_int(t));
 	} else if (t->kind == Type_Pointer) {
 	} else if (t->kind == Type_Pointer) {
 		return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
 		return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
-	} else {
-		GB_PANIC("Unsupported type: %s", type_to_string(t));
 	}
 	}
 	return build_context.endian_kind == TargetEndian_Big;
 	return build_context.endian_kind == TargetEndian_Big;
 }
 }
 
 
+
 bool is_type_integer_endian_little(Type *t) {
 bool is_type_integer_endian_little(Type *t) {
 	t = core_type(t);
 	t = core_type(t);
 	if (t->kind == Type_Basic) {
 	if (t->kind == Type_Basic) {
@@ -1118,11 +1188,24 @@ bool is_type_integer_endian_little(Type *t) {
 		return is_type_integer_endian_little(bit_set_to_int(t));
 		return is_type_integer_endian_little(bit_set_to_int(t));
 	} else if (t->kind == Type_Pointer) {
 	} else if (t->kind == Type_Pointer) {
 		return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
 		return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
-	} else {
-		GB_PANIC("Unsupported type: %s", type_to_string(t));
 	}
 	}
 	return build_context.endian_kind == TargetEndian_Little;
 	return build_context.endian_kind == TargetEndian_Little;
 }
 }
+bool is_type_endian_big(Type *t) {
+	return is_type_integer_endian_big(t);
+}
+bool is_type_endian_little(Type *t) {
+	return is_type_integer_endian_little(t);
+}
+
+bool is_type_dereferenceable(Type *t) {
+	if (is_type_rawptr(t)) {
+		return false;
+	}
+	return is_type_pointer(t);
+}
+
+
 
 
 bool is_type_different_to_arch_endianness(Type *t) {
 bool is_type_different_to_arch_endianness(Type *t) {
 	switch (build_context.endian_kind) {
 	switch (build_context.endian_kind) {
@@ -1284,6 +1367,19 @@ bool is_type_indexable(Type *t) {
 	return false;
 	return false;
 }
 }
 
 
+bool is_type_sliceable(Type *t) {
+	Type *bt = base_type(t);
+	switch (bt->kind) {
+	case Type_Basic:
+		return bt->Basic.kind == Basic_string;
+	case Type_Array:
+	case Type_Slice:
+	case Type_DynamicArray:
+		return true;
+	}
+	return false;
+}
+
 
 
 bool is_type_polymorphic_record(Type *t) {
 bool is_type_polymorphic_record(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
@@ -1663,6 +1759,12 @@ bool are_types_identical(Type *x, Type *y) {
 					if (xf_is_using ^ yf_is_using) {
 					if (xf_is_using ^ yf_is_using) {
 						return false;
 						return false;
 					}
 					}
+					if (x->Struct.tags.count != y->Struct.tags.count) {
+						return false;
+					}
+					if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) {
+						return false;
+					}
 				}
 				}
 				return true;
 				return true;
 			}
 			}
@@ -1683,7 +1785,8 @@ bool are_types_identical(Type *x, Type *y) {
 
 
 	case Type_Tuple:
 	case Type_Tuple:
 		if (y->kind == Type_Tuple) {
 		if (y->kind == Type_Tuple) {
-			if (x->Tuple.variables.count == y->Tuple.variables.count) {
+			if (x->Tuple.variables.count == y->Tuple.variables.count &&
+			    x->Tuple.is_packed == y->Tuple.is_packed) {
 				for_array(i, x->Tuple.variables) {
 				for_array(i, x->Tuple.variables) {
 					Entity *xe = x->Tuple.variables[i];
 					Entity *xe = x->Tuple.variables[i];
 					Entity *ye = y->Tuple.variables[i];
 					Entity *ye = y->Tuple.variables[i];
@@ -1763,6 +1866,7 @@ Type *default_type(Type *type) {
 		case Basic_UntypedInteger:    return t_int;
 		case Basic_UntypedInteger:    return t_int;
 		case Basic_UntypedFloat:      return t_f64;
 		case Basic_UntypedFloat:      return t_f64;
 		case Basic_UntypedComplex:    return t_complex128;
 		case Basic_UntypedComplex:    return t_complex128;
+		case Basic_UntypedQuaternion: return t_quaternion256;
 		case Basic_UntypedString:     return t_string;
 		case Basic_UntypedString:     return t_string;
 		case Basic_UntypedRune:       return t_rune;
 		case Basic_UntypedRune:       return t_rune;
 		}
 		}
@@ -2131,19 +2235,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 		if (type->Array.count <= 4) {
 		if (type->Array.count <= 4) {
 			// HACK(bill): Memory leak
 			// HACK(bill): Memory leak
 			switch (type->Array.count) {
 			switch (type->Array.count) {
-			#define _ARRAY_FIELD_CASE(_length, _name) \
-			case (_length): \
-				if (field_name == _name) { \
+			#define _ARRAY_FIELD_CASE_IF(_length, _name) \
+				if (field_name == (_name)) { \
 					selection_add_index(&sel, (_length)-1); \
 					selection_add_index(&sel, (_length)-1); \
 					sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
 					sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
 					return sel; \
 					return sel; \
-				} \
+				}
+			#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
+			case (_length): \
+				_ARRAY_FIELD_CASE_IF(_length, _name0); \
+				_ARRAY_FIELD_CASE_IF(_length, _name1); \
 				/*fallthrough*/
 				/*fallthrough*/
 
 
-			_ARRAY_FIELD_CASE(4, "w");
-			_ARRAY_FIELD_CASE(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;
 			default: break;
 
 
 			#undef _ARRAY_FIELD_CASE
 			#undef _ARRAY_FIELD_CASE
@@ -2254,7 +2361,9 @@ i64 type_size_of(Type *t) {
 		return 0;
 		return 0;
 	}
 	}
 	// NOTE(bill): Always calculate the size when it is a Type_Basic
 	// NOTE(bill): Always calculate the size when it is a Type_Basic
-	if (t->kind != Type_Basic && t->cached_size >= 0) {
+	if (t->kind == Type_Named && t->cached_size >= 0) {
+
+	} else if (t->kind != Type_Basic && t->cached_size >= 0) {
 		return t->cached_size;
 		return t->cached_size;
 	}
 	}
 	TypePath path = {0};
 	TypePath path = {0};
@@ -2269,7 +2378,9 @@ i64 type_align_of(Type *t) {
 		return 1;
 		return 1;
 	}
 	}
 	// NOTE(bill): Always calculate the size when it is a Type_Basic
 	// NOTE(bill): Always calculate the size when it is a Type_Basic
-	if (t->kind != Type_Basic && t->cached_align > 0) {
+	if (t->kind == Type_Named && t->cached_align >= 0) {
+
+	} if (t->kind != Type_Basic && t->cached_align > 0) {
 		return t->cached_align;
 		return t->cached_align;
 	}
 	}
 
 
@@ -2303,6 +2414,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
 
 
 		case Basic_complex64: case Basic_complex128:
 		case Basic_complex64: case Basic_complex128:
 			return type_size_of_internal(t, path) / 2;
 			return type_size_of_internal(t, path) / 2;
+		case Basic_quaternion128: case Basic_quaternion256:
+			return type_size_of_internal(t, path) / 4;
 		}
 		}
 	} break;
 	} break;
 
 
@@ -2488,9 +2601,9 @@ bool type_set_offsets(Type *t) {
 		}
 		}
 	} else if (is_type_tuple(t)) {
 	} else if (is_type_tuple(t)) {
 		if (!t->Tuple.are_offsets_set) {
 		if (!t->Tuple.are_offsets_set) {
-			t->Struct.are_offsets_being_processed = true;
-			t->Tuple.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;
 			t->Tuple.are_offsets_set = true;
 			return true;
 			return true;
 		}
 		}
@@ -2913,35 +3026,54 @@ gbString write_type_to_string(gbString str, Type *type) {
 			isize comma_index = 0;
 			isize comma_index = 0;
 			for_array(i, type->Tuple.variables) {
 			for_array(i, type->Tuple.variables) {
 				Entity *var = type->Tuple.variables[i];
 				Entity *var = type->Tuple.variables[i];
-				if (var != nullptr) {
-					if (var->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 {
 					} 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);
 							str = write_type_to_string(str, var->type);
 						} else {
 						} else {
-							str = gb_string_appendc(str, "type");
+							str = gb_string_appendc(str, "typeid");
 						}
 						}
 					}
 					}
 				}
 				}

+ 0 - 1
src/unicode.cpp

@@ -2,7 +2,6 @@
 #pragma warning(disable: 4245)
 #pragma warning(disable: 4245)
 
 
 extern "C" {
 extern "C" {
-#include "utf8proc/utf8proc.h"
 #include "utf8proc/utf8proc.c"
 #include "utf8proc/utf8proc.c"
 }
 }
 #pragma warning(pop)
 #pragma warning(pop)

+ 0 - 1
src/utf8proc/utf8proc.c

@@ -40,7 +40,6 @@
  *  Implementation of libutf8proc.
  *  Implementation of libutf8proc.
  */
  */
 
 
-
 #include "utf8proc.h"
 #include "utf8proc.h"
 #include "utf8proc_data.c"
 #include "utf8proc_data.c"
 
 

Some files were not shown because too many files changed in this diff