Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Chris Heyes committed 2019-11-01 19:18:33 +00:00
commit 153e7525b5
83 files changed
+10048 -2578

No files matched your search

+57
View File
@@ -0,0 +1,57 @@
name: CI
on: [push, pull_request]
jobs:
build_unix:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- name: (macOS) Download LLVM and setup PATH
if: startsWith(matrix.os, 'macOS')
run: |
brew install llvm
echo ::add-path::/usr/local/opt/llvm/bin
echo ::set-env name=CPATH::`xcrun --show-sdk-path`/usr/include
- name: (Linux) Download LLVM
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get install llvm
- name: build odin
run: make release
- name: Odin run
run: ./odin run examples/demo/demo.odin
- name: Odin check
run: ./odin check examples/demo/demo.odin -vet
build_windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Install cURL
run: choco install curl
- name: Download and unpack LLVM bins
shell: cmd
run: |
cd bin
curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip
7z x llvm-binaries.zip > nul
- name: build Odin
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
./build_ci.bat
- name: Odin run
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo/demo.odin
- name: Odin check
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/demo/demo.odin -vet
-24
View File
@@ -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
View File
@@ -10,15 +10,12 @@
<a href="https://github.com/odin-lang/odin/releases/latest"> <a href="https://github.com/odin-lang/odin/releases/latest">
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg"> <img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
</a> </a>
<a href="https://github.com/odin-lang/odin/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/odin-lang/odin.svg">
</a>
<br> <br>
<a href="https://ci.appveyor.com/project/ThisDrunkDane/odin-vf0ap"> <a href="https://discord.gg/hnwN2Rj">
<img src="https://ci.appveyor.com/api/projects/status/qss6l921c0eu85u6/branch/master?svg=true"> <img src="https://img.shields.io/discord/568138951836172421?logo=discord">
</a> </a>
<a href="https://travis-ci.org/odin-lang/Odin"> <a href="https://github.com/odin-lang/odin/actions">
<img src="https://travis-ci.org/odin-lang/Odin.svg?branch=master"> <img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg">
</a> </a>
</p> </p>
-19
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) {
} }
error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) { error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) {
fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column); fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column);
fmt.printf_err(msg, ..args); fmt.eprintf(msg, ..args);
fmt.println_err(); fmt.eprintln();
p.error_count += 1; p.error_count += 1;
} }
+3 -3
View File
@@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") {
} }
token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) { token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) {
fmt.printf_err("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1); fmt.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1);
fmt.printf_err(msg, ..args); fmt.eprintf(msg, ..args);
fmt.println_err(); fmt.eprintln();
t.error_count += 1; t.error_count += 1;
} }
+5 -6
View File
@@ -5,7 +5,7 @@ import "core:math/bits"
import "core:runtime" import "core:runtime"
import "core:strconv" import "core:strconv"
import "core:strings" import "core:strings"
import "core:types" import "core:reflect"
Marshal_Error :: enum { Marshal_Error :: enum {
None, None,
@@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
data := uintptr(entries.data) + uintptr(i*entry_size); data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^Map_Entry_Header)data; header := cast(^Map_Entry_Header)data;
if types.is_string(info.key) { if reflect.is_string(info.key) {
marshal_arg(b, header.key.str); marshal_arg(b, header.key.str);
} else { } else {
marshal_arg(b, any{rawptr(&header.key.hash), info.key.id}); marshal_arg(b, any{rawptr(&header.key.hash), info.key.id});
@@ -284,11 +284,10 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
t := runtime.type_info_base(ti); t := runtime.type_info_base(ti);
switch info in t.variant { switch info in t.variant {
case runtime.Type_Info_Integer: case runtime.Type_Info_Integer:
using runtime.Type_Info_Endianness;
switch info.endianness { switch info.endianness {
case Platform: return false; case .Platform: return false;
case Little: return ODIN_ENDIAN != "little"; case .Little: return ODIN_ENDIAN != "little";
case Big: return ODIN_ENDIAN != "big"; case .Big: return ODIN_ENDIAN != "big";
} }
} }
return false; return false;
+54 -228
View File
@@ -5,9 +5,9 @@ import "core:os"
import "core:mem" import "core:mem"
import "core:math/bits" import "core:math/bits"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:types"
import "core:strconv" import "core:strconv"
import "core:strings" import "core:strings"
import "core:reflect"
@private @private
@@ -60,11 +60,17 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
// print* procedures return the number of bytes written // print* procedures return the number of bytes written
print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); } print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); }
print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); } println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); }
println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); } printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); }
printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); }
eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); }
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); }
@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); }
@(deprecated="prefer eprintf") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); }
@(deprecated="prefer eprintln") println_err :: proc(args: ..any) -> int { return eprintln(..args); }
// aprint* procedures return a string that was allocated with the current context // aprint* procedures return a string that was allocated with the current context
@@ -143,7 +149,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location)
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) { fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
data: [DEFAULT_BUFFER_SIZE]byte; data: [DEFAULT_BUFFER_SIZE]byte;
buf := strings.builder_from_slice(data[:]); buf := strings.builder_from_slice(data[:]);
write_type(&buf, info); reflect.write_type(&buf, info);
os.write_string(fd, strings.to_string(buf)); os.write_string(fd, strings.to_string(buf));
} }
@@ -156,7 +162,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string {
fi.buf = buf; fi.buf = buf;
for arg, i in args { for arg, i in args {
is_string := arg != nil && types.is_string(type_info_of(arg.id)); is_string := arg != nil && reflect.is_string(type_info_of(arg.id));
if i > 0 && !is_string && !prev_string { if i > 0 && !is_string && !prev_string {
strings.write_byte(buf, ' '); strings.write_byte(buf, ' ');
} }
@@ -399,7 +405,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) {
strings.write_rune(buf, verb); strings.write_rune(buf, verb);
strings.write_byte(buf, '('); strings.write_byte(buf, '(');
if arg.id != nil { if arg.id != nil {
write_typeid(buf, arg.id); reflect.write_typeid(buf, arg.id);
strings.write_byte(buf, '='); strings.write_byte(buf, '=');
fmt_value(fi, arg, 'v'); fmt_value(fi, arg, 'v');
} else { } else {
@@ -792,7 +798,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) {
case: return "", false; case: return "", false;
case runtime.Type_Info_Enum: case runtime.Type_Info_Enum:
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) { get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
if types.is_string(e.base) { if reflect.is_string(e.base) {
for val, idx in e.values { for val, idx in e.values {
if v, ok := val.(T); ok && v == i { if v, ok := val.(T); ok && v == i {
return e.names[idx], true; return e.names[idx], true;
@@ -947,7 +953,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
if name != "" { if name != "" {
strings.write_string(fi.buf, name); strings.write_string(fi.buf, name);
} else { } else {
write_type(fi.buf, type_info); reflect.write_type(fi.buf, type_info);
} }
strings.write_byte(fi.buf, '{'); strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}'); defer strings.write_byte(fi.buf, '}');
@@ -1042,7 +1048,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok { if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
elem := rt.type_info_base(ot.elem); elem := rt.type_info_base(ot.elem);
if elem == nil do return; if elem == nil do return;
write_type(fi.buf, type_info); reflect.write_type(fi.buf, type_info);
strings.write_byte(fi.buf, '{'); strings.write_byte(fi.buf, '{');
defer strings.write_byte(fi.buf, '}'); defer strings.write_byte(fi.buf, '}');
@@ -1053,7 +1059,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) {
// Okay // Okay
} }
} else { } else {
write_type(fi.buf, type_info); reflect.write_type(fi.buf, type_info);
strings.write_byte(fi.buf, '{'); strings.write_byte(fi.buf, '{');
strings.write_byte(fi.buf, '}'); strings.write_byte(fi.buf, '}');
} }
@@ -1101,7 +1107,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
strings.write_string(fi.buf, name); strings.write_string(fi.buf, name);
strings.write_string(fi.buf, " = "); strings.write_string(fi.buf, " = ");
if t := b.types[i]; types.is_any(t) { if t := b.types[i]; reflect.is_any(t) {
strings.write_string(fi.buf, "any{}"); strings.write_string(fi.buf, "any{}");
} else { } else {
data := rawptr(uintptr(v.data) + b.offsets[i]); data := rawptr(uintptr(v.data) + b.offsets[i]);
@@ -1129,11 +1135,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb); case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
case runtime.Type_Info_Float: fmt_arg(fi, v, verb); case runtime.Type_Info_Float: fmt_arg(fi, v, verb);
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb); case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb);
case runtime.Type_Info_String: fmt_arg(fi, v, verb); case runtime.Type_Info_String: fmt_arg(fi, v, verb);
case runtime.Type_Info_Pointer: case runtime.Type_Info_Pointer:
if v.id == typeid_of(^runtime.Type_Info) { if v.id == typeid_of(^runtime.Type_Info) {
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^); reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
} else { } else {
ptr := (^rawptr)(v.data)^; ptr := (^rawptr)(v.data)^;
if verb != 'p' && info.elem != nil { if verb != 'p' && info.elem != nil {
@@ -1256,7 +1263,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
data := uintptr(entries.data) + uintptr(i*entry_size); data := uintptr(entries.data) + uintptr(i*entry_size);
header := cast(^runtime.Map_Entry_Header)data; header := cast(^runtime.Map_Entry_Header)data;
if types.is_string(info.key) { if reflect.is_string(info.key) {
strings.write_string(fi.buf, header.key.str); strings.write_string(fi.buf, header.key.str);
} else { } else {
fi := Info{buf = fi.buf}; fi := Info{buf = fi.buf};
@@ -1297,7 +1304,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
strings.write_string(fi.buf, info.names[i]); strings.write_string(fi.buf, info.names[i]);
strings.write_string(fi.buf, " = "); strings.write_string(fi.buf, " = ");
if t := info.types[i]; types.is_any(t) { if t := info.types[i]; reflect.is_any(t) {
strings.write_string(fi.buf, "any{}"); strings.write_string(fi.buf, "any{}");
} else { } else {
data := uintptr(v.data) + info.offsets[i]; data := uintptr(v.data) + info.offsets[i];
@@ -1349,14 +1356,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
if ptr == nil { if ptr == nil {
strings.write_string(fi.buf, "nil"); strings.write_string(fi.buf, "nil");
} else { } else {
write_typeid(fi.buf, v.id); reflect.write_typeid(fi.buf, v.id);
strings.write_string(fi.buf, " @ "); strings.write_string(fi.buf, " @ ");
fmt_pointer(fi, ptr, 'p'); fmt_pointer(fi, ptr, 'p');
} }
case runtime.Type_Info_Type_Id: case runtime.Type_Info_Type_Id:
id := (^typeid)(v.data)^; id := (^typeid)(v.data)^;
write_typeid(fi.buf, id); reflect.write_typeid(fi.buf, id);
case runtime.Type_Info_Bit_Field: case runtime.Type_Info_Bit_Field:
fmt_bit_field(fi, v); fmt_bit_field(fi, v);
@@ -1386,6 +1393,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) {
} }
} }
fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) {
switch verb {
case 'f', 'F', 'v', 'h', 'H':
r, i, j, k := real(q), imag(q), jmag(q), kmag(q);
fmt_float(fi, r, bits/4, verb);
if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, i, bits/4, verb);
strings.write_rune(fi.buf, 'i');
if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, j, bits/4, verb);
strings.write_rune(fi.buf, 'j');
if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+');
fmt_float(fi, k, bits/4, verb);
strings.write_rune(fi.buf, 'k');
case:
fmt_bad_verb(fi, verb);
return;
}
}
fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
if arg == nil { if arg == nil {
strings.write_string(fi.buf, "<nil>"); strings.write_string(fi.buf, "<nil>");
@@ -1398,7 +1430,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
switch a in arg { switch a in arg {
case ^runtime.Type_Info: ti = a; case ^runtime.Type_Info: ti = a;
} }
write_type(fi.buf, ti); reflect.write_type(fi.buf, ti);
return; return;
} }
@@ -1434,6 +1466,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case complex64: fmt_complex(fi, complex128(a), 64, verb); case complex64: fmt_complex(fi, complex128(a), 64, verb);
case complex128: fmt_complex(fi, a, 128, verb); case complex128: fmt_complex(fi, a, 128, verb);
case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
case quaternion256: fmt_quaternion(fi, a, 256, verb);
case i8: fmt_int(fi, u64(a), true, 8, verb); case i8: fmt_int(fi, u64(a), true, 8, verb);
case u8: fmt_int(fi, u64(a), false, 8, verb); case u8: fmt_int(fi, u64(a), false, 8, verb);
case i16: fmt_int(fi, u64(a), true, 16, verb); case i16: fmt_int(fi, u64(a), true, 16, verb);
@@ -1449,7 +1484,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case string: fmt_string(fi, a, verb); case string: fmt_string(fi, a, verb);
case cstring: fmt_cstring(fi, a, verb); case cstring: fmt_cstring(fi, a, verb);
case typeid: write_typeid(fi.buf, a); case typeid: reflect.write_typeid(fi.buf, a);
case i16le: fmt_int(fi, u64(a), true, 16, verb); case i16le: fmt_int(fi, u64(a), true, 16, verb);
case u16le: fmt_int(fi, u64(a), false, 16, verb); case u16le: fmt_int(fi, u64(a), false, 16, verb);
@@ -1482,212 +1517,3 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
write_type(buf, type_info_of(id));
}
write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
using strings;
if ti == nil {
write_string(buf, "nil");
return;
}
switch info in ti.variant {
case runtime.Type_Info_Named:
write_string(buf, info.name);
case runtime.Type_Info_Integer:
switch ti.id {
case int: write_string(buf, "int");
case uint: write_string(buf, "uint");
case uintptr: write_string(buf, "uintptr");
case:
write_byte(buf, info.signed ? 'i' : 'u');
write_i64(buf, i64(8*ti.size), 10);
switch info.endianness {
case runtime.Type_Info_Endianness.Little:
write_string(buf, "le");
case runtime.Type_Info_Endianness.Big:
write_string(buf, "be");
}
}
case runtime.Type_Info_Rune:
write_string(buf, "rune");
case runtime.Type_Info_Float:
write_byte(buf, 'f');
write_i64(buf, i64(8*ti.size), 10);
case runtime.Type_Info_Complex:
write_string(buf, "complex");
write_i64(buf, i64(8*ti.size), 10);
case runtime.Type_Info_String:
if info.is_cstring {
write_string(buf, "cstring");
} else {
write_string(buf, "string");
}
case runtime.Type_Info_Boolean:
switch ti.id {
case bool: write_string(buf, "bool");
case:
write_byte(buf, 'b');
write_i64(buf, i64(8*ti.size), 10);
}
case runtime.Type_Info_Any:
write_string(buf, "any");
case runtime.Type_Info_Type_Id:
write_string(buf, "typeid");
case runtime.Type_Info_Pointer:
if info.elem == nil {
write_string(buf, "rawptr");
} else {
write_string(buf, "^");
write_type(buf, info.elem);
}
case runtime.Type_Info_Procedure:
write_string(buf, "proc");
if info.params == nil {
write_string(buf, "()");
} else {
t := info.params.variant.(runtime.Type_Info_Tuple);
write_string(buf, "(");
for t, i in t.types {
if i > 0 do write_string(buf, ", ");
write_type(buf, t);
}
write_string(buf, ")");
}
if info.results != nil {
write_string(buf, " -> ");
write_type(buf, info.results);
}
case runtime.Type_Info_Tuple:
count := len(info.names);
if count != 1 do write_string(buf, "(");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
t := info.types[i];
if len(name) > 0 {
write_string(buf, name);
write_string(buf, ": ");
}
write_type(buf, t);
}
if count != 1 do write_string(buf, ")");
case runtime.Type_Info_Array:
write_string(buf, "[");
write_i64(buf, i64(info.count), 10);
write_string(buf, "]");
write_type(buf, info.elem);
case runtime.Type_Info_Dynamic_Array:
write_string(buf, "[dynamic]");
write_type(buf, info.elem);
case runtime.Type_Info_Slice:
write_string(buf, "[]");
write_type(buf, info.elem);
case runtime.Type_Info_Map:
write_string(buf, "map[");
write_type(buf, info.key);
write_byte(buf, ']');
write_type(buf, info.value);
case runtime.Type_Info_Struct:
write_string(buf, "struct ");
if info.is_packed do write_string(buf, "#packed ");
if info.is_raw_union do write_string(buf, "#raw_union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_type(buf, info.types[i]);
}
write_byte(buf, '}');
case runtime.Type_Info_Union:
write_string(buf, "union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for variant, i in info.variants {
if i > 0 do write_string(buf, ", ");
write_type(buf, variant);
}
write_byte(buf, '}');
case runtime.Type_Info_Enum:
write_string(buf, "enum ");
write_type(buf, info.base);
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
}
write_byte(buf, '}');
case runtime.Type_Info_Bit_Field:
write_string(buf, "bit_field ");
if ti.align != 1 {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_i64(buf, i64(info.bits[i]), 10);
}
write_byte(buf, '}');
case runtime.Type_Info_Bit_Set:
write_string(buf, "bit_set[");
switch {
case types.is_enum(info.elem):
write_type(buf, info.elem);
case types.is_rune(info.elem):
write_encoded_rune(buf, rune(info.lower));
write_string(buf, "..");
write_encoded_rune(buf, rune(info.upper));
case:
write_i64(buf, info.lower, 10);
write_string(buf, "..");
write_i64(buf, info.upper, 10);
}
if info.underlying != nil {
write_string(buf, "; ");
write_type(buf, info.underlying);
}
write_byte(buf, ']');
case runtime.Type_Info_Opaque:
write_string(buf, "opaque ");
write_type(buf, info.elem);
case runtime.Type_Info_Simd_Vector:
if info.is_x86_mmx {
write_string(buf, "intrinsics.x86_mmx");
} else {
write_string(buf, "intrinsics.vector(");
write_i64(buf, i64(info.count));
write_string(buf, ", ");
write_type(buf, info.elem);
write_byte(buf, ')');
}
}
}
+126
View File
@@ -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
View File
@@ -14,18 +14,18 @@ Level_Headers := []string{
}; };
Default_Console_Logger_Opts :: Options{ Default_Console_Logger_Opts :: Options{
Option.Level, .Level,
Option.Terminal_Color, .Terminal_Color,
Option.Short_File_Path, .Short_File_Path,
Option.Line, .Line,
Option.Procedure, .Procedure,
} | Full_Timestamp_Opts; } | Full_Timestamp_Opts;
Default_File_Logger_Opts :: Options{ Default_File_Logger_Opts :: Options{
Option.Level, .Level,
Option.Short_File_Path, .Short_File_Path,
Option.Line, .Line,
Option.Procedure, .Procedure,
} | Full_Timestamp_Opts; } | Full_Timestamp_Opts;
@@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) {
case Level.Error, Level.Fatal : col = RED; case Level.Error, Level.Fatal : col = RED;
} }
if Option.Level in opts { if .Level in opts {
if Option.Terminal_Color in opts do fmt.sbprint(str, col); if .Terminal_Color in opts do fmt.sbprint(str, col);
fmt.sbprint(str, Level_Headers[level]); fmt.sbprint(str, Level_Headers[level]);
if Option.Terminal_Color in opts do fmt.sbprint(str, RESET); if .Terminal_Color in opts do fmt.sbprint(str, RESET);
} }
} }
@@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return; if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return;
file := location.file_path; file := location.file_path;
if Option.Short_File_Path in opts { if .Short_File_Path in opts {
when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/'; when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/';
last := 0; last := 0;
for r, i in location.file_path do if r == delimiter do last = i+1; for r, i in location.file_path do if r == delimiter do last = i+1;
@@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := #
if Location_File_Opts & opts != nil do fmt.sbprint(buf, file); if Location_File_Opts & opts != nil do fmt.sbprint(buf, file);
if Option.Procedure in opts { if .Procedure in opts {
if Location_File_Opts & opts != nil do fmt.sbprint(buf, "."); if Location_File_Opts & opts != nil do fmt.sbprint(buf, ".");
fmt.sbprintf(buf, "%s()", location.procedure); fmt.sbprintf(buf, "%s()", location.procedure);
} }
if Option.Line in opts { if .Line in opts {
if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":"); if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":");
fmt.sbprint(buf, location.line); fmt.sbprint(buf, location.line);
} }
+15 -10
View File
@@ -23,18 +23,18 @@ Option :: enum {
Options :: bit_set[Option]; Options :: bit_set[Option];
Full_Timestamp_Opts :: Options{ Full_Timestamp_Opts :: Options{
Option.Date, .Date,
Option.Time .Time
}; };
Location_Header_Opts :: Options{ Location_Header_Opts :: Options{
Option.Short_File_Path, .Short_File_Path,
Option.Long_File_Path, .Long_File_Path,
Option.Line, .Line,
Option.Procedure, .Procedure,
}; };
Location_File_Opts :: Options{ Location_File_Opts :: Options{
Option.Short_File_Path, .Short_File_Path,
Option.Long_File_Path .Long_File_Path
}; };
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location); Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
@@ -64,8 +64,12 @@ destroy_multi_logger ::proc(log : ^Logger) {
multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string,
options: Options, location := #caller_location) { options: Options, location := #caller_location) {
data := cast(^Multi_Logger_Data)logger_data; data := cast(^Multi_Logger_Data)logger_data;
if data.loggers == nil || len(data.loggers) == 0 do return; if data.loggers == nil || len(data.loggers) == 0 {
for log in data.loggers do log.procedure(log.data, level, text, log.options, location); return;
}
for log in data.loggers {
log.procedure(log.data, level, text, log.options, location);
}
} }
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
@@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, nil}; return Logger{nil_logger_proc, nil, nil};
} }
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location); debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location);
info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location); info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location);
warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location); warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location);
+283
View File
@@ -0,0 +1,283 @@
package linalg
import "core:math"
import "intrinsics"
// Generic
dot_vector :: proc(a, b: $T/[$N]$E) -> (c: E) {
for i in 0..<N {
c += a[i] * b[i];
}
return;
}
dot_quaternion128 :: proc(a, b: $T/quaternion128) -> (c: f32) {
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
}
dot_quaternion256 :: proc(a, b: $T/quaternion256) -> (c: f64) {
return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b);
}
dot :: proc{dot_vector, dot_quaternion128, dot_quaternion256};
cross2 :: proc(a, b: $T/[2]$E) -> E {
return a[0]*b[1] - b[0]*a[1];
}
cross3 :: proc(a, b: $T/[3]$E) -> (c: T) {
c[0] = +(a[1]*b[2] - b[1]*a[2]);
c[1] = -(a[2]*b[3] - b[2]*a[3]);
c[2] = +(a[3]*b[1] - b[3]*a[1]);
return;
}
cross :: proc{cross2, cross3};
normalize_vector :: proc(v: $T/[$N]$E) -> T {
return v / length(v);
}
normalize_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
return q/abs(q);
}
normalize_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
return q/abs(q);
}
normalize :: proc{normalize_vector, normalize_quaternion128, normalize_quaternion256};
normalize0_vector :: proc(v: $T/[$N]$E) -> T {
m := length(v);
return m == 0 ? 0 : v/m;
}
normalize0_quaternion128 :: proc(q: $Q/quaternion128) -> Q {
m := abs(q);
return m == 0 ? 0 : q/m;
}
normalize0_quaternion256 :: proc(q: $Q/quaternion256) -> Q {
m := abs(q);
return m == 0 ? 0 : q/m;
}
normalize0 :: proc{normalize0_vector, normalize0_quaternion128, normalize0_quaternion256};
length :: proc(v: $T/[$N]$E) -> E {
return math.sqrt(dot(v, v));
}
identity :: proc($T: typeid/[$N][N]$E) -> (m: T) {
for i in 0..<N do m[i][i] = E(1);
return m;
}
transpose :: proc(a: $T/[$N][$M]$E) -> (m: [M][N]E) {
for j in 0..<M {
for i in 0..<N {
m[j][i] = a[i][j];
}
}
return;
}
mul_matrix :: proc(a, b: $M/[$N][N]$E) -> (c: M)
where !intrinsics.type_is_array(E),
intrinsics.type_is_numeric(E) {
for i in 0..<N {
for k in 0..<N {
for j in 0..<N {
c[i][k] += a[i][j] * b[j][k];
}
}
}
return;
}
mul_matrix_differ :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: [I][K]E)
where !intrinsics.type_is_array(E),
intrinsics.type_is_numeric(E),
I != J {
for i in 0..<I {
for k in 0..<K {
for j in 0..<J {
c[i][k] += a[i][j] * b[j][k];
}
}
}
return;
}
mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
where !intrinsics.type_is_array(E),
intrinsics.type_is_numeric(E) {
for i in 0..<I {
for j in 0..<J {
c[i] += a[i][j] * b[i];
}
}
return;
}
mul_quaternion128_vector3 :: proc(q: $Q/quaternion128, v: $V/[3]$F/f32) -> V {
Raw_Quaternion :: struct {xyz: [3]f32, r: f32};
q := transmute(Raw_Quaternion)q;
v := transmute([3]f32)v;
t := cross(2*q.xyz, v);
return V(v + q.r*t + cross(q.xyz, t));
}
mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V {
Raw_Quaternion :: struct {xyz: [3]f64, r: f64};
q := transmute(Raw_Quaternion)q;
v := transmute([3]f64)v;
t := cross(2*q.xyz, v);
return V(v + q.r*t + cross(q.xyz, t));
}
mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3};
mul :: proc{
mul_matrix,
mul_matrix_differ,
mul_matrix_vector,
mul_quaternion128_vector3,
mul_quaternion256_vector3,
};
// Specific
Float :: f32;
Vector2 :: distinct [2]Float;
Vector3 :: distinct [3]Float;
Vector4 :: distinct [4]Float;
Matrix2x1 :: distinct [2][1]Float;
Matrix2x2 :: distinct [2][2]Float;
Matrix2x3 :: distinct [2][3]Float;
Matrix2x4 :: distinct [2][4]Float;
Matrix3x1 :: distinct [3][1]Float;
Matrix3x2 :: distinct [3][2]Float;
Matrix3x3 :: distinct [3][3]Float;
Matrix3x4 :: distinct [3][4]Float;
Matrix4x1 :: distinct [4][1]Float;
Matrix4x2 :: distinct [4][2]Float;
Matrix4x3 :: distinct [4][3]Float;
Matrix4x4 :: distinct [4][4]Float;
Matrix2 :: Matrix2x2;
Matrix3 :: Matrix3x3;
Matrix4 :: Matrix4x4;
Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256);
translate_matrix4 :: proc(v: Vector3) -> Matrix4 {
m := identity(Matrix4);
m[3][0] = v[0];
m[3][1] = v[1];
m[3][2] = v[2];
return m;
}
rotate_matrix4 :: proc(v: Vector3, angle_radians: Float) -> Matrix4 {
c := math.cos(angle_radians);
s := math.sin(angle_radians);
a := normalize(v);
t := a * (1-c);
rot := identity(Matrix4);
rot[0][0] = c + t[0]*a[0];
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
rot[0][3] = 0;
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
rot[1][1] = c + t[1]*a[1];
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
rot[1][3] = 0;
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
rot[2][2] = c + t[2]*a[2];
rot[2][3] = 0;
return rot;
}
scale_matrix4 :: proc(m: Matrix4, v: Vector3) -> Matrix4 {
mm := m;
mm[0][0] *= v[0];
mm[1][1] *= v[1];
mm[2][2] *= v[2];
return mm;
}
look_at :: proc(eye, centre, up: Vector3) -> Matrix4 {
f := normalize(centre - eye);
s := normalize(cross(f, up));
u := cross(s, f);
return Matrix4{
{+s.x, +u.x, -f.x, 0},
{+s.y, +u.y, -f.y, 0},
{+s.z, +u.z, -f.z, 0},
{-dot(s, eye), -dot(u, eye), +dot(f, eye), 1},
};
}
perspective :: proc(fovy, aspect, near, far: Float) -> (m: Matrix4) {
tan_half_fovy := math.tan(0.5 * fovy);
m[0][0] = 1 / (aspect*tan_half_fovy);
m[1][1] = 1 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near);
m[2][3] = -1;
m[3][2] = -2*far*near / (far - near);
return;
}
ortho3d :: proc(left, right, bottom, top, near, far: Float) -> (m: Matrix4) {
m[0][0] = +2 / (right - left);
m[1][1] = +2 / (top - bottom);
m[2][2] = -2 / (far - near);
m[3][0] = -(right + left) / (right - left);
m[3][1] = -(top + bottom) / (top - bottom);
m[3][2] = -(far + near) / (far- near);
m[3][3] = 1;
return;
}
axis_angle :: proc(axis: Vector3, angle_radians: Float) -> Quaternion {
t := angle_radians*0.5;
w := math.cos(t);
v := normalize(axis) * math.sin(t);
return quaternion(w, v.x, v.y, v.z);
}
angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion {
t := angle_radians*0.5;
w := math.cos(t);
v := normalize(axis) * math.sin(t);
return quaternion(w, v.x, v.y, v.z);
}
euler_angles :: proc(pitch, yaw, roll: Float) -> Quaternion {
p := axis_angle({1, 0, 0}, pitch);
y := axis_angle({0, 1, 0}, yaw);
r := axis_angle({0, 0, 1}, roll);
return (y * p) * r;
}
+386 -387
View File
@@ -1,36 +1,41 @@
package math package math
import "intrinsics"
Float_Class :: enum {
Normal, // an ordinary nonzero floating point value
Subnormal, // a subnormal floating point value
Zero, // zero
Neg_Zero, // the negative zero
NaN, // Not-A-Number (NaN)
Inf, // positive infinity
Neg_Inf // negative infinity
};
TAU :: 6.28318530717958647692528676655900576; TAU :: 6.28318530717958647692528676655900576;
PI :: 3.14159265358979323846264338327950288; PI :: 3.14159265358979323846264338327950288;
E :: 2.71828182845904523536; E :: 2.71828182845904523536;
τ :: TAU;
π :: PI;
e :: E;
SQRT_TWO :: 1.41421356237309504880168872420969808; SQRT_TWO :: 1.41421356237309504880168872420969808;
SQRT_THREE :: 1.73205080756887729352744634150587236; SQRT_THREE :: 1.73205080756887729352744634150587236;
SQRT_FIVE :: 2.23606797749978969640917366873127623; SQRT_FIVE :: 2.23606797749978969640917366873127623;
LOG_TWO :: 0.693147180559945309417232121458176568; LN2 :: 0.693147180559945309417232121458176568;
LOG_TEN :: 2.30258509299404568401799145468436421; LN10 :: 2.30258509299404568401799145468436421;
EPSILON :: 1.19209290e-7; MAX_F64_PRECISION :: 16; // Maximum number of meaningful digits after the decimal point for 'f64'
MAX_F32_PRECISION :: 8; // Maximum number of meaningful digits after the decimal point for 'f32'
τ :: TAU; RAD_PER_DEG :: TAU/360.0;
π :: PI; DEG_PER_RAD :: 360.0/TAU;
Vec2 :: distinct [2]f32;
Vec3 :: distinct [3]f32;
Vec4 :: distinct [4]f32;
// Column major
Mat2 :: distinct [2][2]f32;
Mat3 :: distinct [3][3]f32;
Mat4 :: distinct [4][4]f32;
Quat :: struct {x, y, z, w: f32};
QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1};
@(default_calling_convention="c") @(default_calling_convention="none")
foreign _ { foreign _ {
@(link_name="llvm.sqrt.f32") @(link_name="llvm.sqrt.f32")
sqrt_f32 :: proc(x: f32) -> f32 ---; sqrt_f32 :: proc(x: f32) -> f32 ---;
@@ -58,9 +63,9 @@ foreign _ {
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---; fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
@(link_name="llvm.log.f32") @(link_name="llvm.log.f32")
log_f32 :: proc(x: f32) -> f32 ---; ln_f32 :: proc(x: f32) -> f32 ---;
@(link_name="llvm.log.f64") @(link_name="llvm.log.f64")
log_f64 :: proc(x: f64) -> f64 ---; ln_f64 :: proc(x: f64) -> f64 ---;
@(link_name="llvm.exp.f32") @(link_name="llvm.exp.f32")
exp_f32 :: proc(x: f32) -> f32 ---; exp_f32 :: proc(x: f32) -> f32 ---;
@@ -68,20 +73,40 @@ foreign _ {
exp_f64 :: proc(x: f64) -> f64 ---; exp_f64 :: proc(x: f64) -> f64 ---;
} }
log :: proc{log_f32, log_f64}; sqrt :: proc{sqrt_f32, sqrt_f64};
sin :: proc{sin_f32, sin_f64};
cos :: proc{cos_f32, cos_f64};
pow :: proc{pow_f32, pow_f64};
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
ln :: proc{ln_f32, ln_f64};
exp :: proc{exp_f32, exp_f64}; exp :: proc{exp_f32, exp_f64};
log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); }
log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); }
log :: proc{log_f32, log_f64};
log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; }
log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; }
log2 :: proc{log2_f32, log2_f64};
log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; }
log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; }
log10 :: proc{log10_f32, log10_f64};
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); } tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); } tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
tan :: proc{tan_f32, tan_f64};
lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; } lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; }
unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); } unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); }
unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); } unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); }
unlerp :: proc{unlerp_f32, unlerp_f64};
sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); }
sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; } sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); }
sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; } sign :: proc{sign_f32, sign_f64};
copy_sign_f32 :: proc(x, y: f32) -> f32 { copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x; ix := transmute(u32)x;
@@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 {
ix |= iy & 0x8000_0000; ix |= iy & 0x8000_0000;
return transmute(f32)ix; return transmute(f32)ix;
} }
copy_sign_f64 :: proc(x, y: f64) -> f64 { copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix := transmute(u64)x; ix := transmute(u64)x;
iy := transmute(u64)y; iy := transmute(u64)y;
@@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 {
ix |= iy & 0x8000_0000_0000_0000; ix |= iy & 0x8000_0000_0000_0000;
return transmute(f64)ix; return transmute(f64)ix;
} }
sqrt :: proc{sqrt_f32, sqrt_f64};
sin :: proc{sin_f32, sin_f64};
cos :: proc{cos_f32, cos_f64};
tan :: proc{tan_f32, tan_f64};
pow :: proc{pow_f32, pow_f64};
fmuladd :: proc{fmuladd_f32, fmuladd_f64};
sign :: proc{sign_f32, sign_f64};
copy_sign :: proc{copy_sign_f32, copy_sign_f64}; copy_sign :: proc{copy_sign_f32, copy_sign_f64};
round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; }
round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; }
to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; }
to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; }
to_radians :: proc{to_radians_f32, to_radians_f64};
to_degrees :: proc{to_degrees_f32, to_degrees_f64};
trunc_f32 :: proc(x: f32) -> f32 {
trunc_internal :: proc(f: f32) -> f32 {
mask :: 0xff;
shift :: 32 - 9;
bias :: 0x7f;
if f < 1 {
switch {
case f < 0: return -trunc_internal(-f);
case f == 0: return f;
case: return 0;
}
}
x := transmute(u32)f;
e := (x >> shift) & mask - bias;
if e < shift {
x &= ~(1 << (shift-e)) - 1;
}
return transmute(f32)x;
}
switch classify(x) {
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
return x;
}
return trunc_internal(x);
}
trunc_f64 :: proc(x: f64) -> f64 {
trunc_internal :: proc(f: f64) -> f64 {
mask :: 0x7ff;
shift :: 64 - 12;
bias :: 0x3ff;
if f < 1 {
switch {
case f < 0: return -trunc_internal(-f);
case f == 0: return f;
case: return 0;
}
}
x := transmute(u64)f;
e := (x >> shift) & mask - bias;
if e < shift {
x &= ~(1 << (shift-e)) - 1;
}
return transmute(f64)x;
}
switch classify(x) {
case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf:
return x;
}
return trunc_internal(x);
}
trunc :: proc{trunc_f32, trunc_f64};
round_f32 :: proc(x: f32) -> f32 {
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
}
round_f64 :: proc(x: f64) -> f64 {
return x < 0 ? ceil(x - 0.5) : floor(x + 0.5);
}
round :: proc{round_f32, round_f64}; round :: proc{round_f32, round_f64};
ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); }
ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); }
ceil :: proc{ceil_f32, ceil_f64};
floor_f32 :: proc(x: f32) -> f32 { floor_f32 :: proc(x: f32) -> f32 {
if x == 0 || is_nan(x) || is_inf(x) { if x == 0 || is_nan(x) || is_inf(x) {
return x; return x;
@@ -144,33 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 {
} }
floor :: proc{floor_f32, floor_f64}; floor :: proc{floor_f32, floor_f64};
ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); }
ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); }
ceil :: proc{ceil_f32, ceil_f64};
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; } floor_div :: proc(x, y: $T) -> T
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; } where intrinsics.type_is_integer(T) {
remainder :: proc{remainder_f32, remainder_f64}; a := x / y;
r := x % y;
if (r > 0 && y < 0) || (r < 0 && y > 0) {
a -= 1;
}
return a;
}
mod_f32 :: proc(x, y: f32) -> (n: f32) { floor_mod :: proc(x, y: $T) -> T
z := abs(y); where intrinsics.type_is_integer(T) {
n = remainder(abs(x), z); r := x % y;
if sign(n) < 0 { if (r > 0 && y < 0) || (r < 0 && y > 0) {
n += z; r += y;
} }
return copy_sign(n, x); return r;
} }
mod_f64 :: proc(x, y: f64) -> (n: f64) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
n += z;
}
return copy_sign(n, x);
}
mod :: proc{mod_f32, mod_f64};
// TODO(bill): These need to implemented with the actual instructions
modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) { modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
shift :: 32 - 8 - 1; shift :: 32 - 8 - 1;
mask :: 0xff; mask :: 0xff;
@@ -190,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) {
i := transmute(u32)x; i := transmute(u32)x;
e := uint(i>>shift)&mask - bias; e := uint(i>>shift)&mask - bias;
if e < 32-9 { if e < shift {
i &~= 1<<(32-9-e) - 1; i &~= 1<<(shift-e) - 1;
} }
int = transmute(f32)i; int = transmute(f32)i;
frac = x - int; frac = x - int;
@@ -216,360 +301,274 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) {
i := transmute(u64)x; i := transmute(u64)x;
e := uint(i>>shift)&mask - bias; e := uint(i>>shift)&mask - bias;
if e < 64-12 { if e < shift {
i &~= 1<<(64-12-e) - 1; i &~= 1<<(shift-e) - 1;
} }
int = transmute(f64)i; int = transmute(f64)i;
frac = x - int; frac = x - int;
return; return;
} }
modf :: proc{modf_f32, modf_f64}; modf :: proc{modf_f32, modf_f64};
split_decimal :: modf;
is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; } mod_f32 :: proc(x, y: f32) -> (n: f32) {
is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; } z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
n += z;
}
return copy_sign(n, x);
}
mod_f64 :: proc(x, y: f64) -> (n: f64) {
z := abs(y);
n = remainder(abs(x), z);
if sign(n) < 0 {
n += z;
}
return copy_sign(n, x);
}
mod :: proc{mod_f32, mod_f64};
remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
remainder :: proc{remainder_f32, remainder_f64};
gcd :: proc(x, y: $T) -> T
where intrinsics.type_is_ordered_numeric(T) {
x, y := x, y;
for y != 0 {
x %= y;
x, y = y, x;
}
return abs(x);
}
lcm :: proc(x, y: $T) -> T
where intrinsics.type_is_ordered_numeric(T) {
return x / gcd(x, y) * y;
}
frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) {
switch {
case x == 0:
return 0, 0;
case x < 0:
significand, exponent = frexp(-x);
return -significand, exponent;
}
ex := trunc(log2(x));
exponent = int(ex);
significand = x / pow(2.0, ex);
if abs(significand) >= 1 {
exponent += 1;
significand /= 2;
}
if exponent == 1024 && significand == 0 {
significand = 0.99999999999999988898;
}
return;
}
frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) {
switch {
case x == 0:
return 0, 0;
case x < 0:
significand, exponent = frexp(-x);
return -significand, exponent;
}
ex := trunc(log2(x));
exponent = int(ex);
significand = x / pow(2.0, ex);
if abs(significand) >= 1 {
exponent += 1;
significand /= 2;
}
if exponent == 1024 && significand == 0 {
significand = 0.99999999999999988898;
}
return;
}
frexp :: proc{frexp_f32, frexp_f64};
binomial :: proc(n, k: int) -> int {
switch {
case k <= 0: return 1;
case 2*k > n: return binomial(n, n-k);
}
b := n;
for i in 2..<k {
b = (b * (n+1-i))/i;
}
return b;
}
factorial :: proc(n: int) -> int {
when size_of(int) == size_of(i64) {
@static table := [21]int{
1,
1,
2,
6,
24,
120,
720,
5_040,
40_320,
362_880,
3_628_800,
39_916_800,
479_001_600,
6_227_020_800,
87_178_291_200,
1_307_674_368_000,
20_922_789_888_000,
355_687_428_096_000,
6_402_373_705_728_000,
121_645_100_408_832_000,
2_432_902_008_176_640_000,
};
} else {
@static table := [13]int{
1,
1,
2,
6,
24,
120,
720,
5_040,
40_320,
362_880,
3_628_800,
39_916_800,
479_001_600,
};
}
assert(n >= 0, "parameter must not be negative");
assert(n < len(table), "parameter is too large to lookup in the table");
return 0;
}
classify_f32 :: proc(x: f32) -> Float_Class {
switch {
case x == 0:
i := transmute(i32)x;
if i < 0 {
return .Neg_Zero;
}
return .Zero;
case x*0.5 == x:
if x < 0 {
return .Neg_Inf;
}
return .Inf;
case x != x:
return .NaN;
}
u := transmute(u32)x;
exp := int(u>>23) & (1<<8 - 1);
if exp == 0 {
return .Subnormal;
}
return .Normal;
}
classify_f64 :: proc(x: f64) -> Float_Class {
switch {
case x == 0:
i := transmute(i64)x;
if i < 0 {
return .Neg_Zero;
}
return .Zero;
case x*0.5 == x:
if x < 0 {
return .Neg_Inf;
}
return .Inf;
case x != x:
return .NaN;
}
u := transmute(u64)x;
exp := int(u>>52) & (1<<11 - 1);
if exp == 0 {
return .Subnormal;
}
return .Normal;
}
classify :: proc{classify_f32, classify_f64};
is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; }
is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; }
is_nan :: proc{is_nan_f32, is_nan_f64}; is_nan :: proc{is_nan_f32, is_nan_f64};
is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); } is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; }
is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); } is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; }
is_finite :: proc{is_finite_f32, is_finite_f64};
is_inf_f32 :: proc(x: f32, sign := 0) -> bool {
return sign >= 0 && x > F32_MAX || sign <= 0 && x < -F32_MAX;
}
is_inf_f64 :: proc(x: f64, sign := 0) -> bool {
return sign >= 0 && x > F64_MAX || sign <= 0 && x < -F64_MAX;
}
// If sign > 0, is_inf reports whether f is positive infinity
// If sign < 0, is_inf reports whether f is negative infinity
// If sign == 0, is_inf reports whether f is either infinity
is_inf :: proc{is_inf_f32, is_inf_f64}; is_inf :: proc{is_inf_f32, is_inf_f64};
to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; } is_power_of_two :: proc(x: int) -> bool {
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; } return x > 0 && (x & (x-1)) == 0;
mul :: proc{
mat3_mul,
mat4_mul, mat4_mul_vec4,
quat_mul, quat_mulf,
};
div :: proc{quat_div, quat_divf};
inverse :: proc{mat4_inverse, quat_inverse};
dot :: proc{vec_dot, quat_dot};
cross :: proc{cross2, cross3};
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
res: E;
for i in 0..<N {
res += a[i] * b[i];
}
return res;
} }
cross2 :: proc(a, b: $T/[2]$E) -> E { next_power_of_two :: proc(x: int) -> int {
return a[0]*b[1] - a[1]*b[0]; k := x -1;
when size_of(int) == 8 {
k = k | (k >> 32);
}
k = k | (k >> 16);
k = k | (k >> 8);
k = k | (k >> 4);
k = k | (k >> 2);
k = k | (k >> 1);
k += 1 + int(x <= 0);
return k;
} }
cross3 :: proc(a, b: $T/[3]$E) -> T { sum :: proc(x: $T/[]$E) -> (res: E)
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1); where intrinsics.BuiltinProc_type_is_numeric(E) {
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0); for i in x {
return T(i - j); res += i;
}
return;
} }
prod :: proc(x: $T/[]$E) -> (res: E)
length :: proc(v: $T/[$N]$E) -> E { return sqrt(dot(v, v)); } where intrinsics.BuiltinProc_type_is_numeric(E) {
for i in x {
norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); } res *= i;
}
norm0 :: proc(v: $T/[$N]$E) -> T { return;
m := length(v);
return m == 0 ? 0 : v/m;
} }
cumsum_inplace :: proc(x: $T/[]$E) -> T
where intrinsics.BuiltinProc_type_is_numeric(E) {
identity :: proc($T: typeid/[$N][N]$E) -> T { for i in 1..<len(x) {
m: T; x[i] = x[i-1] + x[i];
for i in 0..<N do m[i][i] = E(1);
return m;
}
transpose :: proc(m: $M/[$N][N]f32) -> M {
for j in 0..<N {
for i in 0..<N {
m[i][j], m[j][i] = m[j][i], m[i][j];
} }
} }
return m;
}
mat3_mul :: proc(a, b: Mat3) -> Mat3 {
c: Mat3; cumsum :: proc(dst, src: $T/[]$E) -> T
for j in 0..<3 { where intrinsics.BuiltinProc_type_is_numeric(E) {
for i in 0..<3 { N := min(len(dst), len(src));
c[j][i] = a[0][i]*b[j][0] + if N > 0 {
a[1][i]*b[j][1] + dst[0] = src[0];
a[2][i]*b[j][2]; for i in 1..<N {
dst[i] = dst[i-1] + src[i];
} }
} }
return c; return dst[:N];
} }
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
c: Mat4;
for j in 0..<4 {
for i in 0..<4 {
c[j][i] = a[0][i]*b[j][0] +
a[1][i]*b[j][1] +
a[2][i]*b[j][2] +
a[3][i]*b[j][3];
}
}
return c;
}
mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{
m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3],
m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3],
m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3],
m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3],
};
}
mat4_inverse :: proc(m: Mat4) -> Mat4 {
o: Mat4;
sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3];
sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3];
sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2];
sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3];
sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2];
sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1];
sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3];
sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2];
sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3];
sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2];
sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3];
sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1];
sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3];
sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3];
sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2];
sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3];
sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2];
sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1];
o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02);
o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04);
o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05);
o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05);
o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02);
o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04);
o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05);
o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05);
o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08);
o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10);
o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12);
o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12);
o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15);
o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17);
o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18);
o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18);
ood := 1.0 / (m[0][0] * o[0][0] +
m[0][1] * o[0][1] +
m[0][2] * o[0][2] +
m[0][3] * o[0][3]);
o[0][0] *= ood;
o[0][1] *= ood;
o[0][2] *= ood;
o[0][3] *= ood;
o[1][0] *= ood;
o[1][1] *= ood;
o[1][2] *= ood;
o[1][3] *= ood;
o[2][0] *= ood;
o[2][1] *= ood;
o[2][2] *= ood;
o[2][3] *= ood;
o[3][0] *= ood;
o[3][1] *= ood;
o[3][2] *= ood;
o[3][3] *= ood;
return o;
}
mat4_translate :: proc(v: Vec3) -> Mat4 {
m := identity(Mat4);
m[3][0] = v[0];
m[3][1] = v[1];
m[3][2] = v[2];
m[3][3] = 1;
return m;
}
mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 {
c := cos(angle_radians);
s := sin(angle_radians);
a := norm(v);
t := a * (1-c);
rot := identity(Mat4);
rot[0][0] = c + t[0]*a[0];
rot[0][1] = 0 + t[0]*a[1] + s*a[2];
rot[0][2] = 0 + t[0]*a[2] - s*a[1];
rot[0][3] = 0;
rot[1][0] = 0 + t[1]*a[0] - s*a[2];
rot[1][1] = c + t[1]*a[1];
rot[1][2] = 0 + t[1]*a[2] + s*a[0];
rot[1][3] = 0;
rot[2][0] = 0 + t[2]*a[0] + s*a[1];
rot[2][1] = 0 + t[2]*a[1] - s*a[0];
rot[2][2] = c + t[2]*a[2];
rot[2][3] = 0;
return rot;
}
scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 {
mm := m;
mm[0][0] *= v[0];
mm[1][1] *= v[1];
mm[2][2] *= v[2];
return m;
}
scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 {
mm := m;
mm[0][0] *= s;
mm[1][1] *= s;
mm[2][2] *= s;
return m;
}
scale :: proc{scale_vec3, scale_f32};
look_at :: proc(eye, centre, up: Vec3) -> Mat4 {
f := norm(centre - eye);
s := norm(cross(f, up));
u := cross(s, f);
return Mat4{
{+s.x, +u.x, -f.x, 0},
{+s.y, +u.y, -f.y, 0},
{+s.z, +u.z, -f.z, 0},
{-dot(s, eye), -dot(u, eye), dot(f, eye), 1},
};
}
perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 {
m: Mat4;
tan_half_fovy := tan(0.5 * fovy);
m[0][0] = 1.0 / (aspect*tan_half_fovy);
m[1][1] = 1.0 / (tan_half_fovy);
m[2][2] = -(far + near) / (far - near);
m[2][3] = -1.0;
m[3][2] = -2.0*far*near / (far - near);
return m;
}
ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 {
m := identity(Mat4);
m[0][0] = +2.0 / (right - left);
m[1][1] = +2.0 / (top - bottom);
m[2][2] = -2.0 / (far - near);
m[3][0] = -(right + left) / (right - left);
m[3][1] = -(top + bottom) / (top - bottom);
m[3][2] = -(far + near) / (far - near);
return m;
}
// Quaternion operations
conj :: proc(q: Quat) -> Quat {
return Quat{-q.x, -q.y, -q.z, q.w};
}
quat_mul :: proc(q0, q1: Quat) -> Quat {
d: Quat;
d.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y;
d.y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x;
d.z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w;
d.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
return d;
}
quat_mulf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x*f, q.y*f, q.z*f, q.w*f}; }
quat_divf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x/f, q.y/f, q.z/f, q.w/f}; }
quat_div :: proc(q0, q1: Quat) -> Quat { return mul(q0, quat_inverse(q1)); }
quat_inverse :: proc(q: Quat) -> Quat { return div(conj(q), dot(q, q)); }
quat_dot :: proc(q0, q1: Quat) -> f32 { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; }
quat_norm :: proc(q: Quat) -> Quat {
m := sqrt(dot(q, q));
return div(q, m);
}
axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat {
v := norm(axis) * sin(0.5*angle_radians);
w := cos(0.5*angle_radians);
return Quat{v.x, v.y, v.z, w};
}
euler_angles :: proc(pitch, yaw, roll: f32) -> Quat {
p := axis_angle(Vec3{1, 0, 0}, pitch);
y := axis_angle(Vec3{0, 1, 0}, yaw);
r := axis_angle(Vec3{0, 0, 1}, roll);
return mul(mul(y, p), r);
}
quat_to_mat4 :: proc(q: Quat) -> Mat4 {
a := quat_norm(q);
xx := a.x*a.x; yy := a.y*a.y; zz := a.z*a.z;
xy := a.x*a.y; xz := a.x*a.z; yz := a.y*a.z;
wx := a.w*a.x; wy := a.w*a.y; wz := a.w*a.z;
m := identity(Mat4);
m[0][0] = 1 - 2*(yy + zz);
m[0][1] = 2*(xy + wz);
m[0][2] = 2*(xz - wy);
m[1][0] = 2*(xy - wz);
m[1][1] = 1 - 2*(xx + zz);
m[1][2] = 2*(yz + wx);
m[2][0] = 2*(xz + wy);
m[2][1] = 2*(yz - wx);
m[2][2] = 1 - 2*(xx + yy);
return m;
}
F32_DIG :: 6; F32_DIG :: 6;
F32_EPSILON :: 1.192092896e-07; F32_EPSILON :: 1.192092896e-07;
+2 -2
View File
@@ -128,8 +128,8 @@ norm_float64 :: proc(r: ^Rand = global_rand_ptr) -> f64 {
if i == 0 { if i == 0 {
for { for {
x = -math.log(float64(r)) * (1.0/ rn); x = -math.ln(float64(r)) * (1.0/ rn);
y := -math.log(float64(r)); y := -math.ln(float64(r));
if y+y >= x*x { if y+y >= x*x {
break; break;
} }
-2
View File
@@ -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
View File
@@ -31,6 +31,12 @@ Raw_Map :: struct {
entries: Raw_Dynamic_Array, entries: Raw_Dynamic_Array,
} }
Raw_Complex64 :: struct {real, imag: f32};
Raw_Complex128 :: struct {real, imag: f64};
Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32};
Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64};
Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32};
Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64};
make_any :: inline proc(data: rawptr, id: typeid) -> any { make_any :: inline proc(data: rawptr, id: typeid) -> any {
return transmute(any)Raw_Any{data, id}; return transmute(any)Raw_Any{data, id};
+110 -101
View File
@@ -1,11 +1,10 @@
package odin_ast package odin_ast
import "core:odin/token" import "core:odin/tokenizer"
Proc_Tag :: enum { Proc_Tag :: enum {
Bounds_Check, Bounds_Check,
No_Bounds_Check, No_Bounds_Check,
Require_Results,
} }
Proc_Tags :: distinct bit_set[Proc_Tag; u32]; Proc_Tags :: distinct bit_set[Proc_Tag; u32];
@@ -34,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag];
Comment_Group :: struct { Comment_Group :: struct {
list: []token.Token, list: []tokenizer.Token,
} }
Node :: struct { Node :: struct {
pos: token.Pos, pos: tokenizer.Pos,
end: token.Pos, end: tokenizer.Pos,
derived: any, derived: any,
state_flags: Node_State_Flags, state_flags: Node_State_Flags,
} }
@@ -68,29 +67,29 @@ Ident :: struct {
Implicit :: struct { Implicit :: struct {
using node: Expr, using node: Expr,
tok: token.Token, tok: tokenizer.Token,
} }
Undef :: struct { Undef :: struct {
using node: Expr, using node: Expr,
tok: token.Kind, tok: tokenizer.Token_Kind,
} }
Basic_Lit :: struct { Basic_Lit :: struct {
using node: Expr, using node: Expr,
tok: token.Token, tok: tokenizer.Token,
} }
Basic_Directive :: struct { Basic_Directive :: struct {
using node: Expr, using node: Expr,
tok: token.Token, tok: tokenizer.Token,
name: string, name: string,
} }
Ellipsis :: struct { Ellipsis :: struct {
using node: Expr, using node: Expr,
tok: token.Kind, tok: tokenizer.Token_Kind,
expr: ^Expr, expr: ^Expr,
} }
@@ -100,42 +99,44 @@ Proc_Lit :: struct {
body: ^Stmt, body: ^Stmt,
tags: Proc_Tags, tags: Proc_Tags,
inlining: Proc_Inlining, inlining: Proc_Inlining,
where_token: tokenizer.Token,
where_clauses: []^Expr,
} }
Comp_Lit :: struct { Comp_Lit :: struct {
using node: Expr, using node: Expr,
type: ^Expr, type: ^Expr,
open: token.Pos, open: tokenizer.Pos,
elems: []^Expr, elems: []^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Tag_Expr :: struct { Tag_Expr :: struct {
using node: Expr, using node: Expr,
op: token.Token, op: tokenizer.Token,
name: string, name: string,
expr: ^Expr, expr: ^Expr,
} }
Unary_Expr :: struct { Unary_Expr :: struct {
using node: Expr, using node: Expr,
op: token.Token, op: tokenizer.Token,
expr: ^Expr, expr: ^Expr,
} }
Binary_Expr :: struct { Binary_Expr :: struct {
using node: Expr, using node: Expr,
left: ^Expr, left: ^Expr,
op: token.Token, op: tokenizer.Token,
right: ^Expr, right: ^Expr,
} }
Paren_Expr :: struct { Paren_Expr :: struct {
using node: Expr, using node: Expr,
open: token.Pos, open: tokenizer.Pos,
expr: ^Expr, expr: ^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Selector_Expr :: struct { Selector_Expr :: struct {
@@ -152,74 +153,74 @@ Implicit_Selector_Expr :: struct {
Index_Expr :: struct { Index_Expr :: struct {
using node: Expr, using node: Expr,
expr: ^Expr, expr: ^Expr,
open: token.Pos, open: tokenizer.Pos,
index: ^Expr, index: ^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Deref_Expr :: struct { Deref_Expr :: struct {
using node: Expr, using node: Expr,
expr: ^Expr, expr: ^Expr,
op: token.Token, op: tokenizer.Token,
} }
Slice_Expr :: struct { Slice_Expr :: struct {
using node: Expr, using node: Expr,
expr: ^Expr, expr: ^Expr,
open: token.Pos, open: tokenizer.Pos,
low: ^Expr, low: ^Expr,
interval: token.Token, interval: tokenizer.Token,
high: ^Expr, high: ^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Call_Expr :: struct { Call_Expr :: struct {
using node: Expr, using node: Expr,
inlining: Proc_Inlining, inlining: Proc_Inlining,
expr: ^Expr, expr: ^Expr,
open: token.Pos, open: tokenizer.Pos,
args: []^Expr, args: []^Expr,
ellipsis: token.Token, ellipsis: tokenizer.Token,
close: token.Pos, close: tokenizer.Pos,
} }
Field_Value :: struct { Field_Value :: struct {
using node: Expr, using node: Expr,
field: ^Expr, field: ^Expr,
sep: token.Pos, sep: tokenizer.Pos,
value: ^Expr, value: ^Expr,
} }
Ternary_Expr :: struct { Ternary_Expr :: struct {
using node: Expr, using node: Expr,
cond: ^Expr, cond: ^Expr,
op1: token.Token, op1: tokenizer.Token,
x: ^Expr, x: ^Expr,
op2: token.Token, op2: tokenizer.Token,
y: ^Expr, y: ^Expr,
} }
Type_Assertion :: struct { Type_Assertion :: struct {
using node: Expr, using node: Expr,
expr: ^Expr, expr: ^Expr,
dot: token.Pos, dot: tokenizer.Pos,
open: token.Pos, open: tokenizer.Pos,
type: ^Expr, type: ^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Type_Cast :: struct { Type_Cast :: struct {
using node: Expr, using node: Expr,
tok: token.Token, tok: tokenizer.Token,
open: token.Pos, open: tokenizer.Pos,
type: ^Expr, type: ^Expr,
close: token.Pos, close: tokenizer.Pos,
expr: ^Expr, expr: ^Expr,
} }
Auto_Cast :: struct { Auto_Cast :: struct {
using node: Expr, using node: Expr,
op: token.Token, op: tokenizer.Token,
expr: ^Expr, expr: ^Expr,
} }
@@ -234,7 +235,7 @@ Bad_Stmt :: struct {
Empty_Stmt :: struct { Empty_Stmt :: struct {
using node: Stmt, using node: Stmt,
semicolon: token.Pos, // Position of the following ';' semicolon: tokenizer.Pos, // Position of the following ';'
} }
Expr_Stmt :: struct { Expr_Stmt :: struct {
@@ -244,7 +245,7 @@ Expr_Stmt :: struct {
Tag_Stmt :: struct { Tag_Stmt :: struct {
using node: Stmt, using node: Stmt,
op: token.Token, op: tokenizer.Token,
name: string, name: string,
stmt: ^Stmt, stmt: ^Stmt,
} }
@@ -252,7 +253,7 @@ Tag_Stmt :: struct {
Assign_Stmt :: struct { Assign_Stmt :: struct {
using node: Stmt, using node: Stmt,
lhs: []^Expr, lhs: []^Expr,
op: token.Token, op: tokenizer.Token,
rhs: []^Expr, rhs: []^Expr,
} }
@@ -260,15 +261,15 @@ Assign_Stmt :: struct {
Block_Stmt :: struct { Block_Stmt :: struct {
using node: Stmt, using node: Stmt,
label: ^Expr, label: ^Expr,
open: token.Pos, open: tokenizer.Pos,
stmts: []^Stmt, stmts: []^Stmt,
close: token.Pos, close: tokenizer.Pos,
} }
If_Stmt :: struct { If_Stmt :: struct {
using node: Stmt, using node: Stmt,
label: ^Expr, label: ^Expr,
if_pos: token.Pos, if_pos: tokenizer.Pos,
init: ^Stmt, init: ^Stmt,
cond: ^Expr, cond: ^Expr,
body: ^Stmt, body: ^Stmt,
@@ -277,7 +278,7 @@ If_Stmt :: struct {
When_Stmt :: struct { When_Stmt :: struct {
using node: Stmt, using node: Stmt,
when_pos: token.Pos, when_pos: tokenizer.Pos,
cond: ^Expr, cond: ^Expr,
body: ^Stmt, body: ^Stmt,
else_stmt: ^Stmt, else_stmt: ^Stmt,
@@ -296,7 +297,7 @@ Defer_Stmt :: struct {
For_Stmt :: struct { For_Stmt :: struct {
using node: Stmt, using node: Stmt,
label: ^Expr, label: ^Expr,
for_pos: token.Pos, for_pos: tokenizer.Pos,
init: ^Stmt, init: ^Stmt,
cond: ^Expr, cond: ^Expr,
post: ^Stmt, post: ^Stmt,
@@ -306,10 +307,10 @@ For_Stmt :: struct {
Range_Stmt :: struct { Range_Stmt :: struct {
using node: Stmt, using node: Stmt,
label: ^Expr, label: ^Expr,
for_pos: token.Pos, for_pos: tokenizer.Pos,
val0: ^Expr, val0: ^Expr,
val1: ^Expr, val1: ^Expr,
in_pos: token.Pos, in_pos: tokenizer.Pos,
expr: ^Expr, expr: ^Expr,
body: ^Stmt, body: ^Stmt,
} }
@@ -317,16 +318,16 @@ Range_Stmt :: struct {
Case_Clause :: struct { Case_Clause :: struct {
using node: Stmt, using node: Stmt,
case_pos: token.Pos, case_pos: tokenizer.Pos,
list: []^Expr, list: []^Expr,
terminator: token.Token, terminator: tokenizer.Token,
body: []^Stmt, body: []^Stmt,
} }
Switch_Stmt :: struct { Switch_Stmt :: struct {
using node: Stmt, using node: Stmt,
label: ^Expr, label: ^Expr,
switch_pos: token.Pos, switch_pos: tokenizer.Pos,
init: ^Stmt, init: ^Stmt,
cond: ^Expr, cond: ^Expr,
body: ^Stmt, body: ^Stmt,
@@ -336,7 +337,7 @@ Switch_Stmt :: struct {
Type_Switch_Stmt :: struct { Type_Switch_Stmt :: struct {
using node: Stmt, using node: Stmt,
label: ^Expr, label: ^Expr,
switch_pos: token.Pos, switch_pos: tokenizer.Pos,
tag: ^Stmt, tag: ^Stmt,
expr: ^Expr, expr: ^Expr,
body: ^Stmt, body: ^Stmt,
@@ -345,7 +346,7 @@ Type_Switch_Stmt :: struct {
Branch_Stmt :: struct { Branch_Stmt :: struct {
using node: Stmt, using node: Stmt,
tok: token.Token, tok: tokenizer.Token,
label: ^Ident, label: ^Ident,
} }
@@ -376,7 +377,7 @@ Value_Decl :: struct {
Package_Decl :: struct { Package_Decl :: struct {
using node: Decl, using node: Decl,
docs: ^Comment_Group, docs: ^Comment_Group,
token: token.Token, token: tokenizer.Token,
name: string, name: string,
comment: ^Comment_Group, comment: ^Comment_Group,
} }
@@ -385,9 +386,9 @@ Import_Decl :: struct {
using node: Decl, using node: Decl,
docs: ^Comment_Group, docs: ^Comment_Group,
is_using: bool, is_using: bool,
import_tok: token.Token, import_tok: tokenizer.Token,
name: token.Token, name: tokenizer.Token,
relpath: token.Token, relpath: tokenizer.Token,
fullpath: string, fullpath: string,
comment: ^Comment_Group, comment: ^Comment_Group,
} }
@@ -396,7 +397,7 @@ Foreign_Block_Decl :: struct {
using node: Decl, using node: Decl,
docs: ^Comment_Group, docs: ^Comment_Group,
attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily
tok: token.Token, tok: tokenizer.Token,
foreign_library: ^Expr, foreign_library: ^Expr,
body: ^Stmt, body: ^Stmt,
} }
@@ -404,8 +405,8 @@ Foreign_Block_Decl :: struct {
Foreign_Import_Decl :: struct { Foreign_Import_Decl :: struct {
using node: Decl, using node: Decl,
docs: ^Comment_Group, docs: ^Comment_Group,
foreign_tok: token.Token, foreign_tok: tokenizer.Token,
import_tok: token.Token, import_tok: tokenizer.Token,
name: ^Ident, name: ^Ident,
collection_name: string, collection_name: string,
fullpaths: []string, fullpaths: []string,
@@ -435,7 +436,9 @@ Field_Flag :: enum {
C_Vararg, C_Vararg,
Auto_Cast, Auto_Cast,
In, In,
Results, Results,
Tags,
Default_Parameters, Default_Parameters,
Typeid_Token, Typeid_Token,
} }
@@ -443,18 +446,19 @@ Field_Flag :: enum {
Field_Flags :: distinct bit_set[Field_Flag]; Field_Flags :: distinct bit_set[Field_Flag];
Field_Flags_Struct :: Field_Flags{ Field_Flags_Struct :: Field_Flags{
Field_Flag.Using, .Using,
.Tags,
}; };
Field_Flags_Record_Poly_Params :: Field_Flags{ Field_Flags_Record_Poly_Params :: Field_Flags{
Field_Flag.Typeid_Token, .Typeid_Token,
}; };
Field_Flags_Signature :: Field_Flags{ Field_Flags_Signature :: Field_Flags{
Field_Flag.Ellipsis, .Ellipsis,
Field_Flag.Using, .Using,
Field_Flag.No_Alias, .No_Alias,
Field_Flag.C_Vararg, .C_Vararg,
Field_Flag.Auto_Cast, .Auto_Cast,
Field_Flag.Default_Parameters, .Default_Parameters,
}; };
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token}; Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
@@ -463,18 +467,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature;
Proc_Group :: struct { Proc_Group :: struct {
using node: Expr, using node: Expr,
tok: token.Token, tok: tokenizer.Token,
open: token.Pos, open: tokenizer.Pos,
args: []^Expr, args: []^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Attribute :: struct { Attribute :: struct {
using node: Node, using node: Node,
tok: token.Kind, tok: tokenizer.Token_Kind,
open: token.Pos, open: tokenizer.Pos,
elems: []^Expr, elems: []^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Field :: struct { Field :: struct {
@@ -483,56 +487,57 @@ Field :: struct {
names: []^Expr, // Could be polymorphic names: []^Expr, // Could be polymorphic
type: ^Expr, type: ^Expr,
default_value: ^Expr, default_value: ^Expr,
tag: tokenizer.Token,
flags: Field_Flags, flags: Field_Flags,
comment: ^Comment_Group, comment: ^Comment_Group,
} }
Field_List :: struct { Field_List :: struct {
using node: Node, using node: Node,
open: token.Pos, open: tokenizer.Pos,
list: []^Field, list: []^Field,
close: token.Pos, close: tokenizer.Pos,
} }
// Types // Types
Typeid_Type :: struct { Typeid_Type :: struct {
using node: Expr, using node: Expr,
tok: token.Kind, tok: tokenizer.Token_Kind,
specialization: ^Expr, specialization: ^Expr,
} }
Helper_Type :: struct { Helper_Type :: struct {
using node: Expr, using node: Expr,
tok: token.Kind, tok: tokenizer.Token_Kind,
type: ^Expr, type: ^Expr,
} }
Distinct_Type :: struct { Distinct_Type :: struct {
using node: Expr, using node: Expr,
tok: token.Kind, tok: tokenizer.Token_Kind,
type: ^Expr, type: ^Expr,
} }
Opaque_Type :: struct { Opaque_Type :: struct {
using node: Expr, using node: Expr,
tok: token.Kind, tok: tokenizer.Token_Kind,
type: ^Expr, type: ^Expr,
} }
Poly_Type :: struct { Poly_Type :: struct {
using node: Expr, using node: Expr,
dollar: token.Pos, dollar: tokenizer.Pos,
type: ^Ident, type: ^Ident,
specialization: ^Expr, specialization: ^Expr,
} }
Proc_Type :: struct { Proc_Type :: struct {
using node: Expr, using node: Expr,
tok: token.Token, tok: tokenizer.Token,
calling_convention: Proc_Calling_Convention, calling_convention: Proc_Calling_Convention,
params: ^Field_List, params: ^Field_List,
arrow: token.Pos, arrow: tokenizer.Pos,
results: ^Field_List, results: ^Field_List,
tags: Proc_Tags, tags: Proc_Tags,
generic: bool, generic: bool,
@@ -541,77 +546,81 @@ Proc_Type :: struct {
Pointer_Type :: struct { Pointer_Type :: struct {
using node: Expr, using node: Expr,
pointer: token.Pos, pointer: tokenizer.Pos,
elem: ^Expr, elem: ^Expr,
} }
Array_Type :: struct { Array_Type :: struct {
using node: Expr, using node: Expr,
open: token.Pos, open: tokenizer.Pos,
len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types
close: token.Pos, close: tokenizer.Pos,
elem: ^Expr, elem: ^Expr,
} }
Dynamic_Array_Type :: struct { Dynamic_Array_Type :: struct {
using node: Expr, using node: Expr,
open: token.Pos, open: tokenizer.Pos,
dynamic_pos: token.Pos, dynamic_pos: tokenizer.Pos,
close: token.Pos, close: tokenizer.Pos,
elem: ^Expr, elem: ^Expr,
} }
Struct_Type :: struct { Struct_Type :: struct {
using node: Expr, using node: Expr,
tok_pos: token.Pos, tok_pos: tokenizer.Pos,
poly_params: ^Field_List, poly_params: ^Field_List,
align: ^Expr, align: ^Expr,
is_packed: bool,
is_raw_union: bool,
fields: ^Field_List, fields: ^Field_List,
name_count: int, name_count: int,
where_token: tokenizer.Token,
where_clauses: []^Expr,
is_packed: bool,
is_raw_union: bool,
} }
Union_Type :: struct { Union_Type :: struct {
using node: Expr, using node: Expr,
tok_pos: token.Pos, tok_pos: tokenizer.Pos,
poly_params: ^Field_List, poly_params: ^Field_List,
align: ^Expr, align: ^Expr,
variants: []^Expr, variants: []^Expr,
where_token: tokenizer.Token,
where_clauses: []^Expr,
} }
Enum_Type :: struct { Enum_Type :: struct {
using node: Expr, using node: Expr,
tok_pos: token.Pos, tok_pos: tokenizer.Pos,
base_type: ^Expr, base_type: ^Expr,
open: token.Pos, open: tokenizer.Pos,
fields: []^Expr, fields: []^Expr,
close: token.Pos, close: tokenizer.Pos,
is_using: bool, is_using: bool,
} }
Bit_Field_Type :: struct { Bit_Field_Type :: struct {
using node: Expr, using node: Expr,
tok_pos: token.Pos, tok_pos: tokenizer.Pos,
align: ^Expr, align: ^Expr,
open: token.Pos, open: tokenizer.Pos,
fields: []^Field_Value, // Field_Value with ':' rather than '=' fields: []^Field_Value, // Field_Value with ':' rather than '='
close: token.Pos, close: tokenizer.Pos,
} }
Bit_Set_Type :: struct { Bit_Set_Type :: struct {
using node: Expr, using node: Expr,
tok_pos: token.Pos, tok_pos: tokenizer.Pos,
open: token.Pos, open: tokenizer.Pos,
elem: ^Expr, elem: ^Expr,
underlying: ^Expr, underlying: ^Expr,
close: token.Pos, close: tokenizer.Pos,
} }
Map_Type :: struct { Map_Type :: struct {
using node: Expr, using node: Expr,
tok_pos: token.Pos, tok_pos: tokenizer.Pos,
key: ^Expr, key: ^Expr,
value: ^Expr, value: ^Expr,
} }
+2 -2
View File
@@ -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
View File
@@ -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. Load diff
@@ -1,9 +1,9 @@
package odin_token package odin_tokenizer
import "core:strings" import "core:strings"
Token :: struct { Token :: struct {
kind: Kind, kind: Token_Kind,
text: string, text: string,
pos: Pos, pos: Pos,
} }
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
return strings.compare(lhs.file, rhs.file); return strings.compare(lhs.file, rhs.file);
} }
using Kind :: enum u32 { Token_Kind :: enum u32 {
Invalid, Invalid,
EOF, EOF,
Comment, Comment,
@@ -118,6 +118,7 @@ using Kind :: enum u32 {
Package, Package,
Typeid, Typeid,
When, When,
Where,
If, If,
Else, Else,
For, For,
@@ -154,9 +155,6 @@ using Kind :: enum u32 {
Offset_Of, Offset_Of,
Type_Of, Type_Of,
Const, Const,
Asm,
Yield,
Await,
B_Keyword_End, B_Keyword_End,
COUNT, COUNT,
@@ -165,7 +163,7 @@ using Kind :: enum u32 {
// ... Custom keywords // ... Custom keywords
}; };
tokens := [Kind.COUNT]string { tokens := [Token_Kind.COUNT]string {
"Invalid", "Invalid",
"EOF", "EOF",
"Comment", "Comment",
@@ -255,6 +253,7 @@ tokens := [Kind.COUNT]string {
"package", "package",
"typeid", "typeid",
"when", "when",
"where",
"if", "if",
"else", "else",
"for", "for",
@@ -291,20 +290,17 @@ tokens := [Kind.COUNT]string {
"offset_of", "offset_of",
"type_of", "type_of",
"const", "const",
"asm",
"yield",
"await",
"", "",
}; };
custom_keyword_tokens: []string; custom_keyword_tokens: []string;
to_string :: proc(kind: Kind) -> string { to_string :: proc(kind: Token_Kind) -> string {
if Invalid <= kind && kind < COUNT { if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
return tokens[kind]; return tokens[kind];
} }
if B_Custom_Keyword_Begin < kind { if Token_Kind.B_Custom_Keyword_Begin < kind {
n := int(u16(kind)-u16(B_Custom_Keyword_Begin)); n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
if n < len(custom_keyword_tokens) { if n < len(custom_keyword_tokens) {
return custom_keyword_tokens[n]; return custom_keyword_tokens[n];
} }
@@ -313,24 +309,26 @@ to_string :: proc(kind: Kind) -> string {
return "Invalid"; return "Invalid";
} }
is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; } is_literal :: proc(kind: Token_Kind) -> bool {
is_operator :: proc(kind: Kind) -> bool { return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
}
is_operator :: proc(kind: Token_Kind) -> bool {
switch kind { switch kind {
case B_Operator_Begin..B_Operator_End: case .B_Operator_Begin .. .B_Operator_End:
return true; return true;
case In, Notin: case .In, .Notin:
return true; return true;
} }
return false; return false;
} }
is_assignment_operator :: proc(kind: Kind) -> bool { is_assignment_operator :: proc(kind: Token_Kind) -> bool {
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq; return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
} }
is_keyword :: proc(kind: Kind) -> bool { is_keyword :: proc(kind: Token_Kind) -> bool {
switch { switch {
case B_Keyword_Begin < kind && kind < B_Keyword_End: case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
return true; return true;
case B_Custom_Keyword_Begin < kind: case Token_Kind.B_Custom_Keyword_Begin < kind:
return true; return true;
} }
return false; return false;
+79 -79
View File
@@ -1,10 +1,9 @@
package odin_tokenizer package odin_tokenizer
import "core:fmt" import "core:fmt"
import "core:odin/token"
import "core:unicode/utf8" import "core:unicode/utf8"
Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any); Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any);
Tokenizer :: struct { Tokenizer :: struct {
// Immutable data // Immutable data
@@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa
} }
@(private) @(private)
offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos { offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos {
line := t.line_count; line := t.line_count;
column := offset - t.line_offset + 1; column := offset - t.line_offset + 1;
return token.Pos { return Pos {
file = t.path, file = t.path,
offset = offset, offset = offset,
line = line, line = line,
@@ -53,10 +52,10 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos {
}; };
} }
default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) { default_error_handler :: proc(pos: Pos, msg: string, args: ..any) {
fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column); fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column);
fmt.printf_err(msg, ..args); fmt.eprintf(msg, ..args);
fmt.printf_err("\n"); fmt.eprintf("\n");
} }
error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
@@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string {
return string(t.src[offset : t.offset]); return string(t.src[offset : t.offset]);
} }
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) { scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) {
scan_mantissa :: proc(t: ^Tokenizer, base: int) { scan_mantissa :: proc(t: ^Tokenizer, base: int) {
for digit_val(t.ch) < base || t.ch == '_' { for digit_val(t.ch) < base || t.ch == '_' {
advance_rune(t); advance_rune(t);
} }
} }
scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) { scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) {
if t.ch == 'e' || t.ch == 'E' { if t.ch == 'e' || t.ch == 'E' {
kind^ = token.Float; kind^ = .Float;
advance_rune(t); advance_rune(t);
if t.ch == '-' || t.ch == '+' { if t.ch == '-' || t.ch == '+' {
advance_rune(t); advance_rune(t);
@@ -343,17 +342,18 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
} }
// NOTE(bill): This needs to be here for sanity's sake // NOTE(bill): This needs to be here for sanity's sake
if t.ch == 'i' { switch t.ch {
kind^ = token.Imag; case 'i', 'j', 'k':
kind^ = .Imag;
advance_rune(t); advance_rune(t);
} }
} }
scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) { scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) {
if t.ch == '.' && peek_byte(t) == '.' { if t.ch == '.' && peek_byte(t) == '.' {
return true; return true;
} }
if t.ch == '.' { if t.ch == '.' {
kind^ = token.Float; kind^ = .Float;
advance_rune(t); advance_rune(t);
scan_mantissa(t, 10); scan_mantissa(t, 10);
} }
@@ -362,22 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
offset := t.offset; offset := t.offset;
kind := token.Integer; kind := Token_Kind.Integer;
seen_point := seen_decimal_point; seen_point := seen_decimal_point;
if seen_point { if seen_point {
offset -= 1; offset -= 1;
kind = token.Float; kind = .Float;
scan_mantissa(t, 10); scan_mantissa(t, 10);
scan_exponent(t, &kind); scan_exponent(t, &kind);
} else { } else {
if t.ch == '0' { if t.ch == '0' {
int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) { int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) {
prev := t.offset; prev := t.offset;
advance_rune(t); advance_rune(t);
scan_mantissa(t, base); scan_mantissa(t, base);
if t.offset - prev <= 1 { if t.offset - prev <= 1 {
kind^ = token.Invalid; kind^ = .Invalid;
error(t, t.offset, msg); error(t, t.offset, msg);
} }
} }
@@ -394,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
advance_rune(t); advance_rune(t);
scan_mantissa(t, 16); scan_mantissa(t, 16);
if t.offset - prev <= 1 { if t.offset - prev <= 1 {
kind = token.Invalid; kind = .Invalid;
error(t, t.offset, "illegal hexadecimal floating-point number"); error(t, t.offset, "illegal hexadecimal floating-point number");
} else { } else {
sub := t.src[prev+1 : t.offset]; sub := t.src[prev+1 : t.offset];
@@ -439,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str
} }
scan :: proc(t: ^Tokenizer) -> token.Token { scan :: proc(t: ^Tokenizer) -> Token {
switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind { switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind {
if t.ch == '=' { if t.ch == '=' {
advance_rune(t); advance_rune(t);
return tok1; return tok1;
} }
return tok0; return tok0;
} }
switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind { switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind {
if t.ch == '=' { if t.ch == '=' {
advance_rune(t); advance_rune(t);
return tok1; return tok1;
@@ -458,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
} }
return tok0; return tok0;
} }
switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind { switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind {
if t.ch == '=' { if t.ch == '=' {
advance_rune(t); advance_rune(t);
return tok1; return tok1;
@@ -479,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
offset := t.offset; offset := t.offset;
kind: token.Kind; kind: Token_Kind;
lit: string; lit: string;
pos := offset_to_pos(t, offset); pos := offset_to_pos(t, offset);
switch ch := t.ch; true { switch ch := t.ch; true {
case is_letter(ch): case is_letter(ch):
lit = scan_identifier(t); lit = scan_identifier(t);
kind = token.Ident; kind = .Ident;
check_keyword: if len(lit) > 1 { check_keyword: if len(lit) > 1 {
// TODO(bill): Maybe have a hash table lookup rather than this linear search // TODO(bill): Maybe have a hash table lookup rather than this linear search
for i in token.B_Keyword_Begin .. token.B_Keyword_End { for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End {
if lit == token.tokens[i] { if lit == tokens[i] {
kind = token.Kind(i); kind = Token_Kind(i);
break check_keyword; break check_keyword;
} }
} }
for keyword, i in token.custom_keyword_tokens { for keyword, i in custom_keyword_tokens {
if lit == keyword { if lit == keyword {
kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin; kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin;
break check_keyword; break check_keyword;
} }
} }
@@ -508,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
advance_rune(t); advance_rune(t);
switch ch { switch ch {
case -1: case -1:
kind = token.EOF; kind = .EOF;
case '"': case '"':
kind = token.String; kind = .String;
lit = scan_string(t); lit = scan_string(t);
case '\'': case '\'':
kind = token.Rune; kind = .Rune;
lit = scan_rune(t); lit = scan_rune(t);
case '`': case '`':
kind = token.String; kind = .String;
lit = scan_raw_string(t); lit = scan_raw_string(t);
case '=': case '=':
if t.ch == '>' { if t.ch == '>' {
advance_rune(t); advance_rune(t);
kind = token.Double_Arrow_Right; kind = .Double_Arrow_Right;
} else { } else {
kind = switch2(t, token.Eq, token.Cmp_Eq); kind = switch2(t, .Eq, .Cmp_Eq);
} }
case '!': kind = switch2(t, token.Not, token.Not_Eq); case '!': kind = switch2(t, .Not, .Not_Eq);
case '#': case '#':
kind = token.Hash; kind = .Hash;
if t.ch == '!' { if t.ch == '!' {
kind = token.Comment; kind = .Comment;
lit = scan_comment(t); lit = scan_comment(t);
} }
case '?': kind = token.Question; case '?': kind = .Question;
case '@': kind = token.At; case '@': kind = .At;
case '$': kind = token.Dollar; case '$': kind = .Dollar;
case '^': kind = token.Pointer; case '^': kind = .Pointer;
case '+': kind = switch2(t, token.Add, token.Add_Eq); case '+': kind = switch2(t, .Add, .Add_Eq);
case '-': case '-':
if t.ch == '>' { if t.ch == '>' {
advance_rune(t); advance_rune(t);
kind = token.Arrow_Right; kind = .Arrow_Right;
} else if t.ch == '-' && peek_byte(t) == '-' { } else if t.ch == '-' && peek_byte(t) == '-' {
advance_rune(t); advance_rune(t);
advance_rune(t); advance_rune(t);
kind = token.Undef; kind = .Undef;
} else { } else {
kind = switch2(t, token.Sub, token.Sub_Eq); kind = switch2(t, .Sub, .Sub_Eq);
} }
case '*': kind = switch2(t, token.Mul, token.Mul_Eq); case '*': kind = switch2(t, .Mul, .Mul_Eq);
case '/': case '/':
if t.ch == '/' || t.ch == '*' { if t.ch == '/' || t.ch == '*' {
kind = token.Comment; kind = .Comment;
lit = scan_comment(t); lit = scan_comment(t);
} else { } else {
kind = switch2(t, token.Quo, token.Quo_Eq); kind = switch2(t, .Quo, .Quo_Eq);
} }
case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq); case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq);
case '&': case '&':
if t.ch == '~' { if t.ch == '~' {
advance_rune(t); advance_rune(t);
kind = switch2(t, token.And_Not, token.And_Not_Eq); kind = switch2(t, .And_Not, .And_Not_Eq);
} else { } else {
kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And); kind = switch3(t, .And, .And_Eq, '&', .Cmp_And);
} }
case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or); case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or);
case '~': kind = token.Xor; case '~': kind = .Xor;
case '<': case '<':
if t.ch == '-' { if t.ch == '-' {
advance_rune(t); advance_rune(t);
kind = token.Arrow_Left; kind = .Arrow_Left;
} else { } else {
kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq); kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq);
} }
case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq); case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq);
case '≠': kind = token.Not_Eq; case '≠': kind = .Not_Eq;
case '≤': kind = token.Lt_Eq; case '≤': kind = .Lt_Eq;
case '≥': kind = token.Gt_Eq; case '≥': kind = .Gt_Eq;
case '∈': kind = token.In; case '∈': kind = .In;
case '∉': kind = token.Notin; case '∉': kind = .Notin;
case '.': case '.':
if '0' <= t.ch && t.ch <= '9' { if '0' <= t.ch && t.ch <= '9' {
kind, lit = scan_number(t, true); kind, lit = scan_number(t, true);
} else { } else {
kind = token.Period; kind = .Period;
if t.ch == '.' { if t.ch == '.' {
advance_rune(t); advance_rune(t);
kind = token.Ellipsis; kind = .Ellipsis;
if t.ch == '<' { if t.ch == '<' {
advance_rune(t); advance_rune(t);
kind = token.Range_Half; kind = .Range_Half;
} }
} }
} }
case ':': kind = token.Colon; case ':': kind = .Colon;
case ',': kind = token.Comma; case ',': kind = .Comma;
case ';': kind = token.Semicolon; case ';': kind = .Semicolon;
case '(': kind = token.Open_Paren; case '(': kind = .Open_Paren;
case ')': kind = token.Close_Paren; case ')': kind = .Close_Paren;
case '[': kind = token.Open_Bracket; case '[': kind = .Open_Bracket;
case ']': kind = token.Close_Bracket; case ']': kind = .Close_Bracket;
case '{': kind = token.Open_Brace; case '{': kind = .Open_Brace;
case '}': kind = token.Close_Brace; case '}': kind = .Close_Brace;
case '\\': kind = token.Back_Slash; case '\\': kind = .Back_Slash;
case: case:
if ch != utf8.RUNE_BOM { if ch != utf8.RUNE_BOM {
error(t, t.offset, "illegal character '%r': %d", ch, ch); error(t, t.offset, "illegal character '%r': %d", ch, ch);
} }
kind = token.Invalid; kind = .Invalid;
} }
} }
if lit == "" { if lit == "" {
lit = string(t.src[offset : t.offset]); lit = string(t.src[offset : t.offset]);
} }
return token.Token{kind, lit, pos}; return Token{kind, lit, pos};
} }
@@ -6,7 +6,7 @@ foreign import libc "system:c"
import "core:runtime" import "core:runtime"
import "core:strings" import "core:strings"
OS :: "osx"; OS :: "darwin";
Handle :: distinct i32; Handle :: distinct i32;
File_Time :: distinct u64; File_Time :: distinct u64;
@@ -319,9 +319,9 @@ dlerror :: proc() -> string {
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc() -> []string {
args := make([]string, len(runtime.args__)); res := make([]string, len(runtime.args__));
for arg, i in runtime.args__ { for arg, i in runtime.args__ {
args[i] = string(arg); res[i] = string(arg);
} }
return args; return res;
} }
+2420 -160
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -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;
} }
+396
View File
@@ -0,0 +1,396 @@
package reflect
import "core:runtime"
import "core:mem"
Type_Kind :: enum {
Invalid,
Named,
Integer,
Rune,
Float,
Complex,
Quaternion,
String,
Boolean,
Any,
Type_Id,
Pointer,
Procedure,
Array,
Dynamic_Array,
Slice,
Tuple,
Struct,
Union,
Enum,
Map,
Bit_Field,
Bit_Set,
Opaque,
Simd_Vector,
}
type_kind :: proc(T: typeid) -> Type_Kind {
ti := type_info_of(T);
if ti != nil {
#complete switch _ in ti.variant {
case runtime.Type_Info_Named: return .Named;
case runtime.Type_Info_Integer: return .Integer;
case runtime.Type_Info_Rune: return .Rune;
case runtime.Type_Info_Float: return .Float;
case runtime.Type_Info_Complex: return .Complex;
case runtime.Type_Info_Quaternion: return .Quaternion;
case runtime.Type_Info_String: return .String;
case runtime.Type_Info_Boolean: return .Boolean;
case runtime.Type_Info_Any: return .Any;
case runtime.Type_Info_Type_Id: return .Type_Id;
case runtime.Type_Info_Pointer: return .Pointer;
case runtime.Type_Info_Procedure: return .Procedure;
case runtime.Type_Info_Array: return .Array;
case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
case runtime.Type_Info_Slice: return .Slice;
case runtime.Type_Info_Tuple: return .Tuple;
case runtime.Type_Info_Struct: return .Struct;
case runtime.Type_Info_Union: return .Union;
case runtime.Type_Info_Enum: return .Enum;
case runtime.Type_Info_Map: return .Map;
case runtime.Type_Info_Bit_Field: return .Bit_Field;
case runtime.Type_Info_Bit_Set: return .Bit_Set;
case runtime.Type_Info_Opaque: return .Opaque;
case runtime.Type_Info_Simd_Vector: return .Simd_Vector;
}
}
return .Invalid;
}
// TODO(bill): Better name
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
return type_kind(runtime.typeid_base(T));
}
// TODO(bill): Better name
backing_type_kind :: proc(T: typeid) -> Type_Kind {
return type_kind(runtime.typeid_core(T));
}
size_of_typeid :: proc(T: typeid) -> int {
if ti := type_info_of(T); ti != nil {
return ti.size;
}
return 0;
}
align_of_typeid :: proc(T: typeid) -> int {
if ti := type_info_of(T); ti != nil {
return ti.align;
}
return 1;
}
to_bytes :: proc(v: any) -> []byte {
if v != nil {
sz := size_of_typeid(v.id);
return mem.slice_ptr((^byte)(v.data), sz);
}
return nil;
}
any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
return v.data, v.id;
}
is_nil :: proc(v: any) -> bool {
data := to_bytes(v);
if data != nil {
return true;
}
for v in data do if v != 0 {
return false;
}
return true;
}
length :: proc(val: any) -> int {
if val == nil do return 0;
v := val;
v.id = runtime.typeid_base(v.id);
switch a in v {
case runtime.Type_Info_Array:
return a.count;
case runtime.Type_Info_Slice:
return (^mem.Raw_Slice)(v.data).len;
case runtime.Type_Info_Dynamic_Array:
return (^mem.Raw_Dynamic_Array)(v.data).len;
case runtime.Type_Info_String:
if a.is_cstring {
return len((^cstring)(v.data)^);
} else {
return (^mem.Raw_String)(v.data).len;
}
}
return 0;
}
index :: proc(val: any, i: int, loc := #caller_location) -> any {
if val == nil do return nil;
v := val;
v.id = runtime.typeid_base(v.id);
switch a in v {
case runtime.Type_Info_Array:
runtime.bounds_check_error_loc(loc, i, a.count);
offset := uintptr(a.elem.size * i);
data := rawptr(uintptr(v.data) + offset);
return any{data, a.elem.id};
case runtime.Type_Info_Slice:
raw := (^mem.Raw_Slice)(v.data);
runtime.bounds_check_error_loc(loc, i, raw.len);
offset := uintptr(a.elem.size * i);
data := rawptr(uintptr(raw.data) + offset);
return any{data, a.elem.id};
case runtime.Type_Info_Dynamic_Array:
raw := (^mem.Raw_Dynamic_Array)(v.data);
runtime.bounds_check_error_loc(loc, i, raw.len);
offset := uintptr(a.elem.size * i);
data := rawptr(uintptr(raw.data) + offset);
return any{data, a.elem.id};
case runtime.Type_Info_String:
if a.is_cstring do return nil;
raw := (^mem.Raw_String)(v.data);
runtime.bounds_check_error_loc(loc, i, raw.len);
offset := uintptr(size_of(u8) * i);
data := rawptr(uintptr(raw.data) + offset);
return any{data, typeid_of(u8)};
}
return nil;
}
Struct_Tag :: distinct string;
Struct_Field :: struct {
name: string,
type: typeid,
tag: Struct_Tag,
offset: uintptr,
}
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
if 0 <= i && i < len(s.names) {
field.name = s.names[i];
field.type = s.types[i].id;
field.tag = Struct_Tag(s.tags[i]);
field.offset = s.offsets[i];
}
}
return;
}
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
for fname, i in s.names {
if fname == name {
field.name = s.names[i];
field.type = s.types[i].id;
field.tag = Struct_Tag(s.tags[i]);
field.offset = s.offsets[i];
break;
}
}
}
return;
}
struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
if a == nil do return nil;
ti := runtime.type_info_base(type_info_of(a.id));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
for name, i in s.names {
if name == field {
return any{
rawptr(uintptr(a.data) + s.offsets[i]),
s.types[i].id,
};
}
if recurse && s.usings[i] {
f := any{
rawptr(uintptr(a.data) + s.offsets[i]),
s.types[i].id,
};
if res := struct_field_value_by_name(f, field, recurse); res != nil {
return res;
}
}
}
}
return nil;
}
struct_field_names :: proc(T: typeid) -> []string {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.names;
}
return nil;
}
struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.types;
}
return nil;
}
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return transmute([]Struct_Tag)s.tags;
}
return nil;
}
struct_field_offsets :: proc(T: typeid) -> []uintptr {
ti := runtime.type_info_base(type_info_of(T));
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
return s.offsets;
}
return nil;
}
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
value, _ = struct_tag_lookup(tag, key);
return;
}
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
for t := tag; t != ""; /**/ {
i := 0;
for i < len(t) && t[i] == ' ' { // Skip whitespace
i += 1;
}
t = t[i:];
if len(t) == 0 do break;
i = 0;
loop: for i < len(t) {
switch t[i] {
case ':', '"':
break loop;
case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
break loop;
}
i += 1;
}
if i == 0 do break;
if i+1 >= len(t) do break;
if t[i] != ':' || t[i+1] != '"' {
break;
}
name := string(t[:i]);
t = t[i+1:];
i = 1;
for i < len(t) && t[i] != '"' { // find closing quote
if t[i] == '\\' do i += 1; // Skip escaped characters
i += 1;
}
if i >= len(t) do break;
val := string(t[:i+1]);
t = t[i+1:];
if key == name {
return val[1:i], true;
}
}
return;
}
enum_string :: proc(a: any) -> string {
if a == nil do return "";
ti := runtime.type_info_base(type_info_of(a.id));
if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
for _, i in e.values {
value := &e.values[i];
n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
if n == 0 {
return e.names[i];
}
}
} else {
panic("expected an enum to reflect.enum_string");
}
return "";
}
union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
id := union_variant_typeid(a);
return type_info_of(id);
}
union_variant_typeid :: proc(a: any) -> typeid {
if a == nil do return nil;
ti := runtime.type_info_base(type_info_of(a.id));
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
tag_ptr := uintptr(a.data) + info.tag_offset;
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
tag: i64 = ---;
switch i in tag_any {
case u8: tag = i64(i);
case i8: tag = i64(i);
case u16: tag = i64(i);
case i16: tag = i64(i);
case u32: tag = i64(i);
case i32: tag = i64(i);
case u64: tag = i64(i);
case i64: tag = i64(i);
case: unimplemented();
}
if a.data != nil && tag != 0 {
return info.variants[tag-1].id;
}
} else {
panic("expected a union to reflect.union_variant_typeid");
}
return nil;
}
@@ -1,6 +1,7 @@
package types package reflect
import rt "core:runtime" import rt "core:runtime"
import "core:strings"
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool { are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
if a == b do return true; if a == b do return true;
@@ -108,9 +109,11 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
for _, i in x.types { for _, i in x.types {
xn, yn := x.names[i], y.names[i]; xn, yn := x.names[i], y.names[i];
xt, yt := x.types[i], y.types[i]; xt, yt := x.types[i], y.types[i];
xl, yl := x.tags[i], y.tags[i];
if xn != yn do return false; if xn != yn do return false;
if !are_types_identical(xt, yt) do return false; if !are_types_identical(xt, yt) do return false;
if xl != yl do return false;
} }
return true; return true;
@@ -272,3 +275,216 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector); _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
return ok; return ok;
} }
write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
write_type(buf, type_info_of(id));
}
write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
using strings;
if ti == nil {
write_string(buf, "nil");
return;
}
switch info in ti.variant {
case rt.Type_Info_Named:
write_string(buf, info.name);
case rt.Type_Info_Integer:
switch ti.id {
case int: write_string(buf, "int");
case uint: write_string(buf, "uint");
case uintptr: write_string(buf, "uintptr");
case:
write_byte(buf, info.signed ? 'i' : 'u');
write_i64(buf, i64(8*ti.size), 10);
switch info.endianness {
case .Little: write_string(buf, "le");
case .Big: write_string(buf, "be");
}
}
case rt.Type_Info_Rune:
write_string(buf, "rune");
case rt.Type_Info_Float:
write_byte(buf, 'f');
write_i64(buf, i64(8*ti.size), 10);
case rt.Type_Info_Complex:
write_string(buf, "complex");
write_i64(buf, i64(8*ti.size), 10);
case rt.Type_Info_String:
if info.is_cstring {
write_string(buf, "cstring");
} else {
write_string(buf, "string");
}
case rt.Type_Info_Boolean:
switch ti.id {
case bool: write_string(buf, "bool");
case:
write_byte(buf, 'b');
write_i64(buf, i64(8*ti.size), 10);
}
case rt.Type_Info_Any:
write_string(buf, "any");
case rt.Type_Info_Type_Id:
write_string(buf, "typeid");
case rt.Type_Info_Pointer:
if info.elem == nil {
write_string(buf, "rawptr");
} else {
write_string(buf, "^");
write_type(buf, info.elem);
}
case rt.Type_Info_Procedure:
write_string(buf, "proc");
if info.params == nil {
write_string(buf, "()");
} else {
t := info.params.variant.(rt.Type_Info_Tuple);
write_string(buf, "(");
for t, i in t.types {
if i > 0 do write_string(buf, ", ");
write_type(buf, t);
}
write_string(buf, ")");
}
if info.results != nil {
write_string(buf, " -> ");
write_type(buf, info.results);
}
case rt.Type_Info_Tuple:
count := len(info.names);
if count != 1 do write_string(buf, "(");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
t := info.types[i];
if len(name) > 0 {
write_string(buf, name);
write_string(buf, ": ");
}
write_type(buf, t);
}
if count != 1 do write_string(buf, ")");
case rt.Type_Info_Array:
write_string(buf, "[");
write_i64(buf, i64(info.count), 10);
write_string(buf, "]");
write_type(buf, info.elem);
case rt.Type_Info_Dynamic_Array:
write_string(buf, "[dynamic]");
write_type(buf, info.elem);
case rt.Type_Info_Slice:
write_string(buf, "[]");
write_type(buf, info.elem);
case rt.Type_Info_Map:
write_string(buf, "map[");
write_type(buf, info.key);
write_byte(buf, ']');
write_type(buf, info.value);
case rt.Type_Info_Struct:
write_string(buf, "struct ");
if info.is_packed do write_string(buf, "#packed ");
if info.is_raw_union do write_string(buf, "#raw_union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_type(buf, info.types[i]);
}
write_byte(buf, '}');
case rt.Type_Info_Union:
write_string(buf, "union ");
if info.custom_align {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_byte(buf, '{');
for variant, i in info.variants {
if i > 0 do write_string(buf, ", ");
write_type(buf, variant);
}
write_byte(buf, '}');
case rt.Type_Info_Enum:
write_string(buf, "enum ");
write_type(buf, info.base);
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
}
write_byte(buf, '}');
case rt.Type_Info_Bit_Field:
write_string(buf, "bit_field ");
if ti.align != 1 {
write_string(buf, "#align ");
write_i64(buf, i64(ti.align), 10);
write_byte(buf, ' ');
}
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
write_string(buf, name);
write_string(buf, ": ");
write_i64(buf, i64(info.bits[i]), 10);
}
write_byte(buf, '}');
case rt.Type_Info_Bit_Set:
write_string(buf, "bit_set[");
switch {
case is_enum(info.elem):
write_type(buf, info.elem);
case is_rune(info.elem):
write_encoded_rune(buf, rune(info.lower));
write_string(buf, "..");
write_encoded_rune(buf, rune(info.upper));
case:
write_i64(buf, info.lower, 10);
write_string(buf, "..");
write_i64(buf, info.upper, 10);
}
if info.underlying != nil {
write_string(buf, "; ");
write_type(buf, info.underlying);
}
write_byte(buf, ']');
case rt.Type_Info_Opaque:
write_string(buf, "opaque ");
write_type(buf, info.elem);
case rt.Type_Info_Simd_Vector:
if info.is_x86_mmx {
write_string(buf, "intrinsics.x86_mmx");
} else {
write_string(buf, "intrinsics.vector(");
write_i64(buf, i64(info.count));
write_string(buf, ", ");
write_type(buf, info.elem);
write_byte(buf, ')');
}
}
}
+83 -60
View File
@@ -6,6 +6,7 @@ package runtime
import "core:os" import "core:os"
import "core:mem" import "core:mem"
import "core:log" import "core:log"
import "intrinsics"
// Naming Conventions: // Naming Conventions:
// In general, Ada_Case for types and snake_case for values // In general, Ada_Case for types and snake_case for values
@@ -40,7 +41,7 @@ Type_Info_Enum_Value :: union {
u8, u16, u32, u64, uint, uintptr, u8, u16, u32, u64, uint, uintptr,
}; };
Type_Info_Endianness :: enum u8 { Platform_Endianness :: enum u8 {
Platform = 0, Platform = 0,
Little = 1, Little = 1,
Big = 2, Big = 2,
@@ -48,10 +49,11 @@ Type_Info_Endianness :: enum u8 {
// Variant Types // Variant Types
Type_Info_Named :: struct {name: string, base: ^Type_Info}; Type_Info_Named :: struct {name: string, base: ^Type_Info};
Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness};
Type_Info_Rune :: struct {}; Type_Info_Rune :: struct {};
Type_Info_Float :: struct {}; Type_Info_Float :: struct {};
Type_Info_Complex :: struct {}; Type_Info_Complex :: struct {};
Type_Info_Quaternion :: struct {};
Type_Info_String :: struct {is_cstring: bool}; Type_Info_String :: struct {is_cstring: bool};
Type_Info_Boolean :: struct {}; Type_Info_Boolean :: struct {};
Type_Info_Any :: struct {}; Type_Info_Any :: struct {};
@@ -79,8 +81,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
Type_Info_Struct :: struct { Type_Info_Struct :: struct {
types: []^Type_Info, types: []^Type_Info,
names: []string, names: []string,
offsets: []uintptr, // offsets may not be used in tuples offsets: []uintptr,
usings: []bool, // usings may not be used in tuples usings: []bool,
tags: []string,
is_packed: bool, is_packed: bool,
is_raw_union: bool, is_raw_union: bool,
custom_align: bool, custom_align: bool,
@@ -134,6 +137,7 @@ Type_Info :: struct {
Type_Info_Rune, Type_Info_Rune,
Type_Info_Float, Type_Info_Float,
Type_Info_Complex, Type_Info_Complex,
Type_Info_Quaternion,
Type_Info_String, Type_Info_String,
Type_Info_Boolean, Type_Info_Boolean,
Type_Info_Any, Type_Info_Any,
@@ -162,6 +166,7 @@ Typeid_Kind :: enum u8 {
Rune, Rune,
Float, Float,
Complex, Complex,
Quaternion,
String, String,
Boolean, Boolean,
Any, Any,
@@ -183,12 +188,13 @@ Typeid_Kind :: enum u8 {
#assert(len(Typeid_Kind) < 32); #assert(len(Typeid_Kind) < 32);
Typeid_Bit_Field :: bit_field #align align_of(uintptr) { Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
index: 8*size_of(align_of(uintptr)) - 8, index: 8*size_of(uintptr) - 8,
kind: 5, // Typeid_Kind kind: 5, // Typeid_Kind
named: 1, named: 1,
special: 1, // signed, cstring, etc special: 1, // signed, cstring, etc
reserved: 1, reserved: 1,
} }
#assert(size_of(Typeid_Bit_Field) == size_of(uintptr));
// NOTE(bill): only the ones that are needed (not all types) // NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler // This will be set by the compiler
@@ -231,7 +237,22 @@ global_scratch_allocator_data: mem.Scratch_Allocator;
Raw_Slice :: struct {
data: rawptr,
len: int,
}
Raw_Dynamic_Array :: struct {
data: rawptr,
len: int,
cap: int,
allocator: mem.Allocator,
}
Raw_Map :: struct {
hashes: []int,
entries: Raw_Dynamic_Array,
}
INITIAL_MAP_CAP :: 16; INITIAL_MAP_CAP :: 16;
@@ -255,7 +276,7 @@ Map_Entry_Header :: struct {
} }
Map_Header :: struct { Map_Header :: struct {
m: ^mem.Raw_Map, m: ^Raw_Map,
is_key_string: bool, is_key_string: bool,
entry_size: int, entry_size: int,
@@ -282,7 +303,7 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
} }
type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
if info == nil do return nil; if info == nil do return nil;
base := info; base := info;
@@ -290,11 +311,13 @@ type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_In
switch i in base.variant { switch i in base.variant {
case Type_Info_Named: base = i.base; case Type_Info_Named: base = i.base;
case Type_Info_Enum: base = i.base; case Type_Info_Enum: base = i.base;
case Type_Info_Opaque: base = i.elem;
case: break loop; case: break loop;
} }
} }
return base; return base;
} }
type_info_base_without_enum :: type_info_core;
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info { __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
data := transmute(Typeid_Bit_Field)id; data := transmute(Typeid_Bit_Field)id;
@@ -310,10 +333,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid {
ti = type_info_base(ti); ti = type_info_base(ti);
return ti.id; return ti.id;
} }
typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid { typeid_core :: proc "contextless" (id: typeid) -> typeid {
ti := type_info_base_without_enum(type_info_of(id)); ti := type_info_base_without_enum(type_info_of(id));
return ti.id; return ti.id;
} }
typeid_base_without_enum :: typeid_core;
@@ -385,7 +409,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code
@builtin @builtin
copy :: proc "contextless" (dst, src: $T/[]$E) -> int { copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
n := max(0, min(len(dst), len(src))); n := max(0, min(len(dst), len(src)));
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E)); if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E));
return n; return n;
} }
@@ -396,7 +420,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
if array == nil do return E{}; if array == nil do return E{};
assert(len(array) > 0); assert(len(array) > 0);
res := array[len(array)-1]; res := array[len(array)-1];
(^mem.Raw_Dynamic_Array)(array).len -= 1; (^Raw_Dynamic_Array)(array).len -= 1;
return res; return res;
} }
@@ -460,14 +484,11 @@ make :: proc{
mem.make_map, mem.make_map,
}; };
@builtin @builtin
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) { clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
if m == nil do return; if m == nil do return;
raw_map := (^mem.Raw_Map)(m); raw_map := (^Raw_Map)(m);
entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries); entries := (^Raw_Dynamic_Array)(&raw_map.entries);
entries.len = 0; entries.len = 0;
for _, i in raw_map.hashes { for _, i in raw_map.hashes {
raw_map.hashes[i] = -1; raw_map.hashes[i] = -1;
@@ -498,11 +519,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
} }
arg_len = min(cap(array)-len(array), arg_len); arg_len = min(cap(array)-len(array), arg_len);
if arg_len > 0 { if arg_len > 0 {
a := (^mem.Raw_Dynamic_Array)(array); a := (^Raw_Dynamic_Array)(array);
data := (^E)(a.data); data := (^E)(a.data);
assert(data != nil); assert(data != nil);
val := arg; val := arg;
mem.copy(mem.ptr_offset(data, a.len), &val, size_of(E)); mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E));
a.len += arg_len; a.len += arg_len;
} }
} }
@@ -520,10 +541,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
} }
arg_len = min(cap(array)-len(array), arg_len); arg_len = min(cap(array)-len(array), arg_len);
if arg_len > 0 { if arg_len > 0 {
a := (^mem.Raw_Dynamic_Array)(array); a := (^Raw_Dynamic_Array)(array);
data := (^E)(a.data); data := (^E)(a.data);
assert(data != nil); assert(data != nil);
mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
a.len += arg_len; a.len += arg_len;
} }
} }
@@ -540,13 +561,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@builtin @builtin
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) { clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0; if array != nil do (^Raw_Dynamic_Array)(array).len = 0;
} }
@builtin @builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool { reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
if array == nil do return false; if array == nil do return false;
a := (^mem.Raw_Dynamic_Array)(array); a := (^Raw_Dynamic_Array)(array);
if capacity <= a.cap do return true; if capacity <= a.cap do return true;
@@ -573,7 +594,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
@builtin @builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool { resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool {
if array == nil do return false; if array == nil do return false;
a := (^mem.Raw_Dynamic_Array)(array); a := (^Raw_Dynamic_Array)(array);
if length <= a.cap { if length <= a.cap {
a.len = max(length, 0); a.len = max(length, 0);
@@ -666,11 +687,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int {
@builtin @builtin
assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool { assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool {
if !condition { if !condition {
proc(message: string, loc: Source_Code_Location) {
p := context.assertion_failure_proc; p := context.assertion_failure_proc;
if p == nil { if p == nil {
p = default_assertion_failure_proc; p = default_assertion_failure_proc;
} }
p("Runtime assertion", message, loc); p("runtime assertion", message, loc);
}(message, loc);
} }
return condition; return condition;
} }
@@ -681,7 +704,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! {
if p == nil { if p == nil {
p = default_assertion_failure_proc; p = default_assertion_failure_proc;
} }
p("Panic", message, loc); p("panic", message, loc);
} }
@builtin @builtin
@@ -711,7 +734,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! {
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) { __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
array := (^mem.Raw_Dynamic_Array)(array_); array := (^Raw_Dynamic_Array)(array_);
array.allocator = context.allocator; array.allocator = context.allocator;
assert(array.allocator.procedure != nil); assert(array.allocator.procedure != nil);
@@ -722,7 +745,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca
} }
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool { __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
array := (^mem.Raw_Dynamic_Array)(array_); array := (^Raw_Dynamic_Array)(array_);
if cap <= array.cap do return true; if cap <= array.cap do return true;
@@ -744,7 +767,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
} }
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool { __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
array := (^mem.Raw_Dynamic_Array)(array_); array := (^Raw_Dynamic_Array)(array_);
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc); ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
if ok do array.len = len; if ok do array.len = len;
@@ -754,7 +777,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len:
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
items: rawptr, item_count: int, loc := #caller_location) -> int { items: rawptr, item_count: int, loc := #caller_location) -> int {
array := (^mem.Raw_Dynamic_Array)(array_); array := (^Raw_Dynamic_Array)(array_);
if items == nil do return 0; if items == nil do return 0;
if item_count <= 0 do return 0; if item_count <= 0 do return 0;
@@ -771,13 +794,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
assert(array.data != nil); assert(array.data != nil);
data := uintptr(array.data) + uintptr(elem_size*array.len); data := uintptr(array.data) + uintptr(elem_size*array.len);
mem.copy(rawptr(data), items, elem_size * item_count); mem_copy(rawptr(data), items, elem_size * item_count);
array.len += item_count; array.len += item_count;
return array.len; return array.len;
} }
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int { __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
array := (^mem.Raw_Dynamic_Array)(array_); array := (^Raw_Dynamic_Array)(array_);
ok := true; ok := true;
if array.cap <= array.len+1 { if array.cap <= array.len+1 {
@@ -800,15 +823,14 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
// Map // Map
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
header := Map_Header{m = (^mem.Raw_Map)(m)}; header := Map_Header{m = (^Raw_Map)(m)};
Entry :: struct { Entry :: struct {
key: Map_Key, key: Map_Key,
next: int, next: int,
value: V, value: V,
} };
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String); header.is_key_string = intrinsics.type_is_string(K);
header.is_key_string = is_string;
header.entry_size = int(size_of(Entry)); header.entry_size = int(size_of(Entry));
header.entry_align = int(align_of(Entry)); header.entry_align = int(align_of(Entry));
header.value_offset = uintptr(offset_of(Entry, value)); header.value_offset = uintptr(offset_of(Entry, value));
@@ -819,33 +841,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
__get_map_key :: proc "contextless" (k: $K) -> Map_Key { __get_map_key :: proc "contextless" (k: $K) -> Map_Key {
key := k; key := k;
map_key: Map_Key; map_key: Map_Key;
ti := type_info_base_without_enum(type_info_of(K));
switch _ in ti.variant { T :: intrinsics.type_core_type(K);
case Type_Info_Integer:
switch 8*size_of(key) { when intrinsics.type_is_integer(T) {
case 8: map_key.hash = u64(( ^u8)(&key)^); sz :: 8*size_of(T);
case 16: map_key.hash = u64(( ^u16)(&key)^); when sz == 8 do map_key.hash = u64(( ^u8)(&key)^);
case 32: map_key.hash = u64(( ^u32)(&key)^); else when sz == 16 do map_key.hash = u64((^u16)(&key)^);
case 64: map_key.hash = u64(( ^u64)(&key)^); else when sz == 32 do map_key.hash = u64((^u32)(&key)^);
case: panic("Unhandled integer size"); else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
} else do #assert(false, "Unhandled integer size");
case Type_Info_Rune: } else when intrinsics.type_is_rune(T) {
map_key.hash = u64((^rune)(&key)^); map_key.hash = u64((^rune)(&key)^);
case Type_Info_Pointer: } else when intrinsics.type_is_pointer(T) {
map_key.hash = u64(uintptr((^rawptr)(&key)^)); map_key.hash = u64(uintptr((^rawptr)(&key)^));
case Type_Info_Float: } else when intrinsics.type_is_float(T) {
switch 8*size_of(key) { sz :: 8*size_of(T);
case 32: map_key.hash = u64((^u32)(&key)^); when sz == 32 do map_key.hash = u64((^u32)(&key)^);
case 64: map_key.hash = u64((^u64)(&key)^); else when sz == 64 do map_key.hash = u64((^u64)(&key)^);
case: panic("Unhandled float size"); else do #assert(false, "Unhandled float size");
} } else when intrinsics.type_is_string(T) {
case Type_Info_String: #assert(T == string);
str := (^string)(&key)^; str := (^string)(&key)^;
map_key.hash = default_hash_string(str); map_key.hash = default_hash_string(str);
map_key.str = str; map_key.str = str;
case: } else {
panic("Unhandled map key type"); #assert(false, "Unhandled map key type");
} }
return map_key; return map_key;
} }
@@ -874,7 +897,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool { __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
array := (^mem.Raw_Slice)(array_); array := (^Raw_Slice)(array_);
if new_count < array.len do return true; if new_count < array.len do return true;
@@ -900,7 +923,7 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller
} }
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check { __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
new_header: Map_Header = header; new_header: Map_Header = header;
nm := mem.Raw_Map{}; nm := Raw_Map{};
nm.entries.allocator = m.entries.allocator; nm.entries.allocator = m.entries.allocator;
new_header.m = &nm; new_header.m = &nm;
@@ -932,7 +955,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c
e := __dynamic_map_get_entry(new_header, j); e := __dynamic_map_get_entry(new_header, j);
e.next = fr.entry_index; e.next = fr.entry_index;
ndata := uintptr(e); ndata := uintptr(e);
mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size); mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc); if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
} }
@@ -975,7 +998,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca
e := __dynamic_map_get_entry(h, index); e := __dynamic_map_get_entry(h, index);
e.key = key; e.key = key;
val := (^byte)(uintptr(e) + h.value_offset); val := (^byte)(uintptr(e) + h.value_offset);
mem.copy(val, value, h.value_size); mem_copy(val, value, h.value_size);
} }
if __dynamic_map_full(h) { if __dynamic_map_full(h) {
@@ -1054,7 +1077,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds
} else { } else {
old := __dynamic_map_get_entry(h, fr.entry_index); old := __dynamic_map_get_entry(h, fr.entry_index);
end := __dynamic_map_get_entry(h, m.entries.len-1); end := __dynamic_map_get_entry(h, m.entries.len-1);
mem.copy(old, end, entry_size); mem_copy(old, end, entry_size);
if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 { if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 {
last_entry := __dynamic_map_get_entry(h, last.entry_prev); last_entry := __dynamic_map_get_entry(h, last.entry_prev);
+242 -12
View File
@@ -1,9 +1,22 @@
package runtime package runtime
import "core:mem"
import "core:os" import "core:os"
import "core:unicode/utf8"
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil do return dst;
// NOTE(bill): This _must_ be implemented like C's memmove
foreign _ {
when size_of(rawptr) == 8 {
@(link_name="llvm.memmove.p0i8.p0i8.i64")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
} else {
@(link_name="llvm.memmove.p0i8.p0i8.i32")
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
}
}
llvm_memmove(dst, src, len, 1, false);
return dst;
}
print_u64 :: proc(fd: os.Handle, x: u64) { print_u64 :: proc(fd: os.Handle, x: u64) {
digits := "0123456789"; digits := "0123456789";
@@ -243,6 +256,78 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
} }
} }
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
x := uintptr(a);
y := uintptr(b);
n := uintptr(n);
SU :: size_of(uintptr);
fast := uintptr(n/SU + 1);
offset := (fast-1)*SU;
curr_block := uintptr(0);
if n < SU {
fast = 0;
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
vb := (^uintptr)(y + curr_block * size_of(uintptr))^;
if va ~ vb != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^;
b := (^byte)(y+pos)^;
if a ~ b != 0 {
return (int(a) - int(b)) < 0 ? -1 : +1;
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^;
b := (^byte)(y+offset)^;
if a ~ b != 0 {
return (int(a) - int(b)) < 0 ? -1 : +1;
}
}
return 0;
}
memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
x := uintptr(a);
n := uintptr(n);
SU :: size_of(uintptr);
fast := uintptr(n/SU + 1);
offset := (fast-1)*SU;
curr_block := uintptr(0);
if n < SU {
fast = 0;
}
for /**/; curr_block < fast; curr_block += 1 {
va := (^uintptr)(x + curr_block * size_of(uintptr))^;
if va ~ 0 != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
a := (^byte)(x+pos)^;
if a ~ 0 != 0 {
return int(a) < 0 ? -1 : +1;
}
}
}
}
for /**/; offset < n; offset += 1 {
a := (^byte)(x+offset)^;
if a ~ 0 != 0 {
return int(a) < 0 ? -1 : +1;
}
}
return 0;
}
string_eq :: proc "contextless" (a, b: string) -> bool { string_eq :: proc "contextless" (a, b: string) -> bool {
switch { switch {
case len(a) != len(b): return false; case len(a) != len(b): return false;
@@ -253,7 +338,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool {
} }
string_cmp :: proc "contextless" (a, b: string) -> int { string_cmp :: proc "contextless" (a, b: string) -> int {
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b))); return memory_compare(&a[0], &b[0], min(len(a), len(b)));
} }
string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); } string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); }
@@ -263,18 +348,23 @@ string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cm
string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; } string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; }
cstring_len :: proc "contextless" (s: cstring) -> int { cstring_len :: proc "contextless" (s: cstring) -> int {
n := 0; p0 := uintptr((^byte)(s));
for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) { p := p0;
n += 1; for p != 0 && (^byte)(p)^ != 0 {
p += 1;
} }
return n; return int(p - p0);
} }
cstring_to_string :: proc "contextless" (s: cstring) -> string { cstring_to_string :: proc "contextless" (s: cstring) -> string {
Raw_String :: struct {
data: ^byte,
len: int,
};
if s == nil do return ""; if s == nil do return "";
ptr := (^byte)(s); ptr := (^byte)(s);
n := cstring_len(s); n := cstring_len(s);
return transmute(string)mem.Raw_String{ptr, n}; return transmute(string)Raw_String{ptr, n};
} }
@@ -285,6 +375,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r
complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); } complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); }
quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); }
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) { bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
@@ -358,8 +453,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column
handle_error(file, line, column, from, to); handle_error(file, line, column, from, to);
} }
string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) { string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
return utf8.decode_rune_in_string(s); // NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
@static accept_sizes := [256]u8{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
};
Accept_Range :: struct {lo, hi: u8};
@static accept_ranges := [5]Accept_Range{
{0x80, 0xbf},
{0xa0, 0xbf},
{0x80, 0x9f},
{0x90, 0xbf},
{0x80, 0x8f},
};
MASKX :: 0b0011_1111;
MASK2 :: 0b0001_1111;
MASK3 :: 0b0000_1111;
MASK4 :: 0b0000_0111;
LOCB :: 0b1000_0000;
HICB :: 0b1011_1111;
RUNE_ERROR :: '\ufffd';
n := len(s);
if n < 1 {
return RUNE_ERROR, 0;
}
s0 := s[0];
x := accept_sizes[s0];
if x >= 0xF0 {
mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff.
return rune(s[0])&~mask | RUNE_ERROR&mask, 1;
}
sz := x & 7;
accept := accept_ranges[x>>4];
if n < int(sz) {
return RUNE_ERROR, 1;
}
b1 := s[1];
if b1 < accept.lo || accept.hi < b1 {
return RUNE_ERROR, 1;
}
if sz == 2 {
return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2;
}
b2 := s[2];
if b2 < LOCB || HICB < b2 {
return RUNE_ERROR, 1;
}
if sz == 3 {
return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3;
}
b3 := s[3];
if b3 < LOCB || HICB < b3 {
return RUNE_ERROR, 1;
}
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
} }
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) { bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
@@ -474,9 +645,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
r, i := real(x), imag(x); r, i := real(x), imag(x);
return _sqrt_f64(r*r + i*i); return _sqrt_f64(r*r + i*i);
} }
abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f32(r*r + i*i + j*j + k*k);
}
abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 {
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
return _sqrt_f64(r*r + i*i + j*j + k*k);
}
quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 {
quo_complex64 :: proc(n, m: complex64) -> complex64 {
e, f: f32; e, f: f32;
if abs(real(m)) >= abs(imag(m)) { if abs(real(m)) >= abs(imag(m)) {
@@ -494,7 +672,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 {
return complex(e, f); return complex(e, f);
} }
quo_complex128 :: proc(n, m: complex128) -> complex128 { quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 {
e, f: f64; e, f: f64;
if abs(real(m)) >= abs(imag(m)) { if abs(real(m)) >= abs(imag(m)) {
@@ -511,3 +689,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
return complex(e, f); return complex(e, f);
} }
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
return quaternion(t0, t1, t2, t3);
}
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3;
t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2;
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1;
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0;
return quaternion(t0, t1, t2, t3);
}
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
return quaternion(t0, t1, t2, t3);
}
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q);
r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r);
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3);
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2;
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2;
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2;
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2;
return quaternion(t0, t1, t2, t3);
}
+4 -3
View File
@@ -1,6 +1,7 @@
package sort package sort
import "core:mem" import "core:mem"
import "intrinsics"
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil); assert(f != nil);
@@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
} }
} }
bubble_sort :: proc(array: $A/[]$T) { bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
count := len(array); count := len(array);
init_j, last_j := 0, count-1; init_j, last_j := 0, count-1;
@@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
quick_sort_proc(a[i:n], f); quick_sort_proc(a[i:n], f);
} }
quick_sort :: proc(array: $A/[]$T) { quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
a := array; a := array;
n := len(a); n := len(a);
if n < 2 do return; if n < 2 do return;
@@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
if M & 1 == 0 do copy(arr2, arr1); if M & 1 == 0 do copy(arr2, arr1);
} }
merge_sort :: proc(array: $A/[]$T) { merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
merge_slices :: proc(arr1, arr2, out: A) { merge_slices :: proc(arr1, arr2, out: A) {
N1, N2 := len(arr1), len(arr2); N1, N2 := len(arr1), len(arr2);
i, j := 0, 0; i, j := 0, 0;
@@ -1,6 +1,6 @@
// Multiple precision decimal numbers // Multiple precision decimal numbers
// NOTE: This is only for floating point printing and nothing else // NOTE: This is only for floating point printing and nothing else
package decimal package strconv_decimal
Decimal :: struct { Decimal :: struct {
digits: [384]byte, // big-endian digits digits: [384]byte, // big-endian digits
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
return string(b); return string(b);
} }
@private
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
s, n := s_, n_;
if n == 0 {
return nil;
}
if sep == "" {
l := utf8.rune_count_in_string(s);
if n < 0 || n > l {
n = l;
}
res := make([dynamic]string, n, allocator);
for i := 0; i < n-1; i += 1 {
_, w := utf8.decode_rune_in_string(s);
res[i] = s[:w];
s = s[w:];
}
if n > 0 {
res[n-1] = s;
}
return res[:];
}
if n < 0 {
n = count(s, sep) + 1;
}
res := make([dynamic]string, n, allocator);
n -= 1;
i := 0;
for ; i < n; i += 1 {
m := index(s, sep);
if m < 0 {
break;
}
res[i] = s[:m+sep_save];
s = s[m+len(sep):];
}
res[i] = s;
return res[:i+1];
}
split :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
return _split(s, sep, 0, -1, allocator);
}
split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
return _split(s, sep, 0, n, allocator);
}
split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string {
return _split(s, sep, len(sep), -1, allocator);
}
split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string {
return _split(s, sep, len(sep), n, allocator);
}
index_byte :: proc(s: string, c: byte) -> int { index_byte :: proc(s: string, c: byte) -> int {
for i := 0; i < len(s); i += 1 { for i := 0; i < len(s); i += 1 {
if s[i] == c do return i; if s[i] == c do return i;
@@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int {
return -1; return -1;
} }
@private PRIME_RABIN_KARP :: 16777619;
index :: proc(s, substr: string) -> int { index :: proc(s, substr: string) -> int {
hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := 0; i < len(s); i += 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
}
sq := u32(PRIME_RABIN_KARP);
for i := len(s); i > 0; i >>= 1 {
if (i & 1) != 0 {
pow *= sq;
}
sq *= sq;
}
return;
}
n := len(substr); n := len(substr);
switch { switch {
case n == 0: case n == 0:
@@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int {
return -1; return -1;
} }
for i := 0; i < len(s)-n+1; i += 1 { hash, pow := hash_str_rabin_karp(substr);
x := s[i:i+n]; h: u32;
if x == substr { for i := 0; i < n; i += 1 {
h = h*PRIME_RABIN_KARP + u32(s[i]);
}
if h == hash && s[:n] == substr {
return 0;
}
for i := n; i < len(s); /**/ {
h *= PRIME_RABIN_KARP;
h += u32(s[i]);
h -= pow * u32(s[i-n]);
i += 1;
if h == hash && s[i-n:i] == substr {
return i - n;
}
}
return -1;
}
last_index :: proc(s, substr: string) -> int {
hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := len(s) - 1; i >= 0; i -= 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i]);
}
sq := u32(PRIME_RABIN_KARP);
for i := len(s); i > 0; i >>= 1 {
if (i & 1) != 0 {
pow *= sq;
}
sq *= sq;
}
return;
}
n := len(substr);
switch {
case n == 0:
return len(s);
case n == 1:
return last_index_byte(s, substr[0]);
case n == len(s):
return substr == s ? 0 : -1;
case n > len(s):
return -1;
}
hash, pow := hash_str_rabin_karp_reverse(substr);
last := len(s) - n;
h: u32;
for i := len(s)-1; i >= last; i -= 1 {
h = h*PRIME_RABIN_KARP + u32(s[i]);
}
if h == hash && s[last:] == substr {
return last;
}
for i := last-1; i >= 0; i -= 1 {
h *= PRIME_RABIN_KARP;
h += u32(s[i]);
h -= pow * u32(s[i+n]);
if h == hash && s[i:i+n] == substr {
return i; return i;
} }
} }
-24
View File
@@ -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
View File
@@ -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
View File
@@ -182,7 +182,7 @@ foreign user32 {
@(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---; @(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---; @(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
@(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---; @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---;
@(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---; @(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---;
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---; @(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
File renamed without changes.
+2
View File
@@ -0,0 +1,2 @@
package time
IS_SUPPORTED :: false;
+1 -1
View File
@@ -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
View File
@@ -41,23 +41,17 @@ accept_ranges := [5]Accept_Range{
}; };
accept_sizes := [256]u8{ accept_sizes := [256]u8{
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f 0x00..0x7f = 0xf0,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f 0x80..0xc1 = 0xf1,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f 0xc2..0xdf = 0x02,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f 0xe0 = 0x13,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f 0xe1..0xec = 0x03,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f 0xed = 0x23,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f 0xee..0xef = 0x03,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f 0xf0 = 0x34,
0xf1..0xf3 = 0x04,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f 0xf4 = 0x44,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f 0xf5..0xff = 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf
0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf
0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef
0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff
}; };
encode_rune :: proc(c: rune) -> ([4]u8, int) { encode_rune :: proc(c: rune) -> ([4]u8, int) {
@@ -167,9 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
return r, size; return r, size;
} }
rune_at_pos :: proc(s: string, pos: int) -> rune {
if pos < 0 {
return RUNE_ERROR;
}
i := 0;
for r in s {
if i == pos {
return r;
}
i += 1;
}
return RUNE_ERROR;
}
rune_string_at_pos :: proc(s: string, pos: int) -> string {
if pos < 0 {
return "";
}
i := 0;
for c, offset in s {
if i == pos {
w := rune_size(c);
return s[offset:][:w];
}
i += 1;
}
return "";
}
rune_at :: proc(s: string, byte_index: int) -> rune {
r, _ := decode_rune_in_string(s[byte_index:]);
return r;
}
// Returns the byte position of rune at position pos in s with an optional start byte position.
// Returns -1 if it runs out of the string.
rune_offset :: proc(s: string, pos: int, start: int = 0) -> int {
if pos < 0 {
return -1;
}
i := 0;
for _, offset in s[start:] {
if i == pos {
return offset+start;
}
i += 1;
}
return -1;
}
valid_rune :: proc(r: rune) -> bool { valid_rune :: proc(r: rune) -> bool {
if r < 0 { if r < 0 {
+334 -40
View File
@@ -3,14 +3,34 @@ package main
import "core:fmt" import "core:fmt"
import "core:mem" import "core:mem"
import "core:os" import "core:os"
import "core:reflect"
import "intrinsics"
when os.OS == "windows" { when os.OS == "windows" {
import "core:thread" import "core:thread"
} }
@(link_name="general_stuff") /*
general_stuff :: proc() { The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals:
fmt.println("# general_stuff"); * simplicity
* high performance
* built for modern systems
* joy of programming
# Installing Odin
Getting Started - https://odin-lang.org/docs/install/
Instructions for downloading and install the Odin compiler and libraries.
# Learning Odin
Overview of Odin - https://odin-lang.org/docs/overview/
An overview of the Odin programming language.
Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/
Answers to common questions about Odin.
*/
@(link_name="extra_general_stuff")
extra_general_stuff :: proc() {
fmt.println("# extra_general_stuff");
{ // `do` for inline statements rather than block { // `do` for inline statements rather than block
foo :: proc() do fmt.println("Foo!"); foo :: proc() do fmt.println("Foo!");
if false do foo(); if false do foo();
@@ -30,14 +50,12 @@ general_stuff :: proc() {
i := i32(137); i := i32(137);
ptr := &i; ptr := &i;
_ = (^f32)(ptr); _ = (^f32)(ptr); // Call-based syntax
// ^f32(ptr) == ^(f32(ptr)) // ^f32(ptr) == ^(f32(ptr))
_ = cast(^f32)ptr; _ = cast(^f32)ptr; // Operator-based syntax
_ = (^f32)(ptr)^; _ = (^f32)(ptr)^;
_ = (cast(^f32)ptr)^; _ = (cast(^f32)ptr)^;
// Questions: Should there be two ways to do it?
} }
/* /*
@@ -50,7 +68,7 @@ general_stuff :: proc() {
Foo :: struct { Foo :: struct {
x: int, x: int,
b: bool, b: bool,
} };
f := Foo{137, true}; f := Foo{137, true};
x, b := expand_to_tuple(f); x, b := expand_to_tuple(f);
fmt.println(f); fmt.println(f);
@@ -191,8 +209,8 @@ union_type :: proc() {
} }
} }
Vector3 :: struct {x, y, z: f32}; Vector3 :: distinct [3]f32;
Quaternion :: struct {x, y, z, w: f32}; Quaternion :: distinct quaternion128;
// More realistic examples // More realistic examples
{ {
@@ -209,18 +227,18 @@ union_type :: proc() {
orientation: Quaternion, orientation: Quaternion,
derived: any, derived: any,
} };
Frog :: struct { Frog :: struct {
using entity: Entity, using entity: Entity,
jump_height: f32, jump_height: f32,
} };
Monster :: struct { Monster :: struct {
using entity: Entity, using entity: Entity,
is_robot: bool, is_robot: bool,
is_zombie: bool, is_zombie: bool,
} };
// See `parametric_polymorphism` procedure for details // See `parametric_polymorphism` procedure for details
new_entity :: proc($T: typeid) -> ^Entity { new_entity :: proc($T: typeid) -> ^Entity {
@@ -254,18 +272,18 @@ union_type :: proc() {
orientation: Quaternion, orientation: Quaternion,
derived: union {Frog, Monster}, derived: union {Frog, Monster},
} };
Frog :: struct { Frog :: struct {
using entity: ^Entity, using entity: ^Entity,
jump_height: f32, jump_height: f32,
} };
Monster :: struct { Monster :: struct {
using entity: ^Entity, using entity: ^Entity,
is_robot: bool, is_robot: bool,
is_zombie: bool, is_zombie: bool,
} };
// See `parametric_polymorphism` procedure for details // See `parametric_polymorphism` procedure for details
new_entity :: proc($T: typeid) -> ^Entity { new_entity :: proc($T: typeid) -> ^Entity {
@@ -302,17 +320,17 @@ union_type :: proc() {
/* /*
Entity :: struct { Entity :: struct {
.. ...
derived: union{^Frog, ^Monster}, derived: union{^Frog, ^Monster},
} }
Frog :: struct { Frog :: struct {
using entity: Entity, using entity: Entity,
.. ...
} }
Monster :: struct { Monster :: struct {
using entity: Entity, using entity: Entity,
.. ...
} }
new_entity :: proc(T: type) -> ^Entity { new_entity :: proc(T: type) -> ^Entity {
@@ -325,7 +343,7 @@ union_type :: proc() {
} }
parametric_polymorphism :: proc() { parametric_polymorphism :: proc() {
fmt.println("# parametric_polymorphism"); fmt.println("\n# parametric_polymorphism");
print_value :: proc(value: $T) { print_value :: proc(value: $T) {
fmt.printf("print_value: %T %v\n", value, value); fmt.printf("print_value: %T %v\n", value, value);
@@ -383,13 +401,13 @@ parametric_polymorphism :: proc() {
hash: u32, hash: u32,
key: Key, key: Key,
value: Value, value: Value,
} };
TABLE_SIZE_MIN :: 32; TABLE_SIZE_MIN :: 32;
Table :: struct(Key, Value: typeid) { Table :: struct(Key, Value: typeid) {
count: int, count: int,
allocator: mem.Allocator, allocator: mem.Allocator,
slots: []Table_Slot(Key, Value), slots: []Table_Slot(Key, Value),
} };
// Only allow types that are specializations of a (polymorphic) slice // Only allow types that are specializations of a (polymorphic) slice
make_slice :: proc($T: typeid/[]$E, len: int) -> T { make_slice :: proc($T: typeid/[]$E, len: int) -> T {
@@ -513,7 +531,7 @@ parametric_polymorphism :: proc() {
Foo1, Foo1,
Foo2, Foo2,
Foo3, Foo3,
} };
Para_Union :: union(T: typeid) {T, Error}; Para_Union :: union(T: typeid) {T, Error};
r: Para_Union(int); r: Para_Union(int);
fmt.println(typeid_of(type_of(r))); fmt.println(typeid_of(type_of(r)));
@@ -521,7 +539,7 @@ parametric_polymorphism :: proc() {
fmt.println(r); fmt.println(r);
r = 123; r = 123;
fmt.println(r); fmt.println(r);
r = Error.Foo0; r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below
fmt.println(r); fmt.println(r);
} }
@@ -543,6 +561,30 @@ parametric_polymorphism :: proc() {
for v, i in array { for v, i in array {
assert(v == T(i*i)); assert(v == T(i*i));
} }
// Matrix multiplication
mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) {
for i in 0..<M {
for j in 0..<P {
for k in 0..<N {
c[i][j] += a[i][k] * b[k][j];
}
}
}
return;
}
x := [2][3]f32{
{1, 2, 3},
{3, 2, 1},
};
y := [3][2]f32{
{0, 8},
{6, 2},
{8, 4},
};
z := mul(x, y);
assert(z == {{36, 24}, {20, 32}});
} }
} }
@@ -560,7 +602,7 @@ prefix_table := [?]string{
threading_example :: proc() { threading_example :: proc() {
when os.OS == "windows" { when os.OS == "windows" {
fmt.println("# threading_example"); fmt.println("\n# threading_example");
worker_proc :: proc(t: ^thread.Thread) -> int { worker_proc :: proc(t: ^thread.Thread) -> int {
for iteration in 1..5 { for iteration in 1..5 {
@@ -600,7 +642,7 @@ threading_example :: proc() {
} }
array_programming :: proc() { array_programming :: proc() {
fmt.println("# array_programming"); fmt.println("\n# array_programming");
{ {
a := [3]f32{1, 2, 3}; a := [3]f32{1, 2, 3};
b := [3]f32{5, 6, 7}; b := [3]f32{5, 6, 7};
@@ -645,7 +687,7 @@ array_programming :: proc() {
} }
named_proc_return_parameters :: proc() { named_proc_return_parameters :: proc() {
fmt.println("# named proc return parameters"); fmt.println("\n# named proc return parameters");
foo0 :: proc() -> int { foo0 :: proc() -> int {
return 123; return 123;
@@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() {
using_enum :: proc() { using_enum :: proc() {
fmt.println("# using enum"); fmt.println("\n# using enum");
using Foo :: enum {A, B, C}; using Foo :: enum {A, B, C};
@@ -679,25 +721,25 @@ using_enum :: proc() {
} }
map_type :: proc() { map_type :: proc() {
fmt.println("# map type"); fmt.println("\n# map type");
// enums of type u16, u32, i16 & i32 also work // enums of type u16, u32, i16 & i32 also work
Enum_u8 :: enum u8 { Enum_u8 :: enum u8 {
A = 0, A = 0,
B = 1 << 8 - 1, B = 1 << 8 - 1,
} };
Enum_u64 :: enum u64 { Enum_u64 :: enum u64 {
A = 0, A = 0,
B = 1 << 64 - 1, B = 1 << 64 - 1,
} };
Enum_i8 :: enum i8 { Enum_i8 :: enum i8 {
A = 0, A = 0,
B = -(1 << 7), B = -(1 << 7),
} };
Enum_i64 :: enum i64 { Enum_i64 :: enum i64 {
A = 0, A = 0,
B = -(1 << 63), B = -(1 << 63),
} };
map_u8: map[Enum_u8]u8; map_u8: map[Enum_u8]u8;
map_u8[Enum_u8.A] = u8(Enum_u8.B); map_u8[Enum_u8.A] = u8(Enum_u8.B);
@@ -721,7 +763,7 @@ map_type :: proc() {
demo_struct :: struct { demo_struct :: struct {
member: Enum_i64, member: Enum_i64,
} };
map_string: map[string]demo_struct; map_string: map[string]demo_struct;
map_string["Hellope!"] = demo_struct{Enum_i64.B}; map_string["Hellope!"] = demo_struct{Enum_i64.B};
@@ -734,7 +776,7 @@ map_type :: proc() {
} }
implicit_selector_expression :: proc() { implicit_selector_expression :: proc() {
fmt.println("# implicit selector expression"); fmt.println("\n# implicit selector expression");
Foo :: enum {A, B, C}; Foo :: enum {A, B, C};
@@ -762,7 +804,7 @@ implicit_selector_expression :: proc() {
} }
explicit_procedure_overloading :: proc() { explicit_procedure_overloading :: proc() {
fmt.println("# explicit procedure overloading"); fmt.println("\n# explicit procedure overloading");
add_ints :: proc(a, b: int) -> int { add_ints :: proc(a, b: int) -> int {
x := a + b; x := a + b;
@@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() {
} }
complete_switch :: proc() { complete_switch :: proc() {
fmt.println("# complete_switch"); fmt.println("\n# complete_switch");
{ // enum { // enum
using Foo :: enum { using Foo :: enum {
A, A,
B, B,
C, C,
D, D,
} };
b := Foo.B; b := Foo.B;
f := Foo.A; f := Foo.A;
@@ -829,6 +871,8 @@ complete_switch :: proc() {
} }
cstring_example :: proc() { cstring_example :: proc() {
fmt.println("\n# cstring_example");
W :: "Hellope"; W :: "Hellope";
X :: cstring(W); X :: cstring(W);
Y :: string(X); Y :: string(X);
@@ -860,6 +904,8 @@ deprecated_attribute :: proc() {
} }
bit_set_type :: proc() { bit_set_type :: proc() {
fmt.println("\n# bit_set_type");
{ {
using Day :: enum { using Day :: enum {
Sunday, Sunday,
@@ -869,7 +915,7 @@ bit_set_type :: proc() {
Thursday, Thursday,
Friday, Friday,
Saturday, Saturday,
} };
Days :: distinct bit_set[Day]; Days :: distinct bit_set[Day];
WEEKEND :: Days{Sunday, Saturday}; WEEKEND :: Days{Sunday, Saturday};
@@ -921,6 +967,8 @@ bit_set_type :: proc() {
} }
diverging_procedures :: proc() { diverging_procedures :: proc() {
fmt.println("\n# diverging_procedures");
// Diverging procedures may never return // Diverging procedures may never return
foo :: proc() -> ! { foo :: proc() -> ! {
fmt.println("I'm a diverging procedure"); fmt.println("I'm a diverging procedure");
@@ -930,6 +978,8 @@ diverging_procedures :: proc() {
} }
deferred_procedure_associations :: proc() { deferred_procedure_associations :: proc() {
fmt.println("\n# deferred_procedure_associations");
@(deferred_out=closure) @(deferred_out=closure)
open :: proc(s: string) -> bool { open :: proc(s: string) -> bool {
fmt.println(s); fmt.println(s);
@@ -945,9 +995,247 @@ deferred_procedure_associations :: proc() {
} }
} }
reflection :: proc() {
fmt.println("\n# reflection");
Foo :: struct {
x: int `tag1`,
y: string `json:"y_field"`,
z: bool, // no tag
};
id := typeid_of(Foo);
names := reflect.struct_field_names(id);
types := reflect.struct_field_types(id);
tags := reflect.struct_field_tags(id);
assert(len(names) == len(types) && len(names) == len(tags));
fmt.println("Foo :: struct {");
for tag, i in tags {
name, type := names[i], types[i];
if tag != "" {
fmt.printf("\t%s: %T `%s`,\n", name, type, tag);
} else {
fmt.printf("\t%s: %T,\n", name, type);
}
}
fmt.println("}");
for tag, i in tags {
if val, ok := reflect.struct_tag_lookup(tag, "json"); ok {
fmt.printf("json: %s -> %s\n", names[i], val);
}
}
}
quaternions :: proc() {
fmt.println("\n# quaternions");
{ // Quaternion operations
q := 1 + 2i + 3j + 4k;
r := quaternion(5, 6, 7, 8);
t := q * r;
fmt.printf("(%v) * (%v) = %v\n", q, r, t);
v := q / r;
fmt.printf("(%v) / (%v) = %v\n", q, r, v);
u := q + r;
fmt.printf("(%v) + (%v) = %v\n", q, r, u);
s := q - r;
fmt.printf("(%v) - (%v) = %v\n", q, r, s);
}
{ // The quaternion types
q128: quaternion128; // 4xf32
q256: quaternion256; // 4xf64
q128 = quaternion(1, 0, 0, 0);
q256 = 1; // quaternion(1, 0, 0, 0);
}
{ // Built-in procedures
q := 1 + 2i + 3j + 4k;
fmt.println("q =", q);
fmt.println("real(q) =", real(q));
fmt.println("imag(q) =", imag(q));
fmt.println("jmag(q) =", jmag(q));
fmt.println("kmag(q) =", kmag(q));
fmt.println("conj(q) =", conj(q));
fmt.println("abs(q) =", abs(q));
}
{ // Conversion of a complex type to a quaternion type
c := 1 + 2i;
q := quaternion256(c);
fmt.println(c);
fmt.println(q);
}
{ // Memory layout of Quaternions
q := 1 + 2i + 3j + 4k;
a := transmute([4]f64)q;
fmt.println("Quaternion memory layout: xyzw/(ijkr)");
fmt.println(q); // 1.000+2.000i+3.000j+4.000k
fmt.println(a); // [2.000, 3.000, 4.000, 1.000]
}
}
inline_for_statement :: proc() {
fmt.println("\n#inline for statements");
// 'inline for' works the same as if the 'inline' prefix did not
// exist but these ranged loops are explicitly unrolled which can
// be very very useful for certain optimizations
fmt.println("Ranges");
inline for x, i in 1..<4 {
fmt.println(x, i);
}
fmt.println("Strings");
inline for r, i in "Hello, 世界" {
fmt.println(r, i);
}
fmt.println("Arrays");
inline for elem, idx in ([4]int{1, 4, 9, 16}) {
fmt.println(elem, idx);
}
Foo_Enum :: enum {
A = 1,
B,
C = 6,
D,
};
fmt.println("Enum types");
inline for elem, idx in Foo_Enum {
fmt.println(elem, idx);
}
}
where_clauses :: proc() {
fmt.println("\n#procedure 'where' clauses");
{ // Sanity checks
simple_sanity_check :: proc(x: [2]int)
where len(x) > 1,
type_of(x) == [2]int {
fmt.println(x);
}
}
{ // Parametric polymorphism checks
cross_2d :: proc(a, b: $T/[2]$E) -> E
where intrinsics.type_is_numeric(E) {
return a.x*b.y - a.y*b.x;
}
cross_3d :: proc(a, b: $T/[3]$E) -> T
where intrinsics.type_is_numeric(E) {
x := a.y*b.z - a.z*b.y;
y := a.z*b.x - a.x*b.z;
z := a.x*b.y - a.y*b.z;
return T{x, y, z};
}
a := [2]int{1, 2};
b := [2]int{5, -3};
fmt.println(cross_2d(a, b));
x := [3]f32{1, 4, 9};
y := [3]f32{-5, 0, 3};
fmt.println(cross_3d(x, y));
// Failure case
// i := [2]bool{true, false};
// j := [2]bool{false, true};
// fmt.println(cross_2d(i, j));
}
{ // Procedure groups usage
foo :: proc(x: [$N]int) -> bool
where N > 2 {
fmt.println(#procedure, "was called with the parameter", x);
return true;
}
bar :: proc(x: [$N]int) -> bool
where 0 < N,
N <= 2 {
fmt.println(#procedure, "was called with the parameter", x);
return false;
}
baz :: proc{foo, bar};
x := [3]int{1, 2, 3};
y := [2]int{4, 9};
ok_x := baz(x);
ok_y := baz(y);
assert(ok_x == true);
assert(ok_y == false);
}
{ // Record types
Foo :: struct(T: typeid, N: int)
where intrinsics.type_is_integer(T),
N > 2 {
x: [N]T,
y: [N-2]T,
};
T :: i32;
N :: 5;
f: Foo(T, N);
#assert(size_of(f) == (N+N-2)*size_of(T));
}
}
ranged_fields_for_array_compound_literals :: proc() {
fmt.println("\n#ranged fields for array compound literals");
{ // Normal Array Literal
foo := [?]int{1, 4, 9, 16};
fmt.println(foo);
}
{ // Indexed
foo := [?]int{
3 = 16,
1 = 4,
2 = 9,
0 = 1,
};
fmt.println(foo);
}
{ // Ranges
i := 2;
foo := [?]int {
0 = 123,
5..9 = 54,
10..<16 = i*3 + (i-1)*2,
};
#assert(len(foo) == 16);
fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
}
{ // Slice and Dynamic Array support
i := 2;
foo_slice := []int {
0 = 123,
5..9 = 54,
10..<16 = i*3 + (i-1)*2,
};
assert(len(foo_slice) == 16);
fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
foo_dynamic_array := [dynamic]int {
0 = 123,
5..9 = 54,
10..<16 = i*3 + (i-1)*2,
};
assert(len(foo_dynamic_array) == 16);
fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8]
}
}
main :: proc() { main :: proc() {
when true { when true {
general_stuff(); extra_general_stuff();
union_type(); union_type();
parametric_polymorphism(); parametric_polymorphism();
threading_example(); threading_example();
@@ -963,5 +1251,11 @@ main :: proc() {
bit_set_type(); bit_set_type();
diverging_procedures(); diverging_procedures();
deferred_procedure_associations(); deferred_procedure_associations();
reflection();
quaternions();
inline_for_statement();
where_clauses();
ranged_fields_for_array_compound_literals();
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 75 KiB

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2 -2
View File
@@ -1,8 +1,8 @@
@echo off @echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1 set _NO_DEBUG_HEAP=1
+42 -14
View File
@@ -2,7 +2,7 @@ enum TargetOsKind {
TargetOs_Invalid, TargetOs_Invalid,
TargetOs_windows, TargetOs_windows,
TargetOs_osx, TargetOs_darwin,
TargetOs_linux, TargetOs_linux,
TargetOs_essence, TargetOs_essence,
@@ -30,7 +30,7 @@ enum TargetEndianKind {
String target_os_names[TargetOs_COUNT] = { String target_os_names[TargetOs_COUNT] = {
str_lit(""), str_lit(""),
str_lit("windows"), str_lit("windows"),
str_lit("osx"), str_lit("darwin"),
str_lit("linux"), str_lit("linux"),
str_lit("essence"), str_lit("essence"),
}; };
@@ -55,9 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
String const ODIN_VERSION = str_lit("0.10.1"); String const ODIN_VERSION = str_lit("0.10.2");
String cross_compile_target = str_lit("");
String cross_compile_lib_dir = str_lit("");
@@ -66,6 +64,7 @@ struct TargetMetrics {
TargetArchKind arch; TargetArchKind arch;
isize word_size; isize word_size;
isize max_align; isize max_align;
String target_triplet;
}; };
@@ -109,6 +108,7 @@ struct BuildContext {
bool has_resource; bool has_resource;
String opt_flags; String opt_flags;
String llc_flags; String llc_flags;
String target_triplet;
String link_flags; String link_flags;
bool is_dll; bool is_dll;
bool generate_docs; bool generate_docs;
@@ -121,6 +121,7 @@ struct BuildContext {
bool no_crt; bool no_crt;
bool use_lld; bool use_lld;
bool vet; bool vet;
bool cross_compiling;
QueryDataSetSettings query_data_set_settings; QueryDataSetSettings query_data_set_settings;
@@ -135,18 +136,19 @@ struct BuildContext {
gb_global BuildContext build_context = {0}; gb_global BuildContext build_context = {0};
gb_global TargetMetrics target_windows_386 = { gb_global TargetMetrics target_windows_386 = {
TargetOs_windows, TargetOs_windows,
TargetArch_386, TargetArch_386,
4, 4,
8, 8,
str_lit("i686-pc-windows"),
}; };
gb_global TargetMetrics target_windows_amd64 = { gb_global TargetMetrics target_windows_amd64 = {
TargetOs_windows, TargetOs_windows,
TargetArch_amd64, TargetArch_amd64,
8, 8,
16, 16,
str_lit("x86_64-pc-windows-gnu"),
}; };
gb_global TargetMetrics target_linux_386 = { gb_global TargetMetrics target_linux_386 = {
@@ -154,23 +156,47 @@ gb_global TargetMetrics target_linux_386 = {
TargetArch_386, TargetArch_386,
4, 4,
8, 8,
str_lit("i686-pc-linux-gnu"),
}; };
gb_global TargetMetrics target_linux_amd64 = { gb_global TargetMetrics target_linux_amd64 = {
TargetOs_linux, TargetOs_linux,
TargetArch_amd64, TargetArch_amd64,
8, 8,
16, 16,
str_lit("x86_64-pc-linux-gnu"),
}; };
gb_global TargetMetrics target_osx_amd64 = { gb_global TargetMetrics target_darwin_amd64 = {
TargetOs_osx, TargetOs_darwin,
TargetArch_amd64, TargetArch_amd64,
8, 8,
16, 16,
str_lit("x86_64-apple-darwin"),
}; };
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
8,
16,
str_lit("x86_64-pc-none-elf"),
};
struct NamedTargetMetrics {
String name;
TargetMetrics *metrics;
};
gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("essence_amd64"), &target_essence_amd64 },
{ str_lit("darwin_amd64"), &target_darwin_amd64 },
{ str_lit("linux_386"), &target_linux_386 },
{ str_lit("linux_amd64"), &target_linux_amd64 },
{ str_lit("windows_386"), &target_windows_386 },
{ str_lit("windows_amd64"), &target_windows_amd64 },
};
NamedTargetMetrics *selected_target_metrics;
TargetOsKind get_target_os_from_string(String str) { TargetOsKind get_target_os_from_string(String str) {
for (isize i = 0; i < TargetOs_COUNT; i++) { for (isize i = 0; i < TargetOs_COUNT; i++) {
@@ -522,7 +548,7 @@ String get_fullpath_core(gbAllocator a, String path) {
void init_build_context(void) { void init_build_context(TargetMetrics *cross_target) {
BuildContext *bc = &build_context; BuildContext *bc = &build_context;
gb_affinity_init(&bc->affinity); gb_affinity_init(&bc->affinity);
@@ -540,7 +566,7 @@ void init_build_context(void) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
metrics = target_windows_amd64; metrics = target_windows_amd64;
#elif defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_OSX)
metrics = target_osx_amd64; metrics = target_darwin_amd64;
#else #else
metrics = target_linux_amd64; metrics = target_linux_amd64;
#endif #endif
@@ -554,8 +580,9 @@ void init_build_context(void) {
#endif #endif
#endif #endif
if (cross_compile_target.len) { if (cross_target) {
bc->ODIN_OS = cross_compile_target; metrics = *cross_target;
bc->cross_compiling = true;
} }
GB_ASSERT(metrics.os != TargetOs_Invalid); GB_ASSERT(metrics.os != TargetOs_Invalid);
@@ -573,6 +600,7 @@ void init_build_context(void) {
bc->max_align = metrics.max_align; bc->max_align = metrics.max_align;
bc->link_flags = str_lit(" "); bc->link_flags = str_lit(" ");
bc->opt_flags = str_lit(" "); bc->opt_flags = str_lit(" ");
bc->target_triplet = metrics.target_triplet;
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64); gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
@@ -590,7 +618,7 @@ void init_build_context(void) {
case TargetOs_windows: case TargetOs_windows:
bc->link_flags = str_lit("/machine:x64 "); bc->link_flags = str_lit("/machine:x64 ");
break; break;
case TargetOs_osx: case TargetOs_darwin:
break; break;
case TargetOs_linux: case TargetOs_linux:
bc->link_flags = str_lit("-arch x86-64 "); bc->link_flags = str_lit("-arch x86-64 ");
@@ -603,7 +631,7 @@ void init_build_context(void) {
case TargetOs_windows: case TargetOs_windows:
bc->link_flags = str_lit("/machine:x86 "); bc->link_flags = str_lit("/machine:x86 ");
break; break;
case TargetOs_osx: case TargetOs_darwin:
gb_printf_err("Unsupported architecture\n"); gb_printf_err("Unsupported architecture\n");
gb_exit(1); gb_exit(1);
break; break;
+115 -36
View File
@@ -41,12 +41,21 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
} }
if (operand->mode == Addressing_Type) { if (operand->mode == Addressing_Type) {
if (e->type != nullptr && is_type_typeid(e->type)) {
add_type_info_type(ctx, operand->type);
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
return e->type;
} else {
gbString t = type_to_string(operand->type); gbString t = type_to_string(operand->type);
defer (gb_string_free(t));
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
gb_string_free(t); if (e->type == nullptr) {
error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string));
}
e->type = operand->type; e->type = operand->type;
return nullptr; return nullptr;
} }
}
@@ -112,7 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
isize rhs_count = operands.count; isize rhs_count = operands.count;
for_array(i, operands) { for_array(i, operands) {
if (operands[i].mode == Addressing_Invalid) { if (operands[i].mode == Addressing_Invalid) {
rhs_count--; // TODO(bill): Should I ignore invalid parameters?
// rhs_count--;
} }
} }
@@ -239,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) {
} }
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) { void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
GB_ASSERT(e->type == nullptr); GB_ASSERT(e->type == nullptr);
DeclInfo *decl = decl_info_of_entity(e); DeclInfo *decl = decl_info_of_entity(e);
@@ -247,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr); check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr);
} }
bool is_distinct = is_type_distinct(init_expr);
bool is_distinct = is_type_distinct(type_expr); Ast *te = remove_type_alias_clutter(init_expr);
Ast *te = remove_type_alias_clutter(type_expr);
e->type = t_invalid; e->type = t_invalid;
String name = e->token.string; String name = e->token.string;
Type *named = alloc_type_named(name, nullptr, e); Type *named = alloc_type_named(name, nullptr, e);
@@ -265,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
named->Named.base = base_type(bt); named->Named.base = base_type(bt);
if (is_distinct && is_type_typeid(e->type)) { if (is_distinct && is_type_typeid(e->type)) {
error(type_expr, "'distinct' cannot be applied to 'typeid'"); error(init_expr, "'distinct' cannot be applied to 'typeid'");
is_distinct = false; is_distinct = false;
} }
if (!is_distinct) { if (!is_distinct) {
@@ -274,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def)
e->TypeName.is_type_alias = true; e->TypeName.is_type_alias = true;
} }
if (decl->type_expr != nullptr) {
Type *t = check_type(ctx, decl->type_expr);
if (t != nullptr && !is_type_typeid(t)) {
Operand operand = {};
operand.mode = Addressing_Type;
operand.type = e->type;
operand.expr = init_expr;
check_assignment(ctx, &operand, t, str_lit("constant declaration"));
}
}
// using decl // using decl
if (decl->is_using) { if (decl->is_using) {
// NOTE(bill): Must be an enum declaration // NOTE(bill): Must be an enum declaration
@@ -362,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
switch (operand.mode) { switch (operand.mode) {
case Addressing_Type: { case Addressing_Type: {
if (e->type != nullptr && !is_type_typeid(e->type)) {
check_assignment(ctx, &operand, e->type, str_lit("constant declaration"));
}
e->kind = Entity_TypeName; e->kind = Entity_TypeName;
e->type = nullptr; e->type = nullptr;
DeclInfo *d = ctx->decl; check_type_decl(ctx, e, ctx->decl->init_expr, named_type);
if (d->type_expr != nullptr) {
error(e->token, "A type declaration cannot have an type parameter");
}
d->type_expr = d->init_expr;
check_type_decl(ctx, e, d->type_expr, named_type);
return; return;
} }
@@ -654,7 +675,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
bool is_foreign = e->Procedure.is_foreign; bool is_foreign = e->Procedure.is_foreign;
bool is_export = e->Procedure.is_export; bool is_export = e->Procedure.is_export;
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
if (e->pkg != nullptr && e->token.string == "main") { if (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 || if (pt->param_count != 0 ||
@@ -714,10 +734,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
} }
} }
if (pt->result_count == 0 && is_require_results) { if (pt->result_count == 0 && ac.require_results) {
error(pl->type, "'#require_results' is not needed on a procedure with no results"); error(pl->type, "'require_results' is not needed on a procedure with no results");
} else { } else {
pt->require_results = is_require_results; pt->require_results = ac.require_results;
} }
if (ac.link_name.len > 0) { if (ac.link_name.len > 0) {
@@ -791,7 +811,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
} }
} }
void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
GB_ASSERT(e->type == nullptr); GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable); GB_ASSERT(e->kind == Entity_Variable);
@@ -805,6 +825,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
ac.init_expr_list_count = init_expr != nullptr ? 1 : 0; ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
DeclInfo *decl = decl_info_of_entity(e); DeclInfo *decl = decl_info_of_entity(e);
GB_ASSERT(decl == ctx->decl);
if (decl != nullptr) { if (decl != nullptr) {
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac); check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
} }
@@ -936,7 +957,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
ptr_set_destroy(&entity_set); ptr_set_destroy(&entity_set);
for_array(j, pge->entities) { for_array(j, pge->entities) {
Entity *p = pge->entities[j]; Entity *p = pge->entities[j];
if (p->type == t_invalid) { if (p->type == t_invalid) {
@@ -962,27 +982,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
defer (end_error_block()); defer (end_error_block());
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
switch (kind) { bool both_have_where_clauses = false;
if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
auto pl = &p->decl_info->proc_lit->ProcLit;
auto ql = &q->decl_info->proc_lit->ProcLit;
// Allow collisions if the procedures both have 'where' clauses and are both polymorphic
bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
both_have_where_clauses = pw && qw;
}
if (!both_have_where_clauses) switch (kind) {
case ProcOverload_Identical: case ProcOverload_Identical:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name)); error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true; is_invalid = true;
break; break;
// case ProcOverload_CallingConvention: // case ProcOverload_CallingConvention:
// error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name)); // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
// is_invalid = true; // is_invalid = true;
// break; // break;
case ProcOverload_ParamVariadic: case ProcOverload_ParamVariadic:
error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name)); error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true; is_invalid = true;
break; break;
case ProcOverload_ResultCount: case ProcOverload_ResultCount:
case ProcOverload_ResultTypes: case ProcOverload_ResultTypes:
error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name)); error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name));
is_invalid = true; is_invalid = true;
break; break;
case ProcOverload_Polymorphic: case ProcOverload_Polymorphic:
#if 0 #if 0
error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name)); error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name));
is_invalid = true; is_invalid = true;
#endif #endif
break; break;
@@ -1051,13 +1084,13 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
switch (e->kind) { switch (e->kind) {
case Entity_Variable: case Entity_Variable:
check_var_decl(&c, e, d->type_expr, d->init_expr); check_global_variable_decl(&c, e, d->type_expr, d->init_expr);
break; break;
case Entity_Constant: case Entity_Constant:
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type); check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
break; break;
case Entity_TypeName: { case Entity_TypeName: {
check_type_decl(&c, e, d->type_expr, named_type); check_type_decl(&c, e, d->init_expr, named_type);
break; break;
} }
case Entity_Procedure: case Entity_Procedure:
@@ -1074,6 +1107,11 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_
} }
struct ProcUsingVar {
Entity *e;
Entity *uvar;
};
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
if (body == nullptr) { if (body == nullptr) {
@@ -1098,6 +1136,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
ctx->curr_proc_decl = decl; ctx->curr_proc_decl = decl;
ctx->curr_proc_sig = type; ctx->curr_proc_sig = type;
ast_node(bs, BlockStmt, body);
Array<ProcUsingVar> using_entities = {};
using_entities.allocator = heap_allocator();
defer (array_free(&using_entities));
{
GB_ASSERT(type->kind == Type_Proc); GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) { if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple; TypeTuple *params = &type->Proc.params->Tuple;
@@ -1122,15 +1167,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
for_array(i, scope->elements.entries) { for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value; Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) { if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
uvar->Variable.is_immutable = is_immutable; uvar->Variable.is_immutable = is_immutable;
if (is_value) uvar->flags |= EntityFlag_Value; if (is_value) uvar->flags |= EntityFlag_Value;
Entity *prev = scope_insert(ctx->scope, uvar); ProcUsingVar puv = {e, uvar};
if (prev != nullptr) { array_add(&using_entities, puv);
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
break;
}
} }
} }
} else { } else {
@@ -1139,10 +1182,37 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
} }
} }
} }
}
for_array(i, using_entities) {
Entity *e = using_entities[i].e;
Entity *uvar = using_entities[i].uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
break;
}
}
bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
if (!where_clause_ok) {
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
return;
}
check_open_scope(ctx, body);
{
for_array(i, using_entities) {
Entity *e = using_entities[i].e;
Entity *uvar = using_entities[i].uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
// NOTE(bill): Don't err here
}
ast_node(bs, BlockStmt, body);
// check_open_scope(ctx, body);
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) { if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) { if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) { if (token.kind == Token_Ident) {
@@ -1153,12 +1223,19 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
} }
} }
} }
// check_close_scope(ctx); }
check_close_scope(ctx);
check_scope_usage(ctx->checker, ctx->scope); check_scope_usage(ctx->checker, ctx->scope);
#if 1
if (decl->parent != nullptr) { if (decl->parent != nullptr) {
Scope *ps = decl->parent->scope;
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
return;
} else {
// NOTE(bill): Add the dependencies from the procedure literal (lambda) // NOTE(bill): Add the dependencies from the procedure literal (lambda)
// But only at the procedure level
for_array(i, decl->deps.entries) { for_array(i, decl->deps.entries) {
Entity *e = decl->deps.entries[i].ptr; Entity *e = decl->deps.entries[i].ptr;
ptr_set_add(&decl->parent->deps, e); ptr_set_add(&decl->parent->deps, e);
@@ -1169,6 +1246,8 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
} }
} }
} }
#endif
}
+995 -110
View File
File diff suppressed because it is too large. Load diff
+192 -29
View File
@@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) {
} }
case_end; case_end;
case_ast_node(rs, InlineRangeStmt, node);
return false;
case_end;
case_ast_node(rs, RangeStmt, node); case_ast_node(rs, RangeStmt, node);
return false; return false;
case_end; case_end;
@@ -492,8 +496,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b
for_array(i, found->elements.entries) { for_array(i, found->elements.entries) {
Entity *f = found->elements.entries[i].value; Entity *f = found->elements.entries[i].value;
if (f->kind == Entity_Variable) { if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr);
uvar->using_expr = expr;
Entity *prev = scope_insert(ctx->scope, uvar); Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) { if (prev != nullptr) {
gbString expr_str = expr_to_string(expr); gbString expr_str = expr_to_string(expr);
@@ -587,6 +590,162 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
multi_map_insert(seen, key, tap); multi_map_insert(seen, key, tap);
} }
void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(irs, InlineRangeStmt, node);
check_open_scope(ctx, node);
Type *val0 = nullptr;
Type *val1 = nullptr;
Entity *entities[2] = {};
isize entity_count = 0;
Ast *expr = unparen_expr(irs->expr);
ExactValue inline_for_depth = exact_value_i64(0);
if (is_ast_range(expr)) {
ast_node(ie, BinaryExpr, expr);
Operand x = {};
Operand y = {};
bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
if (!ok) {
goto skip_expr;
}
val0 = x.type;
val1 = t_int;
} else {
Operand operand = {Addressing_Invalid};
check_expr_or_type(ctx, &operand, irs->expr);
if (operand.mode == Addressing_Type) {
if (!is_type_enum(operand.type)) {
gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over the type '%s'", t);
gb_string_free(t);
goto skip_expr;
} else {
val0 = operand.type;
val1 = t_int;
add_type_info_type(ctx, operand.type);
Type *bt = base_type(operand.type);
inline_for_depth = exact_value_i64(bt->Enum.fields.count);
goto skip_expr;
}
} else if (operand.mode != Addressing_Invalid) {
Type *t = base_type(operand.type);
switch (t->kind) {
case Type_Basic:
if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
val0 = t_rune;
val1 = t_int;
inline_for_depth = exact_value_i64(operand.value.value_string.len);
}
break;
case Type_Array:
val0 = t->Array.elem;
val1 = t_int;
inline_for_depth = exact_value_i64(t->Array.count);
break;
}
}
if (val0 == nullptr) {
gbString s = expr_to_string(operand.expr);
gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t);
gb_string_free(t);
gb_string_free(s);
} else if (operand.mode != Addressing_Constant) {
error(operand.expr, "An 'inline for' expression must be known at compile time");
}
}
skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
Ast * lhs[2] = {irs->val0, irs->val1};
Type *rhs[2] = {val0, val1};
for (isize i = 0; i < 2; i++) {
if (lhs[i] == nullptr) {
continue;
}
Ast * name = lhs[i];
Type *type = rhs[i];
Entity *entity = nullptr;
if (name->kind == Ast_Ident) {
Token token = name->Ident.token;
String str = token.string;
Entity *found = nullptr;
if (!is_blank_ident(str)) {
found = scope_lookup_current(ctx->scope, str);
}
if (found == nullptr) {
bool is_immutable = true;
entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved);
entity->flags |= EntityFlag_Value;
add_entity_definition(&ctx->checker->info, name, entity);
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
} else {
error(name, "A variable declaration must be an identifier");
}
if (entity == nullptr) {
entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name));
}
entities[entity_count++] = entity;
if (type == nullptr) {
entity->type = t_invalid;
entity->flags |= EntityFlag_Used;
}
}
for (isize i = 0; i < entity_count; i++) {
add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
}
// NOTE(bill): Minimize the amount of nesting of an 'inline for'
i64 prev_inline_for_depth = ctx->inline_for_depth;
defer (ctx->inline_for_depth = prev_inline_for_depth);
{
i64 v = exact_value_to_i64(inline_for_depth);
if (v <= 0) {
// Do nothing
} else {
ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v;
}
if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) {
if (prev_inline_for_depth > 0) {
error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
} else {
error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH);
}
error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n");
ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH;
}
}
check_stmt(ctx, irs->body, mod_flags);
check_close_scope(ctx);
}
void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
ast_node(ss, SwitchStmt, node); ast_node(ss, SwitchStmt, node);
@@ -971,7 +1130,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
GB_PANIC("Unknown type to type switch statement"); GB_PANIC("Unknown type to type switch statement");
} }
if (ptr_set_exists(&seen, y.type)) { if (type_ptr_set_exists(&seen, y.type)) {
TokenPos pos = cc->token.pos; TokenPos pos = cc->token.pos;
gbString expr_str = expr_to_string(y.expr); gbString expr_str = expr_to_string(y.expr);
error(y.expr, error(y.expr,
@@ -1023,7 +1182,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
for_array(i, variants) { for_array(i, variants) {
Type *t = variants[i]; Type *t = variants[i];
if (!ptr_set_exists(&seen, t)) { if (!type_ptr_set_exists(&seen, t)) {
array_add(&unhandled, t); array_add(&unhandled, t);
} }
} }
@@ -1132,7 +1291,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
isize rhs_count = rhs_operands.count; isize rhs_count = rhs_operands.count;
for_array(i, rhs_operands) { for_array(i, rhs_operands) {
if (rhs_operands[i].mode == Addressing_Invalid) { if (rhs_operands[i].mode == Addressing_Invalid) {
rhs_count--; // TODO(bill): Should I ignore invalid parameters?
// rhs_count--;
} }
} }
@@ -1168,7 +1328,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
be->right = as->rhs[0]; be->right = as->rhs[0];
check_expr(ctx, &lhs, as->lhs[0]); check_expr(ctx, &lhs, as->lhs[0]);
check_binary_expr(ctx, &rhs, &binary_expr, true); check_binary_expr(ctx, &rhs, &binary_expr, nullptr, true);
if (rhs.mode == Addressing_Invalid) { if (rhs.mode == Addressing_Invalid) {
return; return;
} }
@@ -1298,6 +1458,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_close_scope(ctx); check_close_scope(ctx);
case_end; case_end;
case_ast_node(rs, RangeStmt, node); case_ast_node(rs, RangeStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
@@ -1320,29 +1481,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_expr(ctx, &x, ie->left); check_expr(ctx, &x, ie->left);
if (x.mode == Addressing_Invalid) { if (x.mode == Addressing_Invalid) {
goto skip_expr; goto skip_expr_range_stmt;
} }
check_expr(ctx, &y, ie->right); check_expr(ctx, &y, ie->right);
if (y.mode == Addressing_Invalid) { if (y.mode == Addressing_Invalid) {
goto skip_expr; goto skip_expr_range_stmt;
} }
convert_to_typed(ctx, &x, y.type); convert_to_typed(ctx, &x, y.type);
if (x.mode == Addressing_Invalid) { if (x.mode == Addressing_Invalid) {
goto skip_expr; goto skip_expr_range_stmt;
} }
convert_to_typed(ctx, &y, x.type); convert_to_typed(ctx, &y, x.type);
if (y.mode == Addressing_Invalid) { if (y.mode == Addressing_Invalid) {
goto skip_expr; goto skip_expr_range_stmt;
} }
convert_to_typed(ctx, &x, default_type(y.type)); convert_to_typed(ctx, &x, default_type(y.type));
if (x.mode == Addressing_Invalid) { if (x.mode == Addressing_Invalid) {
goto skip_expr; goto skip_expr_range_stmt;
} }
convert_to_typed(ctx, &y, default_type(x.type)); convert_to_typed(ctx, &y, default_type(x.type));
if (y.mode == Addressing_Invalid) { if (y.mode == Addressing_Invalid) {
goto skip_expr; goto skip_expr_range_stmt;
} }
if (!are_types_identical(x.type, y.type)) { if (!are_types_identical(x.type, y.type)) {
@@ -1356,13 +1517,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
gb_string_free(yt); gb_string_free(yt);
gb_string_free(xt); gb_string_free(xt);
} }
goto skip_expr; goto skip_expr_range_stmt;
} }
Type *type = x.type; Type *type = x.type;
if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
goto skip_expr; goto skip_expr_range_stmt;
} }
if (x.mode == Addressing_Constant && if (x.mode == Addressing_Constant &&
@@ -1382,18 +1543,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (!ok) { if (!ok) {
// TODO(bill): Better error message // TODO(bill): Better error message
error(ie->op, "Invalid interval range"); error(ie->op, "Invalid interval range");
goto skip_expr; goto skip_expr_range_stmt;
} }
} }
if (x.mode != Addressing_Constant) {
x.value = empty_exact_value;
}
if (y.mode != Addressing_Constant) {
y.value = empty_exact_value;
}
add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value);
add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
val0 = type; val0 = type;
@@ -1407,12 +1560,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
gbString t = type_to_string(operand.type); gbString t = type_to_string(operand.type);
error(operand.expr, "Cannot iterate over the type '%s'", t); error(operand.expr, "Cannot iterate over the type '%s'", t);
gb_string_free(t); gb_string_free(t);
goto skip_expr; goto skip_expr_range_stmt;
} else { } else {
val0 = operand.type; val0 = operand.type;
val1 = t_int; val1 = t_int;
add_type_info_type(ctx, operand.type); add_type_info_type(ctx, operand.type);
goto skip_expr; goto skip_expr_range_stmt;
} }
} else if (operand.mode != Addressing_Invalid) { } else if (operand.mode != Addressing_Invalid) {
bool is_ptr = is_type_pointer(operand.type); bool is_ptr = is_type_pointer(operand.type);
@@ -1457,7 +1610,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
} }
} }
skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird.
Ast * lhs[2] = {rs->val0, rs->val1}; Ast * lhs[2] = {rs->val0, rs->val1};
Type *rhs[2] = {val0, val1}; Type *rhs[2] = {val0, val1};
@@ -1507,7 +1661,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
} }
for (isize i = 0; i < entity_count; i++) { for (isize i = 0; i < entity_count; i++) {
add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]); Entity *e = entities[i];
DeclInfo *d = decl_info_of_entity(e);
GB_ASSERT(d == nullptr);
add_entity(ctx->checker, ctx->scope, e->identifier, e);
d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl);
add_entity_and_decl_info(ctx, e->identifier, e, d);
} }
check_stmt(ctx, rs->body, new_flags); check_stmt(ctx, rs->body, new_flags);
@@ -1515,6 +1674,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
check_close_scope(ctx); check_close_scope(ctx);
case_end; case_end;
case_ast_node(irs, InlineRangeStmt, node);
check_inline_range_stmt(ctx, node, mod_flags);
case_end;
case_ast_node(ss, SwitchStmt, node); case_ast_node(ss, SwitchStmt, node);
check_switch_stmt(ctx, node, mod_flags); check_switch_stmt(ctx, node, mod_flags);
case_end; case_end;
@@ -1814,7 +1977,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
// TODO(bill): Should a 'continue' happen here? // TODO(bill): Should a 'continue' happen here?
} }
for (isize entity_index = 0; entity_index < entity_count; entity_index++) { for (isize entity_index = 0; entity_index < 1; entity_index++) {
Entity *e = entities[entity_index]; Entity *e = entities[entity_index];
if (e == nullptr) { if (e == nullptr) {
continue; continue;
@@ -1833,7 +1996,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
for_array(i, scope->elements.entries) { for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value; Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) { if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
uvar->Variable.is_immutable = is_immutable; uvar->Variable.is_immutable = is_immutable;
Entity *prev = scope_insert(ctx->scope, uvar); Entity *prev = scope_insert(ctx->scope, uvar);
if (prev != nullptr) { if (prev != nullptr) {
+359 -39
View File
@@ -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) { if (show_error) {
set_procedure_abi_types(ctx, poly_type); set_procedure_abi_types(ctx->allocator, poly_type);
} }
return poly_type; return poly_type;
} }
if (modify_type) { if (show_error) {
gbString pts = type_to_string(poly_type); gbString pts = type_to_string(poly_type);
gbString ots = type_to_string(operand.type); gbString ots = type_to_string(operand.type);
defer (gb_string_free(pts)); defer (gb_string_free(pts));
@@ -1538,7 +1567,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
} }
if (is_poly_name) { if (is_poly_name) {
if (type != nullptr && type_expr->kind == Ast_TypeidType) { if (type_expr != nullptr && type_expr->kind == Ast_TypeidType) {
is_type_param = true; is_type_param = true;
} else { } else {
if (param_value.kind != ParameterValue_Invalid) { if (param_value.kind != ParameterValue_Invalid) {
@@ -1622,6 +1651,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
if (op.mode == Addressing_Constant) { if (op.mode == Addressing_Constant) {
poly_const = op.value; poly_const = op.value;
} else { } else {
error(op.expr, "Expected a constant value for this polymorphic name parameter");
success = false; success = false;
} }
} }
@@ -1825,6 +1855,282 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
return tuple; return tuple;
} }
Array<Type *> systemv_distribute_struct_fields(Type *t) {
Type *bt = core_type(t);
isize distributed_cap = 1;
if (bt->kind == Type_Struct) {
distributed_cap = bt->Struct.fields.count;
}
auto distributed = array_make<Type *>(heap_allocator(), 0, distributed_cap);
i64 sz = type_size_of(bt);
switch (bt->kind) {
case Type_Basic:
switch (bt->Basic.kind){
case Basic_complex64:
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
break;
case Basic_complex128:
array_add(&distributed, t_f64);
array_add(&distributed, t_f64);
break;
case Basic_quaternion128:
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
array_add(&distributed, t_f32);
break;
case Basic_quaternion256:
goto DEFAULT;
case Basic_string:
array_add(&distributed, t_u8_ptr);
array_add(&distributed, t_int);
break;
case Basic_any:
GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid));
array_add(&distributed, t_rawptr);
array_add(&distributed, t_uintptr);
break;
case Basic_u128:
case Basic_i128:
if (build_context.ODIN_OS == "windows") {
array_add(&distributed, alloc_type_simd_vector(2, t_u64));
} else {
array_add(&distributed, bt);
}
break;
default:
goto DEFAULT;
}
break;
case Type_Struct:
if (bt->Struct.is_raw_union) {
goto DEFAULT;
} else {
// IMPORTANT TOOD(bill): handle #packed structs correctly
// IMPORTANT TODO(bill): handle #align structs correctly
for_array(field_index, bt->Struct.fields) {
Entity *f = bt->Struct.fields[field_index];
auto nested = systemv_distribute_struct_fields(f->type);
array_add_elems(&distributed, nested.data, nested.count);
array_free(&nested);
}
}
break;
case Type_Array:
for (i64 i = 0; i < bt->Array.count; i++) {
array_add(&distributed, bt->Array.elem);
}
break;
case Type_BitSet:
array_add(&distributed, bit_set_to_int(bt));
break;
case Type_Tuple:
GB_PANIC("Invalid struct field type");
break;
case Type_Slice:
array_add(&distributed, t_rawptr);
array_add(&distributed, t_int);
break;
case Type_Union:
case Type_DynamicArray:
case Type_Map:
case Type_BitField: // TODO(bill): Ignore?
// NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet
goto DEFAULT;
case Type_Pointer:
case Type_Proc:
case Type_SimdVector: // TODO(bill): Is this correct logic?
default:
DEFAULT:;
if (sz > 0) {
array_add(&distributed, bt);
}
break;
}
return distributed;
}
Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) {
GB_ASSERT(is_type_tuple(abi_type));
Type *final_type = alloc_type_struct();
final_type->Struct.fields = abi_type->Tuple.variables;
return final_type;
}
Type *handle_single_distributed_type_parameter(Array<Type *> const &types, bool packed, isize *offset) {
GB_ASSERT(types.count > 0);
if (types.count == 1) {
if (offset) *offset = 1;
i64 sz = type_size_of(types[0]);
if (is_type_float(types[0])) {
return types[0];
}
switch (sz) {
case 0:
GB_PANIC("Zero sized type found!");
case 1: return t_u8;
case 2: return t_u16;
case 4: return t_u32;
case 8: return t_u64;
default:
return types[0];
}
} else if (types.count >= 2) {
if (types[0] == t_f32 && types[1] == t_f32) {
if (offset) *offset = 2;
return alloc_type_simd_vector(2, t_f32);
} else if (type_size_of(types[0]) == 8) {
if (offset) *offset = 1;
return types[0];
}
i64 total_size = 0;
isize i = 0;
if (packed) {
for (; i < types.count && total_size < 8; i += 1) {
Type *t = types[i];
i64 s = type_size_of(t);
total_size += s;
}
} else {
for (; i < types.count && total_size < 8; i += 1) {
Type *t = types[i];
i64 s = gb_max(type_size_of(t), 0);
i64 a = gb_max(type_align_of(t), 1);
isize ts = align_formula(total_size, a);
if (ts >= 8) {
break;
}
total_size = ts + s;
}
}
if (offset) *offset = i;
switch (total_size) {
case 1: return t_u8;
case 2: return t_u16;
case 4: return t_u32;
case 8: return t_u64;
}
return t_u64;
}
return nullptr;
}
Type *handle_struct_system_v_amd64_abi_type(Type *t) {
if (type_size_of(t) > 16) {
return alloc_type_pointer(t);
}
Type *original_type = t;
Type *bt = core_type(t);
t = base_type(t);
i64 size = type_size_of(bt);
switch (t->kind) {
case Type_Slice:
case Type_Struct:
break;
case Type_Basic:
switch (bt->Basic.kind) {
case Basic_string:
case Basic_any:
case Basic_complex64:
case Basic_complex128:
case Basic_quaternion128:
break;
default:
return original_type;
}
break;
default:
return original_type;
}
bool is_packed = false;
if (is_type_struct(bt)) {
is_packed = bt->Struct.is_packed;
}
if (is_type_raw_union(bt)) {
// TODO(bill): Handle raw union correctly for
return t;
} else {
auto field_types = systemv_distribute_struct_fields(bt);
defer (array_free(&field_types));
GB_ASSERT(field_types.count <= 16);
Type *final_type = nullptr;
if (field_types.count == 0) {
final_type = t;
} else if (field_types.count == 1) {
final_type = field_types[0];
} else {
if (size <= 8) {
isize offset = 0;
final_type = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
} else {
isize offset = 0;
isize next_offset = 0;
Type *two_types[2] = {};
two_types[0] = handle_single_distributed_type_parameter(field_types, is_packed, &offset);
auto remaining = array_slice(field_types, offset, field_types.count);
two_types[1] = handle_single_distributed_type_parameter(remaining, is_packed, &next_offset);
GB_ASSERT(offset + next_offset == field_types.count);
auto variables = array_make<Entity *>(heap_allocator(), 2);
variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false);
variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false);
final_type = alloc_type_tuple();
final_type->Tuple.variables = variables;
if (t->kind == Type_Struct) {
// NOTE(bill): Make this packed
final_type->Tuple.is_packed = t->Struct.is_packed;
}
}
}
GB_ASSERT(final_type != nullptr);
i64 ftsz = type_size_of(final_type);
i64 otsz = type_size_of(original_type);
if (ftsz != otsz) {
// TODO(bill): Handle this case which will be caused by #packed most likely
switch (otsz) {
case 1:
case 2:
case 4:
case 8:
GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %s %lld vs %s %lld", type_to_string(final_type), ftsz, type_to_string(original_type), otsz);
}
}
return final_type;
}
}
Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) { Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) {
Type *new_type = original_type; Type *new_type = original_type;
@@ -1889,6 +2195,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
{ {
i64 align = type_align_of(original_type); i64 align = type_align_of(original_type);
i64 size = type_size_of(original_type); i64 size = type_size_of(original_type);
switch (8*size) { switch (8*size) {
case 8: new_type = t_u8; break; case 8: new_type = t_u8; break;
case 16: new_type = t_u16; break; case 16: new_type = t_u16; break;
@@ -1903,7 +2210,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
} }
} }
} else if (build_context.ODIN_OS == "linux" || } else if (build_context.ODIN_OS == "linux" ||
build_context.ODIN_OS == "osx") { build_context.ODIN_OS == "darwin") {
Type *bt = core_type(original_type); Type *bt = core_type(original_type);
switch (bt->kind) { switch (bt->kind) {
// Okay to pass by value (usually) // Okay to pass by value (usually)
@@ -1920,18 +2227,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
case Type_Pointer: break; case Type_Pointer: break;
case Type_Proc: break; // NOTE(bill): Just a pointer case Type_Proc: break; // NOTE(bill): Just a pointer
// Odin specific default: {
case Type_Slice:
case Type_Array:
case Type_DynamicArray:
case Type_Map:
case Type_Union:
// Could be in C too
case Type_Struct: {
i64 align = type_align_of(original_type);
i64 size = type_size_of(original_type); i64 size = type_size_of(original_type);
if (8*size > 16) { if (size > 16) {
new_type = alloc_type_pointer(original_type); new_type = alloc_type_pointer(original_type);
} else if (build_context.ODIN_ARCH == "amd64") {
// NOTE(bill): System V AMD64 ABI
new_type = handle_struct_system_v_amd64_abi_type(bt);
if (are_types_identical(core_type(original_type), new_type)) {
new_type = original_type;
}
return new_type;
} }
break; break;
@@ -2004,8 +2310,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
break; break;
} }
} }
} else if (build_context.ODIN_OS == "linux") { } else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") {
if (build_context.ODIN_ARCH == "amd64") {
}
} else { } else {
// IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for
// their architectures // their architectures
@@ -2071,25 +2379,39 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
return false; return false;
} }
void set_procedure_abi_types(CheckerContext *c, Type *type) { void set_procedure_abi_types(gbAllocator allocator, Type *type) {
type = base_type(type); type = base_type(type);
if (type->kind != Type_Proc) { if (type->kind != Type_Proc) {
return; return;
} }
type->Proc.abi_compat_params = array_make<Type *>(c->allocator, cast(isize)type->Proc.param_count); if (type->Proc.abi_types_set) {
return;
}
type->Proc.abi_compat_params = array_make<Type *>(allocator, cast(isize)type->Proc.param_count);
for (i32 i = 0; i < type->Proc.param_count; i++) { for (i32 i = 0; i < type->Proc.param_count; i++) {
Entity *e = type->Proc.params->Tuple.variables[i]; Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind == Entity_Variable) { if (e->kind == Entity_Variable) {
Type *original_type = e->type; Type *original_type = e->type;
Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention); Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention);
type->Proc.abi_compat_params[i] = new_type; type->Proc.abi_compat_params[i] = new_type;
switch (type->Proc.calling_convention) {
case ProcCC_Odin:
case ProcCC_Contextless:
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
e->flags |= EntityFlag_ImplicitReference;
}
break;
}
} }
} }
// NOTE(bill): The types are the same // NOTE(bill): The types are the same
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention); type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention);
type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
type->Proc.abi_types_set = true;
} }
// NOTE(bill): 'operands' is for generating non generic procedure type // NOTE(bill): 'operands' is for generating non generic procedure type
@@ -2187,8 +2509,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
} }
type->Proc.is_polymorphic = is_polymorphic; type->Proc.is_polymorphic = is_polymorphic;
set_procedure_abi_types(c, type);
return success; return success;
} }
@@ -2537,7 +2857,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
generic_type = o.type; generic_type = o.type;
} }
if (count < 0) { if (count < 0) {
error(at->count, "... can only be used in conjuction with compound literals"); error(at->count, "? can only be used in conjuction with compound literals");
count = 0; count = 0;
} }
Type *elem = check_type_expr(ctx, at->elem, nullptr); Type *elem = check_type_expr(ctx, at->elem, nullptr);
+103 -31
View File
@@ -85,10 +85,14 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) {
EntityGraphNode *y = data[j]; EntityGraphNode *y = data[j];
isize a = x->entity->order_in_src; isize a = x->entity->order_in_src;
isize b = y->entity->order_in_src; isize b = y->entity->order_in_src;
if (x->dep_count < y->dep_count) return -1; if (x->dep_count < y->dep_count) {
if (x->dep_count > y->dep_count) return +1; return -1;
}
if (x->dep_count == y->dep_count) {
return a < b ? -1 : b > a; return a < b ? -1 : b > a;
} }
return +1;
}
void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) { void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) {
EntityGraphNode *x = data[i]; EntityGraphNode *x = data[i];
@@ -400,6 +404,15 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) {
if (found) { if (found) {
return *found; return *found;
} }
if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) {
Entity **found = map_get(&s->parent->elements, key);
if (found) {
if ((*found)->flags & EntityFlag_Result) {
return *found;
}
}
}
map_set(&s->elements, key, entity); map_set(&s->elements, key, entity);
if (entity->scope == nullptr) { if (entity->scope == nullptr) {
entity->scope = s; entity->scope = s;
@@ -1044,22 +1057,38 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) {
// NOTE(bill): Error should have been handled already // NOTE(bill): Error should have been handled already
return false; return false;
} }
if (found->flags & EntityFlag_Result) {
error(prev->token,
"Direct shadowing of the named return value '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
} else {
error(prev->token, error(prev->token,
"Redeclaration of '%.*s' in this scope through 'using'\n" "Redeclaration of '%.*s' in this scope through 'using'\n"
"\tat %.*s(%td:%td)", "\tat %.*s(%td:%td)",
LIT(name), LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
}
} else { } else {
if (pos == prev->token.pos) { if (pos == prev->token.pos) {
// NOTE(bill): Error should have been handled already // NOTE(bill): Error should have been handled already
return false; return false;
} }
if (found->flags & EntityFlag_Result) {
error(prev->token,
"Direct shadowing of the named return value '%.*s' in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
} else {
error(prev->token, error(prev->token,
"Redeclaration of '%.*s' in this scope\n" "Redeclaration of '%.*s' in this scope\n"
"\tat %.*s(%td:%td)", "\tat %.*s(%td:%td)",
LIT(name), LIT(name),
LIT(pos.file), pos.line, pos.column); LIT(pos.file), pos.line, pos.column);
} }
}
return false; return false;
} }
@@ -1139,6 +1168,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec
add_entity_definition(&c->checker->info, identifier, e); add_entity_definition(&c->checker->info, identifier, e);
GB_ASSERT(e->decl_info == nullptr); GB_ASSERT(e->decl_info == nullptr);
e->decl_info = d; e->decl_info = d;
d->entity = e;
array_add(&c->checker->info.entities, e); array_add(&c->checker->info.entities, e);
e->order_in_src = c->checker->info.entities.count; e->order_in_src = c->checker->info.entities.count;
e->pkg = c->pkg; e->pkg = c->pkg;
@@ -1415,6 +1445,14 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, t_type_info_float); add_min_dep_type_info(c, t_type_info_float);
add_min_dep_type_info(c, t_f64); add_min_dep_type_info(c, t_f64);
break; break;
case Basic_quaternion128:
add_min_dep_type_info(c, t_type_info_float);
add_min_dep_type_info(c, t_f32);
break;
case Basic_quaternion256:
add_min_dep_type_info(c, t_type_info_float);
add_min_dep_type_info(c, t_f64);
break;
} }
break; break;
@@ -1577,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("args__"), str_lit("args__"),
str_lit("type_table"), str_lit("type_table"),
str_lit("__type_info_of"),
str_lit("global_scratch_allocator"), str_lit("global_scratch_allocator"),
str_lit("Type_Info"), str_lit("Type_Info"),
@@ -1585,9 +1624,17 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("quo_complex64"), str_lit("quo_complex64"),
str_lit("quo_complex128"), str_lit("quo_complex128"),
str_lit("mul_quaternion128"),
str_lit("mul_quaternion256"),
str_lit("quo_quaternion128"),
str_lit("quo_quaternion256"),
str_lit("cstring_to_string"),
str_lit("umodti3"), str_lit("umodti3"),
str_lit("udivti3"), str_lit("udivti3"),
str_lit("memory_compare"),
str_lit("memory_compare_zero"),
}; };
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));
@@ -1656,9 +1703,10 @@ bool is_entity_a_dependency(Entity *e) {
if (e == nullptr) return false; if (e == nullptr) return false;
switch (e->kind) { switch (e->kind) {
case Entity_Procedure: case Entity_Procedure:
case Entity_Variable:
case Entity_Constant:
return true; return true;
case Entity_Constant:
case Entity_Variable:
return e->pkg != nullptr;
} }
return false; return false;
} }
@@ -1685,21 +1733,20 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
EntityGraphNode *n = M.entries[i].value; EntityGraphNode *n = M.entries[i].value;
DeclInfo *decl = decl_info_of_entity(e); DeclInfo *decl = decl_info_of_entity(e);
if (decl != nullptr) { GB_ASSERT(decl != nullptr);
for_array(j, decl->deps.entries) { for_array(j, decl->deps.entries) {
auto entry = decl->deps.entries[j]; Entity *dep = decl->deps.entries[j].ptr;
Entity *dep = entry.ptr; GB_ASSERT(dep != nullptr);
if (dep && is_entity_a_dependency(dep)) { if (is_entity_a_dependency(dep)) {
EntityGraphNode **m_ = map_get(&M, hash_pointer(dep)); EntityGraphNode **m_ = map_get(&M, hash_pointer(dep));
if (m_ != nullptr) { GB_ASSERT(m_ != nullptr);
EntityGraphNode *m = *m_; EntityGraphNode *m = *m_;
entity_graph_node_set_add(&n->succ, m); entity_graph_node_set_add(&n->succ, m);
entity_graph_node_set_add(&m->pred, n); entity_graph_node_set_add(&m->pred, n);
} }
} }
} }
}
}
auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count); auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count);
@@ -1741,6 +1788,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
EntityGraphNode *n = G[i]; EntityGraphNode *n = G[i];
n->index = i; n->index = i;
n->dep_count = n->succ.entries.count; n->dep_count = n->succ.entries.count;
GB_ASSERT(n->dep_count >= 0); GB_ASSERT(n->dep_count >= 0);
} }
@@ -1863,6 +1911,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer")); t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer"));
t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune")); t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune"));
t_type_info_float = find_core_type(c, str_lit("Type_Info_Float")); t_type_info_float = find_core_type(c, str_lit("Type_Info_Float"));
t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion"));
t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex")); t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex"));
t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); t_type_info_string = find_core_type(c, str_lit("Type_Info_String"));
t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean"));
@@ -1887,6 +1936,7 @@ void init_core_type_info(Checker *c) {
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune); t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune);
t_type_info_float_ptr = alloc_type_pointer(t_type_info_float); t_type_info_float_ptr = alloc_type_pointer(t_type_info_float);
t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion);
t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex); t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex);
t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); t_type_info_string_ptr = alloc_type_pointer(t_type_info_string);
t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean);
@@ -2138,6 +2188,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name)); error(elem, "Expected a string value for '%.*s'", LIT(name));
} }
return true; return true;
} else if (name == "require_results") {
if (value != nullptr) {
error(elem, "Expected no value for '%.*s'", LIT(name));
}
ac->require_results = true;
return true;
} }
return false; return false;
} }
@@ -2528,6 +2584,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
Ast *init_expr = value; Ast *init_expr = value;
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl); DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
d->entity = e;
d->type_expr = vd->type; d->type_expr = vd->type;
d->init_expr = init_expr; d->init_expr = init_expr;
d->attributes = vd->attributes; d->attributes = vd->attributes;
@@ -2557,14 +2614,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
Entity *e = nullptr; Entity *e = nullptr;
d->attributes = vd->attributes; d->attributes = vd->attributes;
d->type_expr = vd->type;
d->init_expr = init;
if (is_ast_type(init)) { if (is_ast_type(init)) {
e = alloc_entity_type_name(d->scope, token, nullptr); e = alloc_entity_type_name(d->scope, token, nullptr);
if (vd->type != nullptr) { // if (vd->type != nullptr) {
error(name, "A type declaration cannot have an type parameter"); // error(name, "A type declaration cannot have an type parameter");
} // }
d->type_expr = init;
d->init_expr = init;
} else if (init->kind == Ast_ProcLit) { } else if (init->kind == Ast_ProcLit) {
if (c->scope->flags&ScopeFlag_Type) { if (c->scope->flags&ScopeFlag_Type) {
error(name, "Procedure declarations are not allowed within a struct"); error(name, "Procedure declarations are not allowed within a struct");
@@ -2591,19 +2648,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
pl->type->ProcType.calling_convention = cc; pl->type->ProcType.calling_convention = cc;
} }
d->proc_lit = init; d->proc_lit = init;
d->type_expr = vd->type; d->init_expr = init;
} else if (init->kind == Ast_ProcGroup) { } else if (init->kind == Ast_ProcGroup) {
ast_node(pg, ProcGroup, init); ast_node(pg, ProcGroup, init);
e = alloc_entity_proc_group(d->scope, token, nullptr); e = alloc_entity_proc_group(d->scope, token, nullptr);
if (fl != nullptr) { if (fl != nullptr) {
error(name, "Procedure groups are not allowed within a foreign block"); error(name, "Procedure groups are not allowed within a foreign block");
} }
d->init_expr = init;
d->type_expr = vd->type;
} else { } else {
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value); e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
d->type_expr = vd->type;
d->init_expr = init;
} }
e->identifier = name; e->identifier = name;
@@ -3101,7 +3154,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
Entity *e = scope->elements.entries[elem_index].value; Entity *e = scope->elements.entries[elem_index].value;
if (e->scope == parent_scope) continue; if (e->scope == parent_scope) continue;
if (is_entity_exported(e)) { if (is_entity_exported(e, true)) {
Entity *found = scope_lookup_current(parent_scope, name); Entity *found = scope_lookup_current(parent_scope, name);
if (found != nullptr) { if (found != nullptr) {
// NOTE(bill): // NOTE(bill):
@@ -3315,8 +3368,9 @@ bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
if (es->expr->kind == Ast_CallExpr) { if (es->expr->kind == Ast_CallExpr) {
ast_node(ce, CallExpr, es->expr); ast_node(ce, CallExpr, es->expr);
if (ce->proc->kind == Ast_BasicDirective) { if (ce->proc->kind == Ast_BasicDirective) {
Operand o = {}; if (ctx->collect_delayed_decls) {
check_expr(ctx, &o, es->expr); array_add(&ctx->scope->delayed_directives, es->expr);
}
} }
} }
case_end; case_end;
@@ -3473,12 +3527,18 @@ void check_import_entities(Checker *c) {
for_array(i, pkg->files) { for_array(i, pkg->files) {
AstFile *f = pkg->files[i]; AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx; CheckerContext ctx = c->init_ctx;
add_curr_ast_file(&ctx, f); add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_imports) { for_array(j, f->scope->delayed_imports) {
Ast *decl = f->scope->delayed_imports[j]; Ast *decl = f->scope->delayed_imports[j];
check_add_import_decl(&ctx, decl); check_add_import_decl(&ctx, decl);
} }
}
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
CheckerContext ctx = c->init_ctx;
add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_directives) { for_array(j, f->scope->delayed_directives) {
Ast *expr = f->scope->delayed_directives[j]; Ast *expr = f->scope->delayed_directives[j];
Operand o = {}; Operand o = {};
@@ -3542,7 +3602,6 @@ void calculate_global_init_order(Checker *c) {
#define TIME_SECTION(str) #define TIME_SECTION(str)
#endif #endif
CheckerInfo *info = &c->info; CheckerInfo *info = &c->info;
TIME_SECTION("generate entity dependency graph"); TIME_SECTION("generate entity dependency graph");
@@ -3584,21 +3643,26 @@ void calculate_global_init_order(Checker *c) {
for_array(i, n->pred.entries) { for_array(i, n->pred.entries) {
EntityGraphNode *p = n->pred.entries[i].ptr; EntityGraphNode *p = n->pred.entries[i].ptr;
p->dep_count -= gb_max(p->dep_count-1, 0); p->dep_count -= 1;
p->dep_count = gb_max(p->dep_count, 0);
priority_queue_fix(&pq, p->index); priority_queue_fix(&pq, p->index);
} }
if (e == nullptr || e->kind != Entity_Variable) { DeclInfo *d = decl_info_of_entity(e);
if (e->kind != Entity_Variable) {
continue; continue;
} }
DeclInfo *d = decl_info_of_entity(e); // IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering
// because it does not need any initialization other than zero
// if (!decl_info_has_init(d)) {
// continue;
// }
if (ptr_set_exists(&emitted, d)) { if (ptr_set_exists(&emitted, d)) {
continue; continue;
} }
ptr_set_add(&emitted, d); ptr_set_add(&emitted, d);
d->entity = e;
array_add(&info->variable_init_order, d); array_add(&info->variable_init_order, d);
} }
@@ -3637,6 +3701,14 @@ void check_proc_info(Checker *c, ProcInfo pi) {
return; return;
} }
if (pt->is_polymorphic && pt->is_poly_specialized) {
Entity *e = pi.decl->entity;
if ((e->flags & EntityFlag_Used) == 0) {
// NOTE(bill, 2019-08-31): It was never used, don't check
return;
}
}
bool bounds_check = (pi.tags & ProcTag_bounds_check) != 0; bool bounds_check = (pi.tags & ProcTag_bounds_check) != 0;
bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0; bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0;
+7 -211
View File
@@ -59,218 +59,8 @@ struct BuiltinProc {
BuiltinProcPkg pkg; BuiltinProcPkg pkg;
}; };
enum BuiltinProcId {
BuiltinProc_Invalid,
BuiltinProc_len, #include "checker_builtin_procs.hpp"
BuiltinProc_cap,
BuiltinProc_size_of,
BuiltinProc_align_of,
BuiltinProc_offset_of,
BuiltinProc_type_of,
BuiltinProc_type_info_of,
BuiltinProc_typeid_of,
BuiltinProc_swizzle,
BuiltinProc_complex,
BuiltinProc_real,
BuiltinProc_imag,
BuiltinProc_conj,
BuiltinProc_expand_to_tuple,
BuiltinProc_min,
BuiltinProc_max,
BuiltinProc_abs,
BuiltinProc_clamp,
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics"
BuiltinProc_vector,
BuiltinProc_atomic_fence,
BuiltinProc_atomic_fence_acq,
BuiltinProc_atomic_fence_rel,
BuiltinProc_atomic_fence_acqrel,
BuiltinProc_atomic_store,
BuiltinProc_atomic_store_rel,
BuiltinProc_atomic_store_relaxed,
BuiltinProc_atomic_store_unordered,
BuiltinProc_atomic_load,
BuiltinProc_atomic_load_acq,
BuiltinProc_atomic_load_relaxed,
BuiltinProc_atomic_load_unordered,
BuiltinProc_atomic_add,
BuiltinProc_atomic_add_acq,
BuiltinProc_atomic_add_rel,
BuiltinProc_atomic_add_acqrel,
BuiltinProc_atomic_add_relaxed,
BuiltinProc_atomic_sub,
BuiltinProc_atomic_sub_acq,
BuiltinProc_atomic_sub_rel,
BuiltinProc_atomic_sub_acqrel,
BuiltinProc_atomic_sub_relaxed,
BuiltinProc_atomic_and,
BuiltinProc_atomic_and_acq,
BuiltinProc_atomic_and_rel,
BuiltinProc_atomic_and_acqrel,
BuiltinProc_atomic_and_relaxed,
BuiltinProc_atomic_nand,
BuiltinProc_atomic_nand_acq,
BuiltinProc_atomic_nand_rel,
BuiltinProc_atomic_nand_acqrel,
BuiltinProc_atomic_nand_relaxed,
BuiltinProc_atomic_or,
BuiltinProc_atomic_or_acq,
BuiltinProc_atomic_or_rel,
BuiltinProc_atomic_or_acqrel,
BuiltinProc_atomic_or_relaxed,
BuiltinProc_atomic_xor,
BuiltinProc_atomic_xor_acq,
BuiltinProc_atomic_xor_rel,
BuiltinProc_atomic_xor_acqrel,
BuiltinProc_atomic_xor_relaxed,
BuiltinProc_atomic_xchg,
BuiltinProc_atomic_xchg_acq,
BuiltinProc_atomic_xchg_rel,
BuiltinProc_atomic_xchg_acqrel,
BuiltinProc_atomic_xchg_relaxed,
BuiltinProc_atomic_cxchg,
BuiltinProc_atomic_cxchg_acq,
BuiltinProc_atomic_cxchg_rel,
BuiltinProc_atomic_cxchg_acqrel,
BuiltinProc_atomic_cxchg_relaxed,
BuiltinProc_atomic_cxchg_failrelaxed,
BuiltinProc_atomic_cxchg_failacq,
BuiltinProc_atomic_cxchg_acq_failrelaxed,
BuiltinProc_atomic_cxchg_acqrel_failrelaxed,
BuiltinProc_atomic_cxchgweak,
BuiltinProc_atomic_cxchgweak_acq,
BuiltinProc_atomic_cxchgweak_rel,
BuiltinProc_atomic_cxchgweak_acqrel,
BuiltinProc_atomic_cxchgweak_relaxed,
BuiltinProc_atomic_cxchgweak_failrelaxed,
BuiltinProc_atomic_cxchgweak_failacq,
BuiltinProc_atomic_cxchgweak_acq_failrelaxed,
BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed,
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin},
{STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
// "Intrinsics"
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
};
// Operand is used as an intermediate value whilst checking // Operand is used as an intermediate value whilst checking
@@ -307,6 +97,7 @@ struct DeferredProcedure {
struct AttributeContext { struct AttributeContext {
bool is_export; bool is_export;
bool is_static; bool is_static;
bool require_results;
String link_name; String link_name;
String link_prefix; String link_prefix;
isize init_expr_list_count; isize init_expr_list_count;
@@ -431,6 +222,7 @@ struct ForeignContext {
typedef Array<Entity *> CheckerTypePath; typedef Array<Entity *> CheckerTypePath;
typedef Array<Type *> CheckerPolyPath; typedef Array<Type *> CheckerPolyPath;
// CheckerInfo stores all the symbol information for a type-checked program // CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo { struct CheckerInfo {
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
@@ -486,10 +278,14 @@ struct CheckerContext {
CheckerPolyPath *poly_path; CheckerPolyPath *poly_path;
isize poly_level; // TODO(bill): Actually handle correctly isize poly_level; // TODO(bill): Actually handle correctly
#define MAX_INLINE_FOR_DEPTH 1024ll
i64 inline_for_depth;
bool in_enum_type; bool in_enum_type;
bool collect_delayed_decls; bool collect_delayed_decls;
bool allow_polymorphic_types; bool allow_polymorphic_types;
bool no_polymorphic_errors; bool no_polymorphic_errors;
bool hide_polymorphic_errors;
bool in_polymorphic_specialization; bool in_polymorphic_specialization;
Scope * polymorphic_scope; Scope * polymorphic_scope;
}; };
+320
View File
@@ -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
View File
@@ -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
View File
@@ -48,7 +48,8 @@ enum EntityFlag {
EntityFlag_NotExported = 1<<14, EntityFlag_NotExported = 1<<14,
EntityFlag_Static = 1<<16, EntityFlag_Static = 1<<16,
// EntityFlag_Reference = 1<<17,
EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++
EntityFlag_CVarArg = 1<<20, EntityFlag_CVarArg = 1<<20,
EntityFlag_AutoCast = 1<<21, EntityFlag_AutoCast = 1<<21,
@@ -183,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
} }
String name = e->token.string; String name = e->token.string;
if (name.len == 0) { switch (name.len) {
return false; case 0: return false;
case 1: return name[0] != '_';
} }
return name[0] != '_'; return true;
} }
bool entity_has_deferred_procedure(Entity *e) { bool entity_has_deferred_procedure(Entity *e) {
@@ -219,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm
return entity; return entity;
} }
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) { Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
GB_ASSERT(parent != nullptr); GB_ASSERT(parent != nullptr);
token.pos = parent->token.pos; token.pos = parent->token.pos;
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type); Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
entity->using_parent = parent; entity->using_parent = parent;
entity->parent_proc_decl = parent->parent_proc_decl; entity->parent_proc_decl = parent->parent_proc_decl;
entity->using_expr = using_expr;
entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Used; entity->flags |= EntityFlag_Used;
entity->state = EntityState_Resolved; entity->state = EntityState_Resolved;
+249 -15
View File
@@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y);
struct Complex128 { struct Complex128 {
f64 real, imag; f64 real, imag;
}; };
struct Quaternion256 {
f64 imag, jmag, kmag, real;
};
Quaternion256 quaternion256_inverse(Quaternion256 x) {
f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
x.real = +x.real * invmag2;
x.imag = -x.imag * invmag2;
x.jmag = -x.jmag * invmag2;
x.kmag = -x.kmag * invmag2;
return x;
}
enum ExactValueKind { enum ExactValueKind {
ExactValue_Invalid, ExactValue_Invalid,
@@ -21,9 +34,11 @@ enum ExactValueKind {
ExactValue_Integer, ExactValue_Integer,
ExactValue_Float, ExactValue_Float,
ExactValue_Complex, ExactValue_Complex,
ExactValue_Quaternion,
ExactValue_Pointer, ExactValue_Pointer,
ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Compound, // TODO(bill): Is this good enough?
ExactValue_Procedure, // TODO(bill): Is this good enough? ExactValue_Procedure, // TODO(bill): Is this good enough?
ExactValue_Typeid,
ExactValue_Count, ExactValue_Count,
}; };
@@ -37,8 +52,10 @@ struct ExactValue {
f64 value_float; f64 value_float;
i64 value_pointer; i64 value_pointer;
Complex128 value_complex; Complex128 value_complex;
Quaternion256 value_quaternion;
Ast * value_compound; Ast * value_compound;
Ast * value_procedure; Ast * value_procedure;
Type * value_typeid;
}; };
}; };
@@ -53,25 +70,22 @@ HashKey hash_exact_value(ExactValue v) {
return hash_integer(u64(v.value_bool)); return hash_integer(u64(v.value_bool));
case ExactValue_String: case ExactValue_String:
return hash_string(v.value_string); return hash_string(v.value_string);
case ExactValue_Integer: { case ExactValue_Integer:
u64 *d = big_int_ptr(&v.value_integer); return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
u64 x = 0;
for (i32 i = 0; i < v.value_integer.len; i++) {
x |= d[i];
}
return hash_integer(x);
}
case ExactValue_Float: case ExactValue_Float:
return hash_f64(v.value_float); return hash_f64(v.value_float);
case ExactValue_Pointer: case ExactValue_Pointer:
return hash_integer(v.value_pointer); return hash_integer(v.value_pointer);
case ExactValue_Complex: case ExactValue_Complex:
return hashing_proc(&v.value_complex, gb_size_of(Complex128)); return hashing_proc(&v.value_complex, gb_size_of(Complex128));
case ExactValue_Quaternion:
return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
case ExactValue_Compound: case ExactValue_Compound:
return hash_pointer(v.value_compound); return hash_pointer(v.value_compound);
case ExactValue_Procedure: case ExactValue_Procedure:
return hash_pointer(v.value_procedure); return hash_pointer(v.value_procedure);
case ExactValue_Typeid:
return hash_pointer(v.value_typeid);
} }
return hashing_proc(&v, gb_size_of(ExactValue)); return hashing_proc(&v, gb_size_of(ExactValue));
@@ -122,6 +136,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
return result; return result;
} }
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion.real = real;
result.value_quaternion.imag = imag;
result.value_quaternion.jmag = jmag;
result.value_quaternion.kmag = kmag;
return result;
}
ExactValue exact_value_pointer(i64 ptr) { ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer}; ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr; result.value_pointer = ptr;
@@ -135,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) {
} }
ExactValue exact_value_typeid(Type *type) {
ExactValue result = {ExactValue_Typeid};
result.value_typeid = type;
return result;
}
ExactValue exact_value_integer_from_string(String const &string) { ExactValue exact_value_integer_from_string(String const &string) {
ExactValue result = {ExactValue_Integer}; ExactValue result = {ExactValue_Integer};
big_int_from_string(&result.value_integer, string); big_int_from_string(&result.value_integer, string);
@@ -259,14 +289,16 @@ ExactValue exact_value_from_basic_literal(Token token) {
str.len--; // Ignore the 'i|j|k' str.len--; // Ignore the 'i|j|k'
f64 imag = float_from_string(str); f64 imag = float_from_string(str);
if (last_rune == 'i') { switch (last_rune) {
return exact_value_complex(0, imag); case 'i': return exact_value_complex(0, imag);
case 'j': return exact_value_quaternion(0, 0, imag, 0);
case 'k': return exact_value_quaternion(0, 0, 0, imag);
default: GB_PANIC("Invalid imaginary basic literal");
} }
} }
case Token_Rune: { case Token_Rune: {
Rune r = GB_RUNE_INVALID; Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r); gb_utf8_decode(token.string.text, token.string.len, &r);
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
return exact_value_i64(r); return exact_value_i64(r);
} }
default: default:
@@ -324,11 +356,26 @@ ExactValue exact_value_to_complex(ExactValue v) {
return exact_value_complex(v.value_float, 0); return exact_value_complex(v.value_float, 0);
case ExactValue_Complex: case ExactValue_Complex:
return v; return v;
// case ExactValue_Quaternion:
// return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
case ExactValue_Float:
return exact_value_quaternion(v.value_float, 0, 0, 0);
case ExactValue_Complex:
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
case ExactValue_Quaternion:
return v;
} }
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
} }
ExactValue exact_value_real(ExactValue v) { ExactValue exact_value_real(ExactValue v) {
switch (v.kind) { switch (v.kind) {
@@ -337,6 +384,8 @@ ExactValue exact_value_real(ExactValue v) {
return v; return v;
case ExactValue_Complex: case ExactValue_Complex:
return exact_value_float(v.value_complex.real); return exact_value_float(v.value_complex.real);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.real);
} }
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
@@ -349,6 +398,34 @@ ExactValue exact_value_imag(ExactValue v) {
return exact_value_i64(0); return exact_value_i64(0);
case ExactValue_Complex: case ExactValue_Complex:
return exact_value_float(v.value_complex.imag); return exact_value_float(v.value_complex.imag);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.imag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_i64(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.jmag);
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
case ExactValue_Complex:
return exact_value_i64(0);
case ExactValue_Quaternion:
return exact_value_float(v.value_quaternion.kmag);
} }
ExactValue r = {ExactValue_Invalid}; ExactValue r = {ExactValue_Invalid};
return r; return r;
@@ -367,6 +444,32 @@ ExactValue exact_value_make_imag(ExactValue v) {
return r; return r;
} }
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
i64 exact_value_to_i64(ExactValue v) { i64 exact_value_to_i64(ExactValue v) {
v = exact_value_to_integer(v); v = exact_value_to_integer(v);
if (v.kind == ExactValue_Integer) { if (v.kind == ExactValue_Integer) {
@@ -395,6 +498,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
case ExactValue_Integer: case ExactValue_Integer:
case ExactValue_Float: case ExactValue_Float:
case ExactValue_Complex: case ExactValue_Complex:
case ExactValue_Quaternion:
return v; return v;
} }
break; break;
@@ -419,6 +523,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
f64 imag = v.value_complex.imag; f64 imag = v.value_complex.imag;
return exact_value_complex(-real, -imag); return exact_value_complex(-real, -imag);
} }
case ExactValue_Quaternion: {
f64 real = v.value_quaternion.real;
f64 imag = v.value_quaternion.imag;
f64 jmag = v.value_quaternion.jmag;
f64 kmag = v.value_quaternion.kmag;
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
}
} }
break; break;
} }
@@ -469,8 +580,10 @@ i32 exact_value_order(ExactValue const &v) {
return 3; return 3;
case ExactValue_Complex: case ExactValue_Complex:
return 4; return 4;
case ExactValue_Pointer: case ExactValue_Quaternion:
return 5; return 5;
case ExactValue_Pointer:
return 6;
default: default:
GB_PANIC("How'd you get here? Invalid Value.kind"); GB_PANIC("How'd you get here? Invalid Value.kind");
@@ -491,7 +604,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Bool: case ExactValue_Bool:
case ExactValue_String: case ExactValue_String:
case ExactValue_Complex: case ExactValue_Quaternion:
return; return;
case ExactValue_Integer: case ExactValue_Integer:
@@ -505,6 +618,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex: case ExactValue_Complex:
*x = exact_value_complex(big_int_to_f64(&x->value_integer), 0); *x = exact_value_complex(big_int_to_f64(&x->value_integer), 0);
return; return;
case ExactValue_Quaternion:
*x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0);
return;
} }
break; break;
@@ -515,6 +631,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
case ExactValue_Complex: case ExactValue_Complex:
*x = exact_value_to_complex(*x); *x = exact_value_to_complex(*x);
return; return;
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
}
break;
case ExactValue_Complex:
switch (y->kind) {
case ExactValue_Quaternion:
*x = exact_value_to_quaternion(*x);
return;
} }
break; break;
} }
@@ -612,6 +739,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
break; break;
} }
case ExactValue_Quaternion: {
y = exact_value_to_quaternion(y);
f64 xr = x.value_quaternion.real;
f64 xi = x.value_quaternion.imag;
f64 xj = x.value_quaternion.jmag;
f64 xk = x.value_quaternion.kmag;
f64 yr = y.value_quaternion.real;
f64 yi = y.value_quaternion.imag;
f64 yj = y.value_quaternion.jmag;
f64 yk = y.value_quaternion.kmag;
f64 real = 0;
f64 imag = 0;
f64 jmag = 0;
f64 kmag = 0;
switch (op) {
case Token_Add:
real = xr + yr;
imag = xi + yi;
jmag = xj + yj;
kmag = xk + yk;
break;
case Token_Sub:
real = xr - yr;
imag = xi - yi;
jmag = xj - yj;
kmag = xk - yk;
break;
case Token_Mul:
imag = xr * yi + xi * yr + xj * yk - xk * yj;
jmag = xr * yj - xi * yk + xj * yr + xk * yi;
kmag = xr * yk + xi * yj - xj * yi + xk * yr;
real = xr * yr - xi * yi - xj * yj - xk * yk;
break;
case Token_Quo: {
f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk);
imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2;
jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2;
kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2;
real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2;
break;
}
default: goto error;
}
return exact_value_quaternion(real, imag, jmag, kmag);
break;
}
case ExactValue_String: { case ExactValue_String: {
if (op != Token_Add) goto error; if (op != Token_Add) goto error;
@@ -647,6 +824,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV
return exact_binary_operator_value(op, x, y); return exact_binary_operator_value(op, x, y);
} }
gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
}
i32 cmp_f64(f64 a, f64 b) { i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b); return (a > b) - (a < b);
@@ -719,8 +900,61 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
} }
break; break;
} }
case ExactValue_Typeid:
switch (op) {
case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid);
case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid);
}
break;
} }
GB_PANIC("Invalid comparison"); GB_PANIC("Invalid comparison");
return false; return false;
} }
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
switch (v.kind) {
case ExactValue_Invalid:
return str;
case ExactValue_Bool:
return gb_string_appendc(str, v.value_bool ? "true" : "false");
case ExactValue_String: {
String s = quote_to_ascii(heap_allocator(), v.value_string);
string_limit = gb_max(string_limit, 36);
if (s.len <= string_limit) {
str = gb_string_append_length(str, s.text, s.len);
} else {
isize n = string_limit/5;
str = gb_string_append_length(str, s.text, n);
str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n));
str = gb_string_append_length(str, s.text+s.len-n, n);
}
gb_free(heap_allocator(), s.text);
return str;
}
case ExactValue_Integer: {
String s = big_int_to_string(heap_allocator(), &v.value_integer);
str = gb_string_append_length(str, s.text, s.len);
gb_free(heap_allocator(), s.text);
return str;
}
case ExactValue_Float:
return gb_string_append_fmt(str, "%f", v.value_float);
case ExactValue_Complex:
return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag);
case ExactValue_Pointer:
return str;
case ExactValue_Compound:
return str;
case ExactValue_Procedure:
return str;
}
return str;
};
gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
}
+15 -7
View File
@@ -930,7 +930,7 @@ typedef struct gbSemaphore { sem_t unix_handle; } gbSemaphore;
GB_DEF void gb_semaphore_init (gbSemaphore *s); GB_DEF void gb_semaphore_init (gbSemaphore *s);
GB_DEF void gb_semaphore_destroy(gbSemaphore *s); GB_DEF void gb_semaphore_destroy(gbSemaphore *s);
GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count); GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count);
GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1) GB_DEF void gb_semaphore_release(gbSemaphore *s);
GB_DEF void gb_semaphore_wait (gbSemaphore *s); GB_DEF void gb_semaphore_wait (gbSemaphore *s);
@@ -978,7 +978,7 @@ typedef struct gbThread {
gbThreadProc * proc; gbThreadProc * proc;
void * user_data; void * user_data;
isize user_index; isize user_index;
isize return_value; isize volatile return_value;
gbSemaphore semaphore; gbSemaphore semaphore;
isize stack_size; isize stack_size;
@@ -4588,10 +4588,18 @@ gb_inline void gb_lfence(void) {
gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); } gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); }
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); } gb_inline void gb_semaphore_init(gbSemaphore *s) {
gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); } s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } }
gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } gb_inline void gb_semaphore_destroy(gbSemaphore *s) {
CloseHandle(s->win32_handle);
}
gb_inline void gb_semaphore_post(gbSemaphore *s, i32 count) {
ReleaseSemaphore(s->win32_handle, count, NULL);
}
gb_inline void gb_semaphore_wait(gbSemaphore *s) {
WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
}
#elif defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_OSX)
gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
@@ -8975,7 +8983,7 @@ gb_inline void gb_exit(u32 code) { exit(code); }
gb_inline void gb_yield(void) { gb_inline void gb_yield(void) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
Sleep(0); YieldProcessor();
#else #else
sched_yield(); sched_yield();
#endif #endif
+796 -99
View File
File diff suppressed because it is too large. Load diff
+201 -25
View File
@@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
set_procedure_abi_types(heap_allocator(), t);
i64 word_bits = 8*build_context.word_size; i64 word_bits = 8*build_context.word_size;
t = base_type(t); t = base_type(t);
GB_ASSERT(is_type_proc(t)); GB_ASSERT(is_type_proc(t));
isize param_count = t->Proc.param_count; isize param_count = t->Proc.param_count;
isize result_count = t->Proc.result_count; isize result_count = t->Proc.result_count;
ir_print_proc_results(f, m, t); ir_print_proc_results(f, m, t);
ir_write_string(f, str_lit(" (")); ir_write_string(f, str_lit(" ("));
if (t->Proc.return_by_pointer) { if (t->Proc.return_by_pointer) {
@@ -426,6 +429,9 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return;
case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return;
case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return;
case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return;
case Basic_any: ir_write_str_lit(f, "%..any"); return; case Basic_any: ir_write_str_lit(f, "%..any"); return;
case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return;
case Basic_string: ir_write_str_lit(f, "%..string"); return; case Basic_string: ir_write_str_lit(f, "%..string"); return;
@@ -767,15 +773,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
case ExactValue_Float: { case ExactValue_Float: {
GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type)); GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type));
type = core_type(type); type = core_type(type);
u64 u = bit_cast<u64>(value.value_float); u64 u_64 = bit_cast<u64>(value.value_float);
u32 u_32 = bit_cast<u32>(cast(f32)value.value_float);
#if 0
switch (type->Basic.kind) { switch (type->Basic.kind) {
case Basic_f32: case Basic_f32:
// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
// a 64 bit number if bits_of(float type) <= 64. // a 64 bit number if bits_of(float type) <= 64.
// https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
// 64 bit mantissa: 52 bits // 64 bit mantissa: 52 bits ==> 52-52 == 0
// 32 bit mantissa: 23 bits // 32 bit mantissa: 23 bits ==> 52-23 == 29
// 16 bit mantissa: 10 bits // 16 bit mantissa: 10 bits ==> 52=10 == 42
// 29 == 52-23 // 29 == 52-23
u >>= 29; u >>= 29;
u <<= 29; u <<= 29;
@@ -792,9 +800,24 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_fprintf(f, "0x%016llx", u); ir_fprintf(f, "0x%016llx", u);
break; break;
} }
#else
switch (type->Basic.kind) {
case Basic_f32: {
ir_fprintf(f, "bitcast (i32 %u to float)", u_32);
break;
}
case Basic_f64:
ir_fprintf(f, "0x%016llx", u_64);
break;
default:
ir_fprintf(f, "0x%016llx", u_64);
break;
}
#endif
break; break;
} }
case ExactValue_Complex: { case ExactValue_Complex: {
// xy/ri format
type = core_type(type); type = core_type(type);
GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type)); GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type); Type *ft = base_complex_elem_type(type);
@@ -807,6 +830,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_byte(f, '}'); ir_write_byte(f, '}');
break; break;
} }
case ExactValue_Quaternion: {
// xyzw/ijkr format
type = core_type(type);
GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type));
Type *ft = base_complex_elem_type(type);
ir_write_byte(f, ' ');
ir_write_byte(f, '{');
ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
ir_write_byte(f, '}');
break;
}
case ExactValue_Pointer: case ExactValue_Pointer:
if (value.value_pointer == 0) { if (value.value_pointer == 0) {
if (is_type_typeid(type)) { if (is_type_typeid(type)) {
@@ -836,6 +879,69 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
ir_write_str_lit(f, "zeroinitializer"); ir_write_str_lit(f, "zeroinitializer");
break; break;
} }
if (cl->elems[0]->kind == Ast_FieldValue) {
// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
ir_write_byte(f, '[');
for (i64 i = 0; i < type->Array.count; i++) {
if (i > 0) ir_write_str_lit(f, ", ");
bool found = false;
for (isize j = 0; j < elem_count; j++) {
Ast *elem = cl->elems[j];
ast_node(fv, FieldValue, elem);
if (is_ast_range(fv->field)) {
ast_node(ie, BinaryExpr, fv->field);
TypeAndValue lo_tav = ie->left->tav;
TypeAndValue hi_tav = ie->right->tav;
GB_ASSERT(lo_tav.mode == Addressing_Constant);
GB_ASSERT(hi_tav.mode == Addressing_Constant);
TokenKind op = ie->op.kind;
i64 lo = exact_value_to_i64(lo_tav.value);
i64 hi = exact_value_to_i64(hi_tav.value);
if (op == Token_Ellipsis) {
hi += 1;
}
if (lo == i) {
TypeAndValue tav = fv->value->tav;
if (tav.mode != Addressing_Constant) {
break;
}
for (i64 k = lo; k < hi; k++) {
if (k > lo) ir_write_str_lit(f, ", ");
ir_print_compound_element(f, m, tav.value, elem_type);
}
found = true;
i += (hi-lo-1);
break;
}
} else {
TypeAndValue index_tav = fv->field->tav;
GB_ASSERT(index_tav.mode == Addressing_Constant);
i64 index = exact_value_to_i64(index_tav.value);
if (index == i) {
TypeAndValue tav = fv->value->tav;
if (tav.mode != Addressing_Constant) {
break;
}
ir_print_compound_element(f, m, tav.value, elem_type);
found = true;
break;
}
}
}
if (!found) {
ir_print_type(f, m, elem_type);
ir_write_byte(f, ' ');
ir_write_str_lit(f, "zeroinitializer");
}
}
ir_write_byte(f, ']');
} else {
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
ir_write_byte(f, '['); ir_write_byte(f, '[');
@@ -852,6 +958,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
} }
ir_write_byte(f, ']'); ir_write_byte(f, ']');
}
} else if (is_type_simd_vector(type)) { } else if (is_type_simd_vector(type)) {
ast_node(cl, CompoundLit, value.value_compound); ast_node(cl, CompoundLit, value.value_compound);
@@ -927,7 +1034,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
if (type->Struct.is_packed) ir_write_byte(f, '<'); if (type->Struct.is_packed) ir_write_byte(f, '<');
ir_write_byte(f, '{'); ir_write_byte(f, '{');
if (type->Struct.custom_align > 0) { if (type->Struct.custom_align > 0) {
ir_fprintf(f, "[0 x <%lld x i8>] zeroinitializer", cast(i64)type->Struct.custom_align); ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align);
ir_write_str_lit(f, " zeroinitializer");
if (value_count > 0) { if (value_count > 0) {
ir_write_string(f, str_lit(", ")); ir_write_string(f, str_lit(", "));
} }
@@ -1089,7 +1197,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
break; break;
} }
case irValue_Param: case irValue_Param:
if (value->Param.index >= 0) {
ir_fprintf(f, "%%_.%d", value->Param.index);
} else {
ir_print_encoded_local(f, value->Param.entity->token.string); ir_print_encoded_local(f, value->Param.entity->token.string);
}
break; break;
case irValue_SourceCodeLocation: { case irValue_SourceCodeLocation: {
irValue *file = value->SourceCodeLocation.file; irValue *file = value->SourceCodeLocation.file;
@@ -1124,7 +1236,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
switch (cc) { switch (cc) {
case ProcCC_Odin: ir_write_str_lit(f, ""); break; case ProcCC_Odin: ir_write_str_lit(f, ""); break;
case ProcCC_Contextless: ir_write_str_lit(f, ""); break; case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break; // case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break; case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break; case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
case ProcCC_None: ir_write_str_lit(f, ""); break; case ProcCC_None: ir_write_str_lit(f, ""); break;
@@ -1134,8 +1247,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) { void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) {
ir_print_type(f, m, t_context_ptr); ir_print_type(f, m, t_context_ptr);
ir_write_str_lit(f, " noalias nonnull nocapture inreg "); // ir_write_str_lit(f, " noalias nonnull nocapture inreg ");
// ir_write_str_lit(f, " noalias nonnull nocapture "); ir_write_str_lit(f, " noalias nonnull nocapture ");
} }
void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
@@ -1186,6 +1299,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_write_str_lit(f, ", "); ir_write_str_lit(f, ", ");
ir_print_type(f, m, type); ir_print_type(f, m, type);
ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index); ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index);
// ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index);
break; break;
} }
@@ -1888,11 +2002,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
if (e->flags&EntityFlag_NoAlias) { if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias"); ir_write_str_lit(f, " noalias");
} }
if (e->flags&EntityFlag_ImplicitReference) {
ir_write_str_lit(f, " nonnull dereferenceable");
}
ir_write_byte(f, ' '); ir_write_byte(f, ' ');
irValue *arg = call->args[i]; irValue *arg = call->args[i];
if (is_type_boolean(t)) {
}
ir_print_value(f, m, arg, t); ir_print_value(f, m, arg, t);
param_index++; param_index++;
} }
@@ -1907,17 +2021,35 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
param_index++; param_index++;
} }
} else { } else {
GB_ASSERT(call->args.count == params->variables.count); // GB_ASSERT(call->args.count == params->variables.count);
isize arg_index = 0;
for_array(i, params->variables) { for_array(i, params->variables) {
Entity *e = params->variables[i]; Entity *e = params->variables[i];
GB_ASSERT(e != nullptr); GB_ASSERT(e != nullptr);
if (e->kind != Entity_Variable) continue; if (e->kind != Entity_Variable) {
arg_index++;
continue;
}
if (param_index > 0) ir_write_str_lit(f, ", "); if (param_index > 0) ir_write_str_lit(f, ", ");
irValue *arg = call->args[i];
Type *t = proc_type->Proc.abi_compat_params[i]; Type *t = proc_type->Proc.abi_compat_params[i];
if (is_type_tuple(t)) {
for_array(j, t->Tuple.variables) {
if (j > 0) ir_write_str_lit(f, ", ");
irValue *arg = call->args[arg_index++];
ir_print_type(f, m, t->Tuple.variables[j]->type);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
ir_write_byte(f, ' ');
ir_print_value(f, m, arg, t);
param_index++;
}
} else {
irValue *arg = call->args[arg_index++];
ir_print_type(f, m, t); ir_print_type(f, m, t);
if (e->flags&EntityFlag_NoAlias) { if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias"); ir_write_str_lit(f, " noalias");
@@ -1928,6 +2060,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
} }
} }
} }
}
if (proc_type->Proc.calling_convention == ProcCC_Odin) { if (proc_type->Proc.calling_convention == ProcCC_Odin) {
if (param_index > 0) ir_write_str_lit(f, ", "); if (param_index > 0) ir_write_str_lit(f, ", ");
@@ -1995,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
set_procedure_abi_types(heap_allocator(), proc->type);
if (proc->body == nullptr) { if (proc->body == nullptr) {
ir_write_str_lit(f, "declare "); ir_write_str_lit(f, "declare ");
// if (proc->tags & ProcTag_dll_import) { // if (proc->tags & ProcTag_dll_import) {
@@ -2043,7 +2178,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (param_count > 0) { if (param_count > 0) {
TypeTuple *params = &proc_type->params->Tuple; TypeTuple *params = &proc_type->params->Tuple;
for (isize i = 0; i < param_count; i++) { isize parameter_index = 0;
for (isize i = 0; i < param_count; i++, parameter_index++) {
Entity *e = params->variables[i]; Entity *e = params->variables[i];
Type *original_type = e->type; Type *original_type = e->type;
Type *abi_type = proc_type->abi_compat_params[i]; Type *abi_type = proc_type->abi_compat_params[i];
@@ -2052,17 +2188,30 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
if (i+1 == params->variables.count && proc_type->c_vararg) { if (i+1 == params->variables.count && proc_type->c_vararg) {
ir_write_str_lit(f, " ..."); ir_write_str_lit(f, " ...");
} else {
if (is_type_tuple(abi_type)) {
for_array(j, abi_type->Tuple.variables) {
if (j > 0) ir_write_string(f, str_lit(", "));
Type *tft = abi_type->Tuple.variables[j]->type;
ir_print_type(f, m, tft);
if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias");
}
if (proc->body != nullptr) {
ir_fprintf(f, " %%_.%td", parameter_index+j);
}
}
parameter_index += abi_type->Tuple.variables.count-1;
param_index += abi_type->Tuple.variables.count-1;
} else { } else {
ir_print_type(f, m, abi_type); ir_print_type(f, m, abi_type);
if (e->flags&EntityFlag_NoAlias) { if (e->flags&EntityFlag_NoAlias) {
ir_write_str_lit(f, " noalias"); ir_write_str_lit(f, " noalias");
} }
if (proc->body != nullptr) { if (proc->body != nullptr) {
if (e->token.string != "" && !is_blank_ident(e->token)) { ir_fprintf(f, " %%_.%td", parameter_index);
ir_write_byte(f, ' ');
ir_print_encoded_local(f, e->token.string);
} else {
ir_fprintf(f, " %%_.param_%td", i);
} }
} }
} }
@@ -2176,6 +2325,22 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) {
ir_write_byte(f, '\n'); ir_write_byte(f, '\n');
} }
bool ir_print_global_type_allowed(Type *t) {
if (t == nullptr) {
return true;
}
t = core_type(t);
switch (t->kind) {
case Type_DynamicArray:
case Type_Map:
case Type_Union:
case Type_BitField:
return false;
}
return true;
}
void print_llvm_ir(irGen *ir) { void print_llvm_ir(irGen *ir) {
irModule *m = &ir->module; irModule *m = &ir->module;
@@ -2184,9 +2349,11 @@ void print_llvm_ir(irGen *ir) {
defer (ir_file_buffer_destroy(f)); defer (ir_file_buffer_destroy(f));
i32 word_bits = cast(i32)(8*build_context.word_size); i32 word_bits = cast(i32)(8*build_context.word_size);
if (build_context.ODIN_OS == "osx" || build_context.ODIN_OS == "macos") { if (build_context.ODIN_OS == "darwin") {
GB_ASSERT(word_bits == 64); GB_ASSERT(word_bits == 64);
ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n\n"); ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n");
ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n");
ir_write_str_lit(f, "\n");
} else if (build_context.ODIN_OS == "windows") { } else if (build_context.ODIN_OS == "windows") {
ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : ""); ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : "");
if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) { if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) {
@@ -2210,6 +2377,13 @@ void print_llvm_ir(irGen *ir) {
ir_print_encoded_local(f, str_lit("..complex128")); ir_print_encoded_local(f, str_lit("..complex128"));
ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n"); ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n");
ir_print_encoded_local(f, str_lit("..quaternion64"));
ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n");
ir_print_encoded_local(f, str_lit("..quaternion128"));
ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n");
ir_print_encoded_local(f, str_lit("..quaternion256"));
ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n");
ir_print_encoded_local(f, str_lit("..typeid")); ir_print_encoded_local(f, str_lit("..typeid"));
ir_write_str_lit(f, " = type "); ir_write_str_lit(f, " = type ");
ir_print_type(f, m, t_uintptr); ir_print_type(f, m, t_uintptr);
@@ -2339,7 +2513,7 @@ void print_llvm_ir(irGen *ir) {
ir_print_type(f, m, g->entity->type); ir_print_type(f, m, g->entity->type);
ir_write_byte(f, ' '); ir_write_byte(f, ' ');
if (!g->is_foreign) { if (!g->is_foreign) {
if (g->value != nullptr) { if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) {
ir_print_value(f, m, g->value, g->entity->type); ir_print_value(f, m, g->value, g->entity->type);
} else { } else {
ir_write_string(f, str_lit("zeroinitializer")); ir_write_string(f, str_lit("zeroinitializer"));
@@ -2383,11 +2557,13 @@ void print_llvm_ir(irGen *ir) {
for_array(di_index, m->debug_info.entries) { for_array(di_index, m->debug_info.entries) {
irDebugInfo *di = m->debug_info.entries[di_index].value; irDebugInfo *di = m->debug_info.entries[di_index].value;
GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo");
ir_fprintf(f, "!%d = ", di->id); ir_fprintf(f, "!%d = ", di->id);
switch (di->kind) { switch (di->kind) {
case irDebugInfo_CompileUnit: { case irDebugInfo_CompileUnit: {
irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file));
GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath));
irDebugInfo *file = *found;
ir_fprintf(f, ir_fprintf(f,
"distinct !DICompileUnit(" "distinct !DICompileUnit("
"language: DW_LANG_C_plus_plus" // Is this good enough? "language: DW_LANG_C_plus_plus" // Is this good enough?
+53 -58
View File
@@ -160,8 +160,9 @@ void usage(String argv0) {
print_usage_line(0, "Usage:"); print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:"); print_usage_line(0, "Commands:");
print_usage_line(1, "build compile .odin file as executable"); print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable.");
print_usage_line(1, "run compile and run .odin file"); print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse and type check .odin file"); print_usage_line(1, "check parse and type check .odin file");
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program"); print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "docs generate documentation for a .odin file"); print_usage_line(1, "docs generate documentation for a .odin file");
@@ -210,9 +211,8 @@ enum BuildFlagKind {
BuildFlag_Collection, BuildFlag_Collection,
BuildFlag_Define, BuildFlag_Define,
BuildFlag_BuildMode, BuildFlag_BuildMode,
BuildFlag_Target,
BuildFlag_Debug, BuildFlag_Debug,
BuildFlag_CrossCompile,
BuildFlag_CrossLibDir,
BuildFlag_NoBoundsCheck, BuildFlag_NoBoundsCheck,
BuildFlag_NoCRT, BuildFlag_NoCRT,
BuildFlag_UseLLD, BuildFlag_UseLLD,
@@ -298,9 +298,8 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None);
@@ -447,7 +446,7 @@ bool parse_build_flags(Array<String> args) {
path = substring(path, 0, string_extension_position(path)); path = substring(path, 0, string_extension_position(path));
} }
#endif #endif
build_context.out_filepath = path; build_context.out_filepath = path_to_full_path(heap_allocator(), path);
} else { } else {
gb_printf_err("Invalid -out path, got %.*s\n", LIT(path)); gb_printf_err("Invalid -out path, got %.*s\n", LIT(path));
bad_flags = true; bad_flags = true;
@@ -478,33 +477,6 @@ bool parse_build_flags(Array<String> args) {
build_context.keep_temp_files = true; build_context.keep_temp_files = true;
break; break;
case BuildFlag_CrossCompile: {
GB_ASSERT(value.kind == ExactValue_String);
cross_compile_target = value.value_string;
#if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT)
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
} else
#endif
{
gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
bad_flags = true;
}
break;
}
case BuildFlag_CrossLibDir: {
GB_ASSERT(value.kind == ExactValue_String);
if (cross_compile_lib_dir.len) {
gb_printf_err("Multiple cross compilation library directories\n");
bad_flags = true;
} else {
cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
}
break;
}
case BuildFlag_Collection: { case BuildFlag_Collection: {
GB_ASSERT(value.kind == ExactValue_String); GB_ASSERT(value.kind == ExactValue_String);
String str = value.value_string; String str = value.value_string;
@@ -623,7 +595,25 @@ bool parse_build_flags(Array<String> args) {
break; break;
} }
case BuildFlag_Target: {
String str = value.value_string;
bool found = false;
for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) {
if (str_eq_ignore_case(str, named_targets[i].name)) {
found = true;
selected_target_metrics = named_targets + i;
break;
}
}
if (!found) {
gb_printf_err("Unknown target '%.*s'\n", LIT(str));
bad_flags = true;
}
break;
}
case BuildFlag_BuildMode: { case BuildFlag_BuildMode: {
GB_ASSERT(value.kind == ExactValue_String); GB_ASSERT(value.kind == ExactValue_String);
@@ -635,7 +625,7 @@ bool parse_build_flags(Array<String> args) {
break; break;
} }
if (str == "dll") { if (str == "dll" || str == "shared") {
build_context.is_dll = true; build_context.is_dll = true;
} else if (str == "exe") { } else if (str == "exe") {
build_context.is_dll = false; build_context.is_dll = false;
@@ -889,8 +879,8 @@ i32 exec_llvm_opt(String output_base) {
} }
i32 exec_llvm_llc(String output_base) { i32 exec_llvm_llc(String output_base) {
#if defined(GB_SYSTEM_WINDOWS)
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html // For more arguments: http://llvm.org/docs/CommandGuide/llc.html
#if defined(GB_SYSTEM_WINDOWS)
return system_exec_command_line_app("llvm-llc", return system_exec_command_line_app("llvm-llc",
"\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d " "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d "
"-o \"%.*s.obj\" " "-o \"%.*s.obj\" "
@@ -903,21 +893,19 @@ i32 exec_llvm_llc(String output_base) {
LIT(build_context.llc_flags)); LIT(build_context.llc_flags));
#else #else
// NOTE(zangent): Linux / Unix is unfinished and not tested very well. // NOTE(zangent): Linux / Unix is unfinished and not tested very well.
// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
return system_exec_command_line_app("llc", return system_exec_command_line_app("llc",
"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
"%.*s " "%.*s "
"%s" "%s%.*s",
"",
LIT(output_base), LIT(output_base),
build_context.optimization_level, build_context.optimization_level,
LIT(build_context.llc_flags), LIT(build_context.llc_flags),
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : ""); build_context.cross_compiling ? "-mtriple=" : "",
(int) (build_context.cross_compiling ? build_context.target_triplet.len : 0),
build_context.target_triplet.text);
#endif #endif
} }
int main(int arg_count, char **arg_ptr) { int main(int arg_count, char **arg_ptr) {
if (arg_count < 2) { if (arg_count < 2) {
usage(make_string_c(arg_ptr[0])); usage(make_string_c(arg_ptr[0]));
@@ -1026,7 +1014,7 @@ int main(int arg_count, char **arg_ptr) {
} }
init_build_context(); init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr);
if (build_context.word_size == 4) { if (build_context.word_size == 4) {
print_usage_line(0, "%s 32-bit is not yet supported", args[0]); print_usage_line(0, "%s 32-bit is not yet supported", args[0]);
return 1; return 1;
@@ -1121,6 +1109,17 @@ int main(int arg_count, char **arg_ptr) {
return exit_code; return exit_code;
} }
if (build_context.cross_compiling) {
if (0) {
#ifdef GB_SYSTEM_UNIX
} else if (selected_target_metrics->metrics == &target_essence_amd64) {
system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s",
LIT(output_base), LIT(output_base), LIT(build_context.link_flags));
#endif
} else {
gb_printf_err("Don't know how to cross compile to selected target.\n");
}
} else {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
timings_start_section(&timings, str_lit("msvc-link")); timings_start_section(&timings, str_lit("msvc-link"));
@@ -1219,7 +1218,7 @@ int main(int arg_count, char **arg_ptr) {
remove_temp_files(output_base); remove_temp_files(output_base);
if (run_output) { if (run_output) {
system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string));
} }
#else #else
timings_start_section(&timings, str_lit("ld-link")); timings_start_section(&timings, str_lit("ld-link"));
@@ -1241,15 +1240,17 @@ int main(int arg_count, char **arg_ptr) {
// This allows you to specify '-f' in a #foreign_system_library, // This allows you to specify '-f' in a #foreign_system_library,
// without having to implement any new syntax specifically for MacOS. // without having to implement any new syntax specifically for MacOS.
#if defined(GB_SYSTEM_OSX) #if defined(GB_SYSTEM_OSX)
if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { if (string_ends_with(lib, str_lit(".framework"))) {
// framework thingie // framework thingie
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); String lib_name = lib;
lib_name = remove_extension_from_path(lib_name);
lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name));
} else if (string_ends_with(lib, str_lit(".a"))) { } else if (string_ends_with(lib, str_lit(".a"))) {
// static libs, absolute full path relative to the file in which the lib was imported from // static libs, absolute full path relative to the file in which the lib was imported from
lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
} else if (string_ends_with(lib, str_lit(".dylib"))) { } else if (string_ends_with(lib, str_lit(".dylib"))) {
// dynamic lib, relative path to executable // dynamic lib
lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
} else { } else {
// dynamic or static system lib, just link regularly searching system library paths // dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -1309,11 +1310,7 @@ int main(int arg_count, char **arg_ptr) {
// It probably has to do with including the entire CRT, but // It probably has to do with including the entire CRT, but
// that's quite a complicated issue to solve while remaining distro-agnostic. // that's quite a complicated issue to solve while remaining distro-agnostic.
// Clang can figure out linker flags for us, and that's good enough _for now_. // Clang can figure out linker flags for us, and that's good enough _for now_.
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
} else {
linker = "clang -Wno-unused-command-line-argument"; linker = "clang -Wno-unused-command-line-argument";
}
#endif #endif
exit_code = system_exec_command_line_app("ld-link", exit_code = system_exec_command_line_app("ld-link",
@@ -1321,7 +1318,6 @@ int main(int arg_count, char **arg_ptr) {
" %s " " %s "
" %.*s " " %.*s "
" %s " " %s "
" %.*s "
#if defined(GB_SYSTEM_OSX) #if defined(GB_SYSTEM_OSX)
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
// NOTE: If you change this (although this minimum is as low as you can go with Odin working) // NOTE: If you change this (although this minimum is as low as you can go with Odin working)
@@ -1332,11 +1328,9 @@ int main(int arg_count, char **arg_ptr) {
#endif #endif
, linker, LIT(output_base), LIT(output_base), LIT(output_ext), , linker, LIT(output_base), LIT(output_base), LIT(output_ext),
lib_str, lib_str,
str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm", "-lc -lm",
LIT(build_context.link_flags), LIT(build_context.link_flags),
link_settings, link_settings);
LIT(cross_compile_lib_dir)
);
if (exit_code != 0) { if (exit_code != 0) {
return exit_code; return exit_code;
} }
@@ -1366,9 +1360,10 @@ int main(int arg_count, char **arg_ptr) {
//NOTE(thebirk): This whole thing is a little leaky //NOTE(thebirk): This whole thing is a little leaky
String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext);
complete_path = path_to_full_path(heap_allocator(), complete_path); complete_path = path_to_full_path(heap_allocator(), complete_path);
system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string));
} }
#endif #endif
}
return 0; return 0;
} }
+286 -208
View File
@@ -51,6 +51,7 @@ Token ast_token(Ast *node) {
case Ast_ReturnStmt: return node->ReturnStmt.token; case Ast_ReturnStmt: return node->ReturnStmt.token;
case Ast_ForStmt: return node->ForStmt.token; case Ast_ForStmt: return node->ForStmt.token;
case Ast_RangeStmt: return node->RangeStmt.token; case Ast_RangeStmt: return node->RangeStmt.token;
case Ast_InlineRangeStmt: return node->InlineRangeStmt.inline_token;
case Ast_CaseClause: return node->CaseClause.token; case Ast_CaseClause: return node->CaseClause.token;
case Ast_SwitchStmt: return node->SwitchStmt.token; case Ast_SwitchStmt: return node->SwitchStmt.token;
case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
@@ -143,6 +144,7 @@ Ast *clone_ast(Ast *node) {
case Ast_ProcLit: case Ast_ProcLit:
n->ProcLit.type = clone_ast(n->ProcLit.type); n->ProcLit.type = clone_ast(n->ProcLit.type);
n->ProcLit.body = clone_ast(n->ProcLit.body); n->ProcLit.body = clone_ast(n->ProcLit.body);
n->ProcLit.where_clauses = clone_ast_array(n->ProcLit.where_clauses);
break; break;
case Ast_CompoundLit: case Ast_CompoundLit:
n->CompoundLit.type = clone_ast(n->CompoundLit.type); n->CompoundLit.type = clone_ast(n->CompoundLit.type);
@@ -257,6 +259,12 @@ Ast *clone_ast(Ast *node) {
n->RangeStmt.expr = clone_ast(n->RangeStmt.expr); n->RangeStmt.expr = clone_ast(n->RangeStmt.expr);
n->RangeStmt.body = clone_ast(n->RangeStmt.body); n->RangeStmt.body = clone_ast(n->RangeStmt.body);
break; break;
case Ast_InlineRangeStmt:
n->InlineRangeStmt.val0 = clone_ast(n->InlineRangeStmt.val0);
n->InlineRangeStmt.val1 = clone_ast(n->InlineRangeStmt.val1);
n->InlineRangeStmt.expr = clone_ast(n->InlineRangeStmt.expr);
n->InlineRangeStmt.body = clone_ast(n->InlineRangeStmt.body);
break;
case Ast_CaseClause: case Ast_CaseClause:
n->CaseClause.list = clone_ast_array(n->CaseClause.list); n->CaseClause.list = clone_ast_array(n->CaseClause.list);
n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts); n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts);
@@ -341,10 +349,12 @@ Ast *clone_ast(Ast *node) {
n->StructType.fields = clone_ast_array(n->StructType.fields); n->StructType.fields = clone_ast_array(n->StructType.fields);
n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params); n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params);
n->StructType.align = clone_ast(n->StructType.align); n->StructType.align = clone_ast(n->StructType.align);
n->StructType.where_clauses = clone_ast_array(n->StructType.where_clauses);
break; break;
case Ast_UnionType: case Ast_UnionType:
n->UnionType.variants = clone_ast_array(n->UnionType.variants); n->UnionType.variants = clone_ast_array(n->UnionType.variants);
n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params); n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params);
n->UnionType.where_clauses = clone_ast_array(n->UnionType.where_clauses);
break; break;
case Ast_EnumType: case Ast_EnumType:
n->EnumType.base_type = clone_ast(n->EnumType.base_type); n->EnumType.base_type = clone_ast(n->EnumType.base_type);
@@ -417,7 +427,7 @@ void syntax_error(Ast *node, char *fmt, ...) {
bool ast_node_expect(Ast *node, AstKind kind) { bool ast_node_expect(Ast *node, AstKind kind) {
if (node->kind != kind) { if (node->kind != kind) {
error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind])); syntax_error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind]));
return false; return false;
} }
return true; return true;
@@ -578,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) {
Ast *ast_basic_lit(AstFile *f, Token basic_lit) { Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
Ast *result = alloc_ast_node(f, Ast_BasicLit); Ast *result = alloc_ast_node(f, Ast_BasicLit);
result->BasicLit.token = basic_lit; result->BasicLit.token = basic_lit;
result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
return result; return result;
} }
@@ -605,11 +616,13 @@ Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<Ast
return result; return result;
} }
Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags) { Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags, Token where_token, Array<Ast *> const &where_clauses) {
Ast *result = alloc_ast_node(f, Ast_ProcLit); Ast *result = alloc_ast_node(f, Ast_ProcLit);
result->ProcLit.type = type; result->ProcLit.type = type;
result->ProcLit.body = body; result->ProcLit.body = body;
result->ProcLit.tags = tags; result->ProcLit.tags = tags;
result->ProcLit.where_token = where_token;
result->ProcLit.where_clauses = where_clauses;
return result; return result;
} }
@@ -748,6 +761,18 @@ Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_toke
return result; return result;
} }
Ast *ast_inline_range_stmt(AstFile *f, Token inline_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) {
Ast *result = alloc_ast_node(f, Ast_InlineRangeStmt);
result->InlineRangeStmt.inline_token = inline_token;
result->InlineRangeStmt.for_token = for_token;
result->InlineRangeStmt.val0 = val0;
result->InlineRangeStmt.val1 = val1;
result->InlineRangeStmt.in_token = in_token;
result->InlineRangeStmt.expr = expr;
result->InlineRangeStmt.body = body;
return result;
}
Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) { Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) {
Ast *result = alloc_ast_node(f, Ast_SwitchStmt); Ast *result = alloc_ast_node(f, Ast_SwitchStmt);
result->SwitchStmt.token = token; result->SwitchStmt.token = token;
@@ -805,13 +830,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
return result; return result;
} }
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Token tag,
CommentGroup *docs, CommentGroup *comment) { CommentGroup *docs, CommentGroup *comment) {
Ast *result = alloc_ast_node(f, Ast_Field); Ast *result = alloc_ast_node(f, Ast_Field);
result->Field.names = names; result->Field.names = names;
result->Field.type = type; result->Field.type = type;
result->Field.default_value = default_value; result->Field.default_value = default_value;
result->Field.flags = flags; result->Field.flags = flags;
result->Field.tag = tag;
result->Field.docs = docs; result->Field.docs = docs;
result->Field.comment = comment; result->Field.comment = comment;
return result; return result;
@@ -898,7 +924,8 @@ Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count, Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count,
Ast *polymorphic_params, bool is_packed, bool is_raw_union, Ast *polymorphic_params, bool is_packed, bool is_raw_union,
Ast *align) { Ast *align,
Token where_token, Array<Ast *> const &where_clauses) {
Ast *result = alloc_ast_node(f, Ast_StructType); Ast *result = alloc_ast_node(f, Ast_StructType);
result->StructType.token = token; result->StructType.token = token;
result->StructType.fields = fields; result->StructType.fields = fields;
@@ -907,17 +934,22 @@ Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_c
result->StructType.is_packed = is_packed; result->StructType.is_packed = is_packed;
result->StructType.is_raw_union = is_raw_union; result->StructType.is_raw_union = is_raw_union;
result->StructType.align = align; result->StructType.align = align;
result->StructType.where_token = where_token;
result->StructType.where_clauses = where_clauses;
return result; return result;
} }
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil) { Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil,
Token where_token, Array<Ast *> const &where_clauses) {
Ast *result = alloc_ast_node(f, Ast_UnionType); Ast *result = alloc_ast_node(f, Ast_UnionType);
result->UnionType.token = token; result->UnionType.token = token;
result->UnionType.variants = variants; result->UnionType.variants = variants;
result->UnionType.polymorphic_params = polymorphic_params; result->UnionType.polymorphic_params = polymorphic_params;
result->UnionType.align = align; result->UnionType.align = align;
result->UnionType.no_nil = no_nil; result->UnionType.no_nil = no_nil;
result->UnionType.where_token = where_token;
result->UnionType.where_clauses = where_clauses;
return result; return result;
} }
@@ -1118,6 +1150,17 @@ Token advance_token(AstFile *f) {
return prev; return prev;
} }
bool peek_token_kind(AstFile *f, TokenKind kind) {
for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) {
Token tok = f->tokens[i];
if (kind != Token_Comment && tok.kind == Token_Comment) {
continue;
}
return tok.kind == kind;
}
return false;
}
Token expect_token(AstFile *f, TokenKind kind) { Token expect_token(AstFile *f, TokenKind kind) {
Token prev = f->curr_token; Token prev = f->curr_token;
if (prev.kind != kind) { if (prev.kind != kind) {
@@ -1302,7 +1345,8 @@ bool is_semicolon_optional_for_node(AstFile *f, Ast *s) {
case Ast_UnionType: case Ast_UnionType:
case Ast_EnumType: case Ast_EnumType:
case Ast_BitFieldType: case Ast_BitFieldType:
return true; // Require semicolon within a procedure body
return f->curr_proc == nullptr;
case Ast_ProcLit: case Ast_ProcLit:
return true; return true;
@@ -1336,10 +1380,6 @@ void expect_semicolon(AstFile *f, Ast *s) {
return; return;
} }
switch (f->curr_token.kind) {
case Token_EOF:
return;
}
if (s != nullptr) { if (s != nullptr) {
if (prev_token.pos.line != f->curr_token.pos.line) { if (prev_token.pos.line != f->curr_token.pos.line) {
@@ -1352,12 +1392,21 @@ void expect_semicolon(AstFile *f, Ast *s) {
case Token_CloseParen: case Token_CloseParen:
case Token_else: case Token_else:
return; return;
case Token_EOF:
if (is_semicolon_optional_for_node(f, s)) {
return;
}
break;
} }
} }
String node_string = ast_strings[s->kind]; String node_string = ast_strings[s->kind];
syntax_error(prev_token, "Expected ';' after %.*s, got %.*s", syntax_error(prev_token, "Expected ';' after %.*s, got %.*s",
LIT(node_string), LIT(token_strings[prev_token.kind])); LIT(node_string), LIT(token_strings[f->curr_token.kind]));
} else { } else {
switch (f->curr_token.kind) {
case Token_EOF:
return;
}
syntax_error(prev_token, "Expected ';'"); syntax_error(prev_token, "Expected ';'");
} }
fix_advance_to_next_stmt(f); fix_advance_to_next_stmt(f);
@@ -1461,8 +1510,11 @@ Ast *parse_value(AstFile *f) {
if (f->curr_token.kind == Token_OpenBrace) { if (f->curr_token.kind == Token_OpenBrace) {
return parse_literal_value(f, nullptr); return parse_literal_value(f, nullptr);
} }
Ast *value;
Ast *value = parse_expr(f, false); bool prev_allow_range = f->allow_range;
f->allow_range = true;
value = parse_expr(f, false);
f->allow_range = prev_allow_range;
return value; return value;
} }
@@ -1614,7 +1666,7 @@ void check_polymorphic_params_for_type(AstFile *f, Ast *polymorphic_params, Toke
for_array(i, field->Field.names) { for_array(i, field->Field.names) {
Ast *name = field->Field.names[i]; Ast *name = field->Field.names[i];
if (name->kind == Ast_PolyType) { if (name->kind == Ast_PolyType) {
error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string)); syntax_error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string));
return; // TODO(bill): Err multiple times or just the once? return; // TODO(bill): Err multiple times or just the once?
} }
} }
@@ -1687,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) {
operand = ast_bad_expr(f, token, f->curr_token); operand = ast_bad_expr(f, token, f->curr_token);
} }
operand->stmt_state_flags |= StmtStateFlag_no_deferred; operand->stmt_state_flags |= StmtStateFlag_no_deferred;
} */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string); } */ else if (name.string == "file") {
return ast_basic_directive(f, token, name.string);
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string); } else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string); } else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string); } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
@@ -1796,15 +1849,41 @@ Ast *parse_operand(AstFile *f, bool lhs) {
} }
Ast *type = parse_proc_type(f, token); Ast *type = parse_proc_type(f, token);
Token where_token = {};
Array<Ast *> where_clauses = {};
u64 tags = 0;
if (f->curr_token.kind == Token_where) {
where_token = expect_token(f, Token_where);
isize prev_level = f->expr_level;
f->expr_level = -1;
where_clauses = parse_rhs_expr_list(f);
f->expr_level = prev_level;
}
parse_proc_tags(f, &tags);
if ((tags & ProcTag_require_results) != 0) {
syntax_error(f->curr_token, "#require_results has now been replaced as an attribute @(require_results) on the declaration");
tags &= ~ProcTag_require_results;
}
GB_ASSERT(type->kind == Ast_ProcType);
type->ProcType.tags = tags;
if (f->allow_type && f->expr_level < 0) { if (f->allow_type && f->expr_level < 0) {
if (tags != 0) {
syntax_error(token, "A procedure type cannot have suffix tags");
}
if (where_token.kind != Token_Invalid) {
syntax_error(where_token, "'where' clauses are not allowed on procedure types");
}
return type; return type;
} }
u64 tags = type->ProcType.tags;
if (allow_token(f, Token_Undef)) { if (allow_token(f, Token_Undef)) {
return ast_proc_lit(f, type, nullptr, tags); if (where_token.kind != Token_Invalid) {
syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)");
}
return ast_proc_lit(f, type, nullptr, tags, where_token, where_clauses);
} else if (f->curr_token.kind == Token_OpenBrace) { } else if (f->curr_token.kind == Token_OpenBrace) {
Ast *curr_proc = f->curr_proc; Ast *curr_proc = f->curr_proc;
Ast *body = nullptr; Ast *body = nullptr;
@@ -1812,7 +1891,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
body = parse_body(f); body = parse_body(f);
f->curr_proc = curr_proc; f->curr_proc = curr_proc;
return ast_proc_lit(f, type, body, tags); return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
} else if (allow_token(f, Token_do)) { } else if (allow_token(f, Token_do)) {
Ast *curr_proc = f->curr_proc; Ast *curr_proc = f->curr_proc;
Ast *body = nullptr; Ast *body = nullptr;
@@ -1820,11 +1899,14 @@ Ast *parse_operand(AstFile *f, bool lhs) {
body = convert_stmt_to_body(f, parse_stmt(f)); body = convert_stmt_to_body(f, parse_stmt(f));
f->curr_proc = curr_proc; f->curr_proc = curr_proc;
return ast_proc_lit(f, type, body, tags); return ast_proc_lit(f, type, body, tags, where_token, where_clauses);
} }
if (tags != 0) { if (tags != 0) {
syntax_error(token, "A procedure type cannot have tags"); syntax_error(token, "A procedure type cannot have suffix tags");
}
if (where_token.kind != Token_Invalid) {
syntax_error(where_token, "'where' clauses are not allowed on procedure types");
} }
return type; return type;
@@ -1847,10 +1929,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
case Token_typeid: { case Token_typeid: {
Token token = expect_token(f, Token_typeid); Token token = expect_token(f, Token_typeid);
// Ast *specialization = nullptr;
// if (allow_token(f, Token_Quo)) {
// specialization = parse_type(f);
// }
return ast_typeid_type(f, token, nullptr); return ast_typeid_type(f, token, nullptr);
} break; } break;
@@ -1952,6 +2030,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(token, "'#raw_union' cannot also be '#packed'"); syntax_error(token, "'#raw_union' cannot also be '#packed'");
} }
Token where_token = {};
Array<Ast *> where_clauses = {};
if (f->curr_token.kind == Token_where) {
where_token = expect_token(f, Token_where);
isize prev_level = f->expr_level;
f->expr_level = -1;
where_clauses = parse_rhs_expr_list(f);
f->expr_level = prev_level;
}
Token open = expect_token_after(f, Token_OpenBrace, "struct"); Token open = expect_token_after(f, Token_OpenBrace, "struct");
isize name_count = 0; isize name_count = 0;
@@ -1964,7 +2054,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
decls = fields->FieldList.list; decls = fields->FieldList.list;
} }
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align); return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align, where_token, where_clauses);
} break; } break;
case Token_union: { case Token_union: {
@@ -2005,6 +2095,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
} }
} }
Token where_token = {};
Array<Ast *> where_clauses = {};
if (f->curr_token.kind == Token_where) {
where_token = expect_token(f, Token_where);
isize prev_level = f->expr_level;
f->expr_level = -1;
where_clauses = parse_rhs_expr_list(f);
f->expr_level = prev_level;
}
Token open = expect_token_after(f, Token_OpenBrace, "union"); Token open = expect_token_after(f, Token_OpenBrace, "union");
while (f->curr_token.kind != Token_CloseBrace && while (f->curr_token.kind != Token_CloseBrace &&
@@ -2020,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
Token close = expect_token(f, Token_CloseBrace); Token close = expect_token(f, Token_CloseBrace);
return ast_union_type(f, token, variants, polymorphic_params, align, no_nil); return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, where_token, where_clauses);
} break; } break;
case Token_enum: { case Token_enum: {
@@ -2091,7 +2193,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
bool prev_allow_range = f->allow_range; bool prev_allow_range = f->allow_range;
f->allow_range = true; f->allow_range = true;
elem = parse_expr(f, false); elem = parse_expr(f, true);
f->allow_range = prev_allow_range; f->allow_range = prev_allow_range;
if (allow_token(f, Token_Semicolon)) { if (allow_token(f, Token_Semicolon)) {
underlying = parse_type(f); underlying = parse_type(f);
@@ -2383,17 +2485,18 @@ i32 token_precedence(AstFile *f, TokenKind t) {
case Token_LtEq: case Token_LtEq:
case Token_GtEq: case Token_GtEq:
return 5; return 5;
case Token_in: case Token_in:
case Token_notin: case Token_notin:
if (f->expr_level >= 0 || f->allow_in_expr) { if (f->expr_level < 0 && !f->allow_in_expr) {
return 6;
}
return 0; return 0;
}
/*fallthrough*/
case Token_Add: case Token_Add:
case Token_Sub: case Token_Sub:
case Token_Or: case Token_Or:
case Token_Xor: case Token_Xor:
return 7; return 6;
case Token_Mul: case Token_Mul:
case Token_Quo: case Token_Quo:
case Token_Mod: case Token_Mod:
@@ -2402,7 +2505,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
case Token_AndNot: case Token_AndNot:
case Token_Shl: case Token_Shl:
case Token_Shr: case Token_Shr:
return 8; return 7;
} }
return 0; return 0;
} }
@@ -2649,7 +2752,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) {
allow_token(f, Token_in); allow_token(f, Token_in);
bool prev_allow_range = f->allow_range; bool prev_allow_range = f->allow_range;
f->allow_range = true; f->allow_range = true;
Ast *expr = parse_expr(f, false); Ast *expr = parse_expr(f, true);
f->allow_range = prev_allow_range; f->allow_range = prev_allow_range;
auto rhs = array_make<Ast *>(heap_allocator(), 0, 1); auto rhs = array_make<Ast *>(heap_allocator(), 0, 1);
@@ -2740,7 +2843,8 @@ Ast *parse_results(AstFile *f, bool *diverging) {
Array<Ast *> empty_names = {}; Array<Ast *> empty_names = {};
auto list = array_make<Ast *>(heap_allocator(), 0, 1); auto list = array_make<Ast *>(heap_allocator(), 0, 1);
Ast *type = parse_type(f); Ast *type = parse_type(f);
array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr)); Token tag = {};
array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr));
return ast_field_list(f, begin_token, list); return ast_field_list(f, begin_token, list);
} }
@@ -2795,8 +2899,6 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) {
results = parse_results(f, &diverging); results = parse_results(f, &diverging);
u64 tags = 0; u64 tags = 0;
parse_proc_tags(f, &tags);
bool is_generic = false; bool is_generic = false;
for_array(i, params->FieldList.list) { for_array(i, params->FieldList.list) {
@@ -3095,6 +3197,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
Ast *type = nullptr; Ast *type = nullptr;
Ast *default_value = nullptr; Ast *default_value = nullptr;
Token tag = {};
expect_token_after(f, Token_Colon, "field list"); expect_token_after(f, Token_Colon, "field list");
if (f->curr_token.kind != Token_Eq) { if (f->curr_token.kind != Token_Eq) {
@@ -3132,16 +3235,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
} }
if (type != nullptr && default_value == nullptr) {
if (f->curr_token.kind == Token_String) {
tag = expect_token(f, Token_String);
if ((allowed_flags & FieldFlag_Tags) == 0) {
syntax_error(tag, "Field tags are only allowed within structures");
}
}
}
parse_expect_field_separator(f, type); parse_expect_field_separator(f, type);
Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
array_add(&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);
Token tag = {};
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment); Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment);
array_add(&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") { } else if (tag == "panic") {
s = parse_stmt(f); Ast *t = ast_basic_directive(f, hash_token, tag);
s->stmt_state_flags |= StmtStateFlag_no_deferred; return ast_expr_stmt(f, parse_call_expr(f, t));
} */ } else if (tag == "include") {
if (tag == "include") {
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?"); syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
s = ast_bad_stmt(f, token, f->curr_token); s = ast_bad_stmt(f, token, f->curr_token);
} else { } else {
@@ -4037,7 +4174,6 @@ bool init_parser(Parser *p) {
map_init(&p->package_map, heap_allocator()); map_init(&p->package_map, heap_allocator());
array_init(&p->packages, heap_allocator()); array_init(&p->packages, heap_allocator());
array_init(&p->package_imports, heap_allocator()); array_init(&p->package_imports, heap_allocator());
array_init(&p->files_to_process, heap_allocator());
gb_mutex_init(&p->file_add_mutex); gb_mutex_init(&p->file_add_mutex);
gb_mutex_init(&p->file_decl_mutex); gb_mutex_init(&p->file_decl_mutex);
return true; return true;
@@ -4060,7 +4196,6 @@ void destroy_parser(Parser *p) {
#endif #endif
array_free(&p->packages); array_free(&p->packages);
array_free(&p->package_imports); array_free(&p->package_imports);
array_free(&p->files_to_process);
string_set_destroy(&p->imported_files); string_set_destroy(&p->imported_files);
map_destroy(&p->package_map); map_destroy(&p->package_map);
gb_mutex_destroy(&p->file_add_mutex); gb_mutex_destroy(&p->file_add_mutex);
@@ -4077,19 +4212,32 @@ void parser_add_package(Parser *p, AstPackage *pkg) {
if (found) { if (found) {
GB_ASSERT(pkg->files.count > 0); GB_ASSERT(pkg->files.count > 0);
AstFile *f = pkg->files[0]; AstFile *f = pkg->files[0];
error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name)); syntax_error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name));
GB_ASSERT((*found)->files.count > 0); GB_ASSERT((*found)->files.count > 0);
TokenPos pos = (*found)->files[0]->package_token.pos; TokenPos pos = (*found)->files[0]->package_token.pos;
gb_printf_err("\tpreviously declared at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column); error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column);
} else { } else {
map_set(&p->package_map, key, pkg); map_set(&p->package_map, key, pkg);
} }
} }
} }
ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file);
WORKER_TASK_PROC(parser_worker_proc) {
ParserWorkerData *wd = cast(ParserWorkerData *)data;
ParseFileError err = process_imported_file(wd->parser, wd->imported_file);
return cast(isize)err;
}
void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) { void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) {
ImportedFile f = {pkg, fi, pos, p->files_to_process.count}; // TODO(bill): Use a better allocator
array_add(&p->files_to_process, f); ImportedFile f = {pkg, fi, pos, p->file_to_process_count++};
auto wd = gb_alloc_item(heap_allocator(), ParserWorkerData);
wd->parser = p;
wd->imported_file = f;
thread_pool_add_task(&parser_thread_pool, parser_worker_proc, wd);
} }
@@ -4140,22 +4288,22 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path,
switch (rd_err) { switch (rd_err) {
case ReadDirectory_InvalidPath: case ReadDirectory_InvalidPath:
error(pos, "Invalid path: %.*s", LIT(rel_path)); syntax_error(pos, "Invalid path: %.*s", LIT(rel_path));
return false; return false;
case ReadDirectory_NotExists: case ReadDirectory_NotExists:
error(pos, "Path does not exist: %.*s", LIT(rel_path)); syntax_error(pos, "Path does not exist: %.*s", LIT(rel_path));
return false; return false;
case ReadDirectory_Permission: case ReadDirectory_Permission:
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path)); syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
return false; return false;
case ReadDirectory_NotDir: case ReadDirectory_NotDir:
error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path)); syntax_error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
return false; return false;
case ReadDirectory_Empty: case ReadDirectory_Empty:
error(pos, "Empty directory: %.*s", LIT(rel_path)); syntax_error(pos, "Empty directory: %.*s", LIT(rel_path));
return false; return false;
case ReadDirectory_Unknown: case ReadDirectory_Unknown:
error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path)); syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
return false; return false;
} }
@@ -4257,7 +4405,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
String file_str = {}; String file_str = {};
if (colon_pos == 0) { if (colon_pos == 0) {
error(node, "Expected a collection name"); syntax_error(node, "Expected a collection name");
return false; return false;
} }
@@ -4272,32 +4420,19 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
if (has_windows_drive) { if (has_windows_drive) {
String sub_file_path = substring(file_str, 3, file_str.len); String sub_file_path = substring(file_str, 3, file_str.len);
if (!is_import_path_valid(sub_file_path)) { if (!is_import_path_valid(sub_file_path)) {
error(node, "Invalid import path: '%.*s'", LIT(file_str)); syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
return false; return false;
} }
} else if (!is_import_path_valid(file_str)) { } else if (!is_import_path_valid(file_str)) {
error(node, "Invalid import path: '%.*s'", LIT(file_str)); syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
return false; return false;
} }
if (is_package_name_reserved(file_str)) {
*path = file_str;
return true;
}
if (file_mutex) gb_mutex_lock(file_mutex);
defer (if (file_mutex) gb_mutex_unlock(file_mutex));
if (node->kind == Ast_ForeignImportDecl) {
node->ForeignImportDecl.collection_name = collection_name;
}
if (collection_name.len > 0) { if (collection_name.len > 0) {
if (collection_name == "system") { if (collection_name == "system") {
if (node->kind != Ast_ForeignImportDecl) { if (node->kind != Ast_ForeignImportDecl) {
error(node, "The library collection 'system' is restrict for 'foreign_library'"); syntax_error(node, "The library collection 'system' is restrict for 'foreign_library'");
return false; return false;
} else { } else {
*path = file_str; *path = file_str;
@@ -4305,7 +4440,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
} }
} else if (!find_library_collection_path(collection_name, &base_dir)) { } else if (!find_library_collection_path(collection_name, &base_dir)) {
// NOTE(bill): It's a naughty name // NOTE(bill): It's a naughty name
error(node, "Unknown library collection: '%.*s'", LIT(collection_name)); syntax_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
return false; return false;
} }
} else { } else {
@@ -4324,6 +4459,20 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
#endif #endif
} }
if (is_package_name_reserved(file_str)) {
*path = file_str;
return true;
}
if (file_mutex) gb_mutex_lock(file_mutex);
defer (if (file_mutex) gb_mutex_unlock(file_mutex));
if (node->kind == Ast_ForeignImportDecl) {
node->ForeignImportDecl.collection_name = collection_name;
}
if (has_windows_drive) { if (has_windows_drive) {
*path = file_str; *path = file_str;
} else { } else {
@@ -4412,7 +4561,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *>
array_add(&fl->fullpaths, fullpath); array_add(&fl->fullpaths, fullpath);
} }
if (fl->fullpaths.count == 0) { if (fl->fullpaths.count == 0) {
error(decls[i], "No foreign paths found"); syntax_error(decls[i], "No foreign paths found");
decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]); decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
goto end; goto end;
} }
@@ -4461,7 +4610,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
is_notted = true; is_notted = true;
p = substring(p, 1, p.len); p = substring(p, 1, p.len);
if (p.len == 0) { if (p.len == 0) {
error(token_for_pos, "Expected a build platform after '!'"); syntax_error(token_for_pos, "Expected a build platform after '!'");
break; break;
} }
} }
@@ -4490,7 +4639,7 @@ bool parse_build_tag(Token token_for_pos, String s) {
} }
} }
if (os == TargetOs_Invalid && arch == TargetArch_Invalid) { if (os == TargetOs_Invalid && arch == TargetArch_Invalid) {
error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p)); syntax_error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p));
break; break;
} }
} }
@@ -4536,11 +4685,11 @@ bool parse_file(Parser *p, AstFile *f) {
Token package_name = expect_token_after(f, Token_Ident, "package"); Token package_name = expect_token_after(f, Token_Ident, "package");
if (package_name.kind == Token_Ident) { if (package_name.kind == Token_Ident) {
if (package_name.string == "_") { if (package_name.string == "_") {
error(package_name, "Invalid package name '_'"); syntax_error(package_name, "Invalid package name '_'");
} else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") { } else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") {
error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
} else if (is_package_name_reserved(package_name.string)) { } else if (is_package_name_reserved(package_name.string)) {
error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string));
} }
} }
f->package_name = package_name.string; f->package_name = package_name.string;
@@ -4590,9 +4739,9 @@ bool parse_file(Parser *p, AstFile *f) {
} }
ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) { ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file) {
AstPackage *pkg = imported_file.pkg; AstPackage *pkg = imported_file.pkg;
FileInfo *fi = &imported_file.fi; FileInfo const *fi = &imported_file.fi;
TokenPos pos = imported_file.pos; TokenPos pos = imported_file.pos;
AstFile *file = gb_alloc_item(heap_allocator(), AstFile); AstFile *file = gb_alloc_item(heap_allocator(), AstFile);
@@ -4607,38 +4756,35 @@ ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) {
if (err != ParseFile_None) { if (err != ParseFile_None) {
if (err == ParseFile_EmptyFile) { if (err == ParseFile_EmptyFile) {
if (fi->fullpath == p->init_fullpath) { if (fi->fullpath == p->init_fullpath) {
error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath)); syntax_error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath));
gb_exit(1); gb_exit(1);
} }
goto skip; } else {
}
switch (err) { switch (err) {
case ParseFile_WrongExtension: case ParseFile_WrongExtension:
error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name)); syntax_error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name));
break; break;
case ParseFile_InvalidFile: case ParseFile_InvalidFile:
error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name)); syntax_error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name));
break; break;
case ParseFile_Permission: case ParseFile_Permission:
error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name)); syntax_error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name));
break; break;
case ParseFile_NotFound: case ParseFile_NotFound:
error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath)); syntax_error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath));
break; break;
case ParseFile_InvalidToken: case ParseFile_InvalidToken:
error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name)); syntax_error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name));
break; break;
case ParseFile_EmptyFile: case ParseFile_EmptyFile:
error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name)); syntax_error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name));
break; break;
} }
return err; return err;
} }
}
skip:
if (parse_file(p, file)) { if (parse_file(p, file)) {
gb_mutex_lock(&p->file_add_mutex); gb_mutex_lock(&p->file_add_mutex);
defer (gb_mutex_unlock(&p->file_add_mutex)); defer (gb_mutex_unlock(&p->file_add_mutex));
@@ -4648,42 +4794,33 @@ skip:
if (pkg->name.len == 0) { if (pkg->name.len == 0) {
pkg->name = file->package_name; pkg->name = file->package_name;
} else if (file->tokens.count > 0 && pkg->name != file->package_name) { } else if (file->tokens.count > 0 && pkg->name != file->package_name) {
error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name)); syntax_error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name));
} }
p->total_line_count += file->tokenizer.line_count; p->total_line_count += file->tokenizer.line_count;
p->total_token_count += file->tokens.count; p->total_token_count += file->tokens.count;
} }
return ParseFile_None; return ParseFile_None;
} }
GB_THREAD_PROC(parse_worker_file_proc) {
if (thread == nullptr) return 0;
auto *p = cast(Parser *)thread->user_data;
isize index = thread->user_index;
gb_mutex_lock(&p->file_add_mutex);
auto file_to_process = p->files_to_process[index];
gb_mutex_unlock(&p->file_add_mutex);
ParseFileError err = process_imported_file(p, file_to_process);
return cast(isize)err;
}
ParseFileError parse_packages(Parser *p, String init_filename) { ParseFileError parse_packages(Parser *p, String init_filename) {
GB_ASSERT(init_filename.text[init_filename.len] == 0); GB_ASSERT(init_filename.text[init_filename.len] == 0);
// char *fullpath_str = gb_path_get_full_name(heap_allocator(), cast(char const *)&init_filename[0]); isize thread_count = gb_max(build_context.thread_count, 1);
// String init_fullpath = string_trim_whitespace(make_string_c(fullpath_str)); isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work
thread_pool_init(&parser_thread_pool, heap_allocator(), worker_count, "ParserWork");
String init_fullpath = path_to_full_path(heap_allocator(), init_filename); String init_fullpath = path_to_full_path(heap_allocator(), init_filename);
if (!path_is_directory(init_fullpath)) { if (!path_is_directory(init_fullpath)) {
String const ext = str_lit(".odin"); String const ext = str_lit(".odin");
if (!string_ends_with(init_fullpath, ext)) { if (!string_ends_with(init_fullpath, ext)) {
gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename));
return ParseFile_WrongExtension; return ParseFile_WrongExtension;
} }
} }
TokenPos init_pos = {}; TokenPos init_pos = {};
if (!build_context.generate_docs) { if (!build_context.generate_docs) {
String s = get_fullpath_core(heap_allocator(), str_lit("runtime")); String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
@@ -4693,76 +4830,17 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init); try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init);
p->init_fullpath = init_fullpath; p->init_fullpath = init_fullpath;
#if 1 thread_pool_start(&parser_thread_pool);
isize thread_count = gb_max(build_context.thread_count, 1); thread_pool_wait_to_process(&parser_thread_pool);
if (thread_count > 1) {
isize volatile curr_import_index = 0;
isize initial_file_count = p->files_to_process.count;
// NOTE(bill): Make sure that these are in parsed in this order
for (isize i = 0; i < initial_file_count; i++) {
ParseFileError err = process_imported_file(p, p->files_to_process[i]);
if (err != ParseFile_None) {
return err;
}
curr_import_index++;
}
auto worker_threads = array_make<gbThread>(heap_allocator(), thread_count); // NOTE(bill): Get the last error and use that
defer (array_free(&worker_threads)); for (isize i = parser_thread_pool.task_tail-1; i >= 0; i--) {
WorkerTask *task = &parser_thread_pool.tasks[i];
for_array(i, worker_threads) { ParseFileError err = cast(ParseFileError)task->result;
gbThread *t = &worker_threads[i];
gb_thread_init(t);
}
defer (for_array(i, worker_threads) {
gb_thread_destroy(&worker_threads[i]);
});
auto errors = array_make<ParseFileError>(heap_allocator(), 0, 16);
for (;;) {
bool are_any_alive = false;
for_array(i, worker_threads) {
gbThread *t = &worker_threads[i];
if (gb_thread_is_running(t)) {
are_any_alive = true;
} else if (curr_import_index < p->files_to_process.count) {
auto curr_err = cast(ParseFileError)t->return_value;
if (curr_err != ParseFile_None) {
array_add(&errors, curr_err);
} else {
t->user_index = curr_import_index;
curr_import_index++;
gb_thread_start(t, parse_worker_file_proc, p);
are_any_alive = true;
}
}
}
if (!are_any_alive && curr_import_index >= p->files_to_process.count) {
break;
}
}
if (errors.count > 0) {
return errors[errors.count-1];
}
} else {
for_array(i, p->files_to_process) {
ParseFileError err = process_imported_file(p, p->files_to_process[i]);
if (err != ParseFile_None) { if (err != ParseFile_None) {
return err; return err;
} }
} }
}
#else
for_array(i, p->files_to_process) {
ImportedFile f = p->files_to_process[i];
ParseFileError err = process_imported_file(p, f);
if (err != ParseFile_None) {
return err;
}
}
#endif
return ParseFile_None; return ParseFile_None;
} }
+34 -2
View File
@@ -134,13 +134,26 @@ struct Parser {
Map<AstPackage *> package_map; // Key: String (package name) Map<AstPackage *> package_map; // Key: String (package name)
Array<AstPackage *> packages; Array<AstPackage *> packages;
Array<ImportedPackage> package_imports; Array<ImportedPackage> package_imports;
Array<ImportedFile> files_to_process; isize file_to_process_count;
isize total_token_count; isize total_token_count;
isize total_line_count; isize total_line_count;
gbMutex file_add_mutex; gbMutex file_add_mutex;
gbMutex file_decl_mutex; gbMutex file_decl_mutex;
}; };
gb_global ThreadPool parser_thread_pool = {};
struct ParserWorkerData {
Parser *parser;
ImportedFile imported_file;
};
enum ProcInlining { enum ProcInlining {
ProcInlining_none = 0, ProcInlining_none = 0,
ProcInlining_inline = 1, ProcInlining_inline = 1,
@@ -186,11 +199,12 @@ enum FieldFlag {
FieldFlag_c_vararg = 1<<3, FieldFlag_c_vararg = 1<<3,
FieldFlag_auto_cast = 1<<4, FieldFlag_auto_cast = 1<<4,
FieldFlag_Tags = 1<<10,
FieldFlag_Results = 1<<16, FieldFlag_Results = 1<<16,
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast, FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
FieldFlag_Struct = FieldFlag_using, FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
}; };
enum StmtAllowFlag { enum StmtAllowFlag {
@@ -208,6 +222,7 @@ enum StmtAllowFlag {
AST_KIND(Undef, "undef", Token) \ AST_KIND(Undef, "undef", Token) \
AST_KIND(BasicLit, "basic literal", struct { \ AST_KIND(BasicLit, "basic literal", struct { \
Token token; \ Token token; \
ExactValue value; \
}) \ }) \
AST_KIND(BasicDirective, "basic directive", struct { \ AST_KIND(BasicDirective, "basic directive", struct { \
Token token; \ Token token; \
@@ -228,11 +243,14 @@ enum StmtAllowFlag {
Ast *body; \ Ast *body; \
u64 tags; \ u64 tags; \
ProcInlining inlining; \ ProcInlining inlining; \
Token where_token; \
Array<Ast *> where_clauses; \
}) \ }) \
AST_KIND(CompoundLit, "compound literal", struct { \ AST_KIND(CompoundLit, "compound literal", struct { \
Ast *type; \ Ast *type; \
Array<Ast *> elems; \ Array<Ast *> elems; \
Token open, close; \ Token open, close; \
i64 max_count; \
}) \ }) \
AST_KIND(_ExprBegin, "", bool) \ AST_KIND(_ExprBegin, "", bool) \
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
@@ -325,6 +343,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
Ast *expr; \ Ast *expr; \
Ast *body; \ Ast *body; \
}) \ }) \
AST_KIND(InlineRangeStmt, "inline range statement", struct { \
Token inline_token; \
Token for_token; \
Ast *val0; \
Ast *val1; \
Token in_token; \
Ast *expr; \
Ast *body; \
}) \
AST_KIND(CaseClause, "case clause", struct { \ AST_KIND(CaseClause, "case clause", struct { \
Token token; \ Token token; \
Array<Ast *> list; \ Array<Ast *> list; \
@@ -412,6 +439,7 @@ AST_KIND(_DeclEnd, "", bool) \
Array<Ast *> names; \ Array<Ast *> names; \
Ast * type; \ Ast * type; \
Ast * default_value; \ Ast * default_value; \
Token tag; \
u32 flags; \ u32 flags; \
CommentGroup * docs; \ CommentGroup * docs; \
CommentGroup * comment; \ CommentGroup * comment; \
@@ -470,6 +498,8 @@ AST_KIND(_TypeBegin, "", bool) \
isize field_count; \ isize field_count; \
Ast *polymorphic_params; \ Ast *polymorphic_params; \
Ast *align; \ Ast *align; \
Token where_token; \
Array<Ast *> where_clauses; \
bool is_packed; \ bool is_packed; \
bool is_raw_union; \ bool is_raw_union; \
}) \ }) \
@@ -479,6 +509,8 @@ AST_KIND(_TypeBegin, "", bool) \
Ast *polymorphic_params; \ Ast *polymorphic_params; \
Ast * align; \ Ast * align; \
bool no_nil; \ bool no_nil; \
Token where_token; \
Array<Ast *> where_clauses; \
}) \ }) \
AST_KIND(EnumType, "enum type", struct { \ AST_KIND(EnumType, "enum type", struct { \
Token token; \ Token token; \
+2 -2
View File
@@ -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
View File
@@ -0,0 +1,70 @@
// Integers only
struct RangeValue {
i64 lo;
i64 hi;
};
struct RangeCache {
Array<RangeValue> ranges;
};
RangeCache range_cache_make(gbAllocator a) {
RangeCache cache = {};
array_init(&cache.ranges, a);
return cache;
}
void range_cache_destroy(RangeCache *c) {
array_free(&c->ranges);
}
bool range_cache_add_index(RangeCache *c, i64 index) {
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (v.lo <= index && index <= v.hi) {
return false;
}
}
RangeValue v = {index, index};
array_add(&c->ranges, v);
return true;
}
bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
GB_ASSERT(lo <= hi);
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (hi < v.lo) {
continue;
}
if (lo > v.hi) {
continue;
}
if (v.hi < hi) {
v.hi = hi;
}
if (lo < v.lo) {
v.lo = lo;
}
c->ranges[i] = v;
return false;
}
RangeValue v = {lo, hi};
array_add(&c->ranges, v);
return true;
}
bool range_cache_index_exists(RangeCache *c, i64 index) {
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (v.lo <= index && index <= v.hi) {
return true;
}
}
return false;
}
+86 -4
View File
@@ -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
View File
@@ -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
View File
@@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
TOKEN_KIND(Token_package, "package"), \ TOKEN_KIND(Token_package, "package"), \
TOKEN_KIND(Token_typeid, "typeid"), \ TOKEN_KIND(Token_typeid, "typeid"), \
TOKEN_KIND(Token_when, "when"), \ TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_where, "where"), \
TOKEN_KIND(Token_if, "if"), \ TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \ TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \ TOKEN_KIND(Token_for, "for"), \
@@ -400,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) {
va_end(va); va_end(va);
} }
void syntax_error(TokenPos pos, char *fmt, ...) {
va_list va;
va_start(va, fmt);
Token token = {};
token.pos = pos;
syntax_error_va(token, fmt, va);
va_end(va);
}
void syntax_warning(Token token, char *fmt, ...) { void syntax_warning(Token token, char *fmt, ...) {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@@ -745,9 +755,11 @@ exponent:
scan_mantissa(t, 10); scan_mantissa(t, 10);
} }
if (t->curr_rune == 'i') { switch (t->curr_rune) {
case 'i': case 'j': case 'k':
token.kind = Token_Imag; token.kind = Token_Imag;
advance_to_next_rune(t); advance_to_next_rune(t);
break;
} }
end: end:
+173 -41
View File
@@ -32,6 +32,9 @@ enum BasicKind {
Basic_complex64, Basic_complex64,
Basic_complex128, Basic_complex128,
Basic_quaternion128,
Basic_quaternion256,
Basic_int, Basic_int,
Basic_uint, Basic_uint,
Basic_uintptr, Basic_uintptr,
@@ -66,6 +69,7 @@ enum BasicKind {
Basic_UntypedInteger, Basic_UntypedInteger,
Basic_UntypedFloat, Basic_UntypedFloat,
Basic_UntypedComplex, Basic_UntypedComplex,
Basic_UntypedQuaternion,
Basic_UntypedString, Basic_UntypedString,
Basic_UntypedRune, Basic_UntypedRune,
Basic_UntypedNil, Basic_UntypedNil,
@@ -82,17 +86,18 @@ enum BasicFlag {
BasicFlag_Unsigned = GB_BIT(2), BasicFlag_Unsigned = GB_BIT(2),
BasicFlag_Float = GB_BIT(3), BasicFlag_Float = GB_BIT(3),
BasicFlag_Complex = GB_BIT(4), BasicFlag_Complex = GB_BIT(4),
BasicFlag_Pointer = GB_BIT(5), BasicFlag_Quaternion = GB_BIT(5),
BasicFlag_String = GB_BIT(6), BasicFlag_Pointer = GB_BIT(6),
BasicFlag_Rune = GB_BIT(7), BasicFlag_String = GB_BIT(7),
BasicFlag_Untyped = GB_BIT(8), BasicFlag_Rune = GB_BIT(8),
BasicFlag_Untyped = GB_BIT(9),
BasicFlag_LLVM = GB_BIT(10), BasicFlag_LLVM = GB_BIT(11),
BasicFlag_EndianLittle = GB_BIT(13), BasicFlag_EndianLittle = GB_BIT(13),
BasicFlag_EndianBig = GB_BIT(14), BasicFlag_EndianBig = GB_BIT(14),
BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex, BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion,
BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune, BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune,
BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune,
@@ -107,21 +112,23 @@ struct BasicType {
struct TypeStruct { struct TypeStruct {
Array<Entity *> fields; Array<Entity *> fields;
Array<String> tags;
Array<i64> offsets;
Ast * node; Ast * node;
Scope * scope; Scope * scope;
Array<i64> offsets; Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
i64 custom_align;
Entity * names;
bool are_offsets_set; bool are_offsets_set;
bool are_offsets_being_processed; bool are_offsets_being_processed;
bool is_packed; bool is_packed;
bool is_raw_union; bool is_raw_union;
bool is_polymorphic; bool is_polymorphic;
bool is_poly_specialized; bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent;
i64 custom_align; // NOTE(bill): Only used in structs at the moment
Entity * names;
}; };
struct TypeUnion { struct TypeUnion {
@@ -131,12 +138,11 @@ struct TypeUnion {
i64 variant_block_size; i64 variant_block_size;
i64 custom_align; i64 custom_align;
i64 tag_size; i64 tag_size;
bool no_nil;
bool is_polymorphic;
bool is_poly_specialized;
Type * polymorphic_params; // Type_Tuple Type * polymorphic_params; // Type_Tuple
Type * polymorphic_parent; Type * polymorphic_parent;
bool no_nil;
bool is_polymorphic;
bool is_poly_specialized;
}; };
#define TYPE_KINDS \ #define TYPE_KINDS \
@@ -184,7 +190,9 @@ struct TypeUnion {
TYPE_KIND(Tuple, struct { \ TYPE_KIND(Tuple, struct { \
Array<Entity *> variables; /* Entity_Variable */ \ Array<Entity *> variables; /* Entity_Variable */ \
Array<i64> offsets; \ Array<i64> offsets; \
bool are_offsets_being_processed; \
bool are_offsets_set; \ bool are_offsets_set; \
bool is_packed; \
}) \ }) \
TYPE_KIND(Proc, struct { \ TYPE_KIND(Proc, struct { \
Ast *node; \ Ast *node; \
@@ -195,9 +203,9 @@ struct TypeUnion {
i32 result_count; \ i32 result_count; \
Array<Type *> abi_compat_params; \ Array<Type *> abi_compat_params; \
Type * abi_compat_result_type; \ Type * abi_compat_result_type; \
bool return_by_pointer; \
bool variadic; \
i32 variadic_index; \ i32 variadic_index; \
bool variadic; \
bool abi_types_set; \
bool require_results; \ bool require_results; \
bool c_vararg; \ bool c_vararg; \
bool is_polymorphic; \ bool is_polymorphic; \
@@ -205,6 +213,7 @@ struct TypeUnion {
bool has_proc_default_values; \ bool has_proc_default_values; \
bool has_named_results; \ bool has_named_results; \
bool diverging; /* no return */ \ bool diverging; /* no return */ \
bool return_by_pointer; \
u64 tags; \ u64 tags; \
isize specialization_count; \ isize specialization_count; \
ProcCallingConvention calling_convention; \ ProcCallingConvention calling_convention; \
@@ -341,6 +350,9 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}},
{Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}},
{Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}},
{Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}},
{Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}}, {Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}},
{Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}}, {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}},
{Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}}, {Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}},
@@ -376,6 +388,7 @@ gb_global Type basic_types[] = {
{Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}}, {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}},
{Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}}, {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}},
{Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}}, {Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}},
{Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}},
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
@@ -411,6 +424,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64];
gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex64 = &basic_types[Basic_complex64];
gb_global Type *t_complex128 = &basic_types[Basic_complex128]; gb_global Type *t_complex128 = &basic_types[Basic_complex128];
gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128];
gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256];
gb_global Type *t_int = &basic_types[Basic_int]; gb_global Type *t_int = &basic_types[Basic_int];
gb_global Type *t_uint = &basic_types[Basic_uint]; gb_global Type *t_uint = &basic_types[Basic_uint];
gb_global Type *t_uintptr = &basic_types[Basic_uintptr]; gb_global Type *t_uintptr = &basic_types[Basic_uintptr];
@@ -445,6 +461,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex]; gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex];
gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
@@ -471,6 +488,7 @@ gb_global Type *t_type_info_integer = nullptr;
gb_global Type *t_type_info_rune = nullptr; gb_global Type *t_type_info_rune = nullptr;
gb_global Type *t_type_info_float = nullptr; gb_global Type *t_type_info_float = nullptr;
gb_global Type *t_type_info_complex = nullptr; gb_global Type *t_type_info_complex = nullptr;
gb_global Type *t_type_info_quaternion = nullptr;
gb_global Type *t_type_info_any = nullptr; gb_global Type *t_type_info_any = nullptr;
gb_global Type *t_type_info_typeid = nullptr; gb_global Type *t_type_info_typeid = nullptr;
gb_global Type *t_type_info_string = nullptr; gb_global Type *t_type_info_string = nullptr;
@@ -495,6 +513,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr;
gb_global Type *t_type_info_rune_ptr = nullptr; gb_global Type *t_type_info_rune_ptr = nullptr;
gb_global Type *t_type_info_float_ptr = nullptr; gb_global Type *t_type_info_float_ptr = nullptr;
gb_global Type *t_type_info_complex_ptr = nullptr; gb_global Type *t_type_info_complex_ptr = nullptr;
gb_global Type *t_type_info_quaternion_ptr = nullptr;
gb_global Type *t_type_info_any_ptr = nullptr; gb_global Type *t_type_info_any_ptr = nullptr;
gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_typeid_ptr = nullptr;
gb_global Type *t_type_info_string_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr;
@@ -535,8 +554,27 @@ i64 type_offset_of (Type *t, i32 index);
gbString type_to_string (Type *type); gbString type_to_string (Type *type);
void init_map_internal_types(Type *type); void init_map_internal_types(Type *type);
Type * bit_set_to_int(Type *t); Type * bit_set_to_int(Type *t);
bool are_types_identical(Type *x, Type *y);
bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t) {
if (ptr_set_exists(s, t)) {
return true;
}
// TODO(bill, 2019-10-05): This is very slow and it's probably a lot
// faster to cache types correctly
for_array(i, s->entries) {
Type *f = s->entries[i].ptr;
if (are_types_identical(t, f)) {
ptr_set_add(s, t);
return true;
}
}
return false;
}
Type *base_type(Type *t) { Type *base_type(Type *t) {
for (;;) { for (;;) {
if (t == nullptr) { if (t == nullptr) {
@@ -923,6 +961,13 @@ bool is_type_complex(Type *t) {
} }
return false; return false;
} }
bool is_type_quaternion(Type *t) {
t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Quaternion) != 0;
}
return false;
}
bool is_type_f32(Type *t) { bool is_type_f32(Type *t) {
t = core_type(t); t = core_type(t);
if (t->kind == Type_Basic) { if (t->kind == Type_Basic) {
@@ -1037,14 +1082,40 @@ Type *core_array_type(Type *t) {
return t; return t;
} }
// NOTE(bill): type can be easily compared using memcmp
bool is_type_simple_compare(Type *t) {
t = core_type(t);
switch (t->kind) {
case Type_Array:
return is_type_simple_compare(t->Array.elem);
case Type_Basic:
if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) {
return true;
}
return false;
case Type_Pointer:
case Type_Proc:
case Type_BitSet:
case Type_BitField:
return true;
}
return false;
}
Type *base_complex_elem_type(Type *t) { Type *base_complex_elem_type(Type *t) {
t = core_type(t); t = core_type(t);
if (is_type_complex(t)) { if (t->kind == Type_Basic) {
switch (t->Basic.kind) { switch (t->Basic.kind) {
// case Basic_complex32: return t_f16; // case Basic_complex32: return t_f16;
case Basic_complex64: return t_f32; case Basic_complex64: return t_f32;
case Basic_complex128: return t_f64; case Basic_complex128: return t_f64;
case Basic_quaternion128: return t_f32;
case Basic_quaternion256: return t_f64;
case Basic_UntypedComplex: return t_untyped_float; case Basic_UntypedComplex: return t_untyped_float;
case Basic_UntypedQuaternion: return t_untyped_float;
} }
} }
GB_PANIC("Invalid complex type"); GB_PANIC("Invalid complex type");
@@ -1099,12 +1170,11 @@ bool is_type_integer_endian_big(Type *t) {
return is_type_integer_endian_big(bit_set_to_int(t)); return is_type_integer_endian_big(bit_set_to_int(t));
} else if (t->kind == Type_Pointer) { } else if (t->kind == Type_Pointer) {
return is_type_integer_endian_big(&basic_types[Basic_uintptr]); return is_type_integer_endian_big(&basic_types[Basic_uintptr]);
} else {
GB_PANIC("Unsupported type: %s", type_to_string(t));
} }
return build_context.endian_kind == TargetEndian_Big; return build_context.endian_kind == TargetEndian_Big;
} }
bool is_type_integer_endian_little(Type *t) { bool is_type_integer_endian_little(Type *t) {
t = core_type(t); t = core_type(t);
if (t->kind == Type_Basic) { if (t->kind == Type_Basic) {
@@ -1118,11 +1188,24 @@ bool is_type_integer_endian_little(Type *t) {
return is_type_integer_endian_little(bit_set_to_int(t)); return is_type_integer_endian_little(bit_set_to_int(t));
} else if (t->kind == Type_Pointer) { } else if (t->kind == Type_Pointer) {
return is_type_integer_endian_little(&basic_types[Basic_uintptr]); return is_type_integer_endian_little(&basic_types[Basic_uintptr]);
} else {
GB_PANIC("Unsupported type: %s", type_to_string(t));
} }
return build_context.endian_kind == TargetEndian_Little; return build_context.endian_kind == TargetEndian_Little;
} }
bool is_type_endian_big(Type *t) {
return is_type_integer_endian_big(t);
}
bool is_type_endian_little(Type *t) {
return is_type_integer_endian_little(t);
}
bool is_type_dereferenceable(Type *t) {
if (is_type_rawptr(t)) {
return false;
}
return is_type_pointer(t);
}
bool is_type_different_to_arch_endianness(Type *t) { bool is_type_different_to_arch_endianness(Type *t) {
switch (build_context.endian_kind) { switch (build_context.endian_kind) {
@@ -1284,6 +1367,19 @@ bool is_type_indexable(Type *t) {
return false; return false;
} }
bool is_type_sliceable(Type *t) {
Type *bt = base_type(t);
switch (bt->kind) {
case Type_Basic:
return bt->Basic.kind == Basic_string;
case Type_Array:
case Type_Slice:
case Type_DynamicArray:
return true;
}
return false;
}
bool is_type_polymorphic_record(Type *t) { bool is_type_polymorphic_record(Type *t) {
t = base_type(t); t = base_type(t);
@@ -1663,6 +1759,12 @@ bool are_types_identical(Type *x, Type *y) {
if (xf_is_using ^ yf_is_using) { if (xf_is_using ^ yf_is_using) {
return false; return false;
} }
if (x->Struct.tags.count != y->Struct.tags.count) {
return false;
}
if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) {
return false;
}
} }
return true; return true;
} }
@@ -1683,7 +1785,8 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Tuple: case Type_Tuple:
if (y->kind == Type_Tuple) { if (y->kind == Type_Tuple) {
if (x->Tuple.variables.count == y->Tuple.variables.count) { if (x->Tuple.variables.count == y->Tuple.variables.count &&
x->Tuple.is_packed == y->Tuple.is_packed) {
for_array(i, x->Tuple.variables) { for_array(i, x->Tuple.variables) {
Entity *xe = x->Tuple.variables[i]; Entity *xe = x->Tuple.variables[i];
Entity *ye = y->Tuple.variables[i]; Entity *ye = y->Tuple.variables[i];
@@ -1763,6 +1866,7 @@ Type *default_type(Type *type) {
case Basic_UntypedInteger: return t_int; case Basic_UntypedInteger: return t_int;
case Basic_UntypedFloat: return t_f64; case Basic_UntypedFloat: return t_f64;
case Basic_UntypedComplex: return t_complex128; case Basic_UntypedComplex: return t_complex128;
case Basic_UntypedQuaternion: return t_quaternion256;
case Basic_UntypedString: return t_string; case Basic_UntypedString: return t_string;
case Basic_UntypedRune: return t_rune; case Basic_UntypedRune: return t_rune;
} }
@@ -2131,19 +2235,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
if (type->Array.count <= 4) { if (type->Array.count <= 4) {
// HACK(bill): Memory leak // HACK(bill): Memory leak
switch (type->Array.count) { switch (type->Array.count) {
#define _ARRAY_FIELD_CASE(_length, _name) \ #define _ARRAY_FIELD_CASE_IF(_length, _name) \
case (_length): \ if (field_name == (_name)) { \
if (field_name == _name) { \
selection_add_index(&sel, (_length)-1); \ selection_add_index(&sel, (_length)-1); \
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \ sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
return sel; \ return sel; \
} \ }
#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
case (_length): \
_ARRAY_FIELD_CASE_IF(_length, _name0); \
_ARRAY_FIELD_CASE_IF(_length, _name1); \
/*fallthrough*/ /*fallthrough*/
_ARRAY_FIELD_CASE(4, "w"); _ARRAY_FIELD_CASE(4, "w", "a");
_ARRAY_FIELD_CASE(3, "z"); _ARRAY_FIELD_CASE(3, "z", "b");
_ARRAY_FIELD_CASE(2, "y"); _ARRAY_FIELD_CASE(2, "y", "g");
_ARRAY_FIELD_CASE(1, "x"); _ARRAY_FIELD_CASE(1, "x", "r");
default: break; default: break;
#undef _ARRAY_FIELD_CASE #undef _ARRAY_FIELD_CASE
@@ -2254,7 +2361,9 @@ i64 type_size_of(Type *t) {
return 0; return 0;
} }
// NOTE(bill): Always calculate the size when it is a Type_Basic // NOTE(bill): Always calculate the size when it is a Type_Basic
if (t->kind != Type_Basic && t->cached_size >= 0) { if (t->kind == Type_Named && t->cached_size >= 0) {
} else if (t->kind != Type_Basic && t->cached_size >= 0) {
return t->cached_size; return t->cached_size;
} }
TypePath path = {0}; TypePath path = {0};
@@ -2269,7 +2378,9 @@ i64 type_align_of(Type *t) {
return 1; return 1;
} }
// NOTE(bill): Always calculate the size when it is a Type_Basic // NOTE(bill): Always calculate the size when it is a Type_Basic
if (t->kind != Type_Basic && t->cached_align > 0) { if (t->kind == Type_Named && t->cached_align >= 0) {
} if (t->kind != Type_Basic && t->cached_align > 0) {
return t->cached_align; return t->cached_align;
} }
@@ -2303,6 +2414,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
case Basic_complex64: case Basic_complex128: case Basic_complex64: case Basic_complex128:
return type_size_of_internal(t, path) / 2; return type_size_of_internal(t, path) / 2;
case Basic_quaternion128: case Basic_quaternion256:
return type_size_of_internal(t, path) / 4;
} }
} break; } break;
@@ -2488,9 +2601,9 @@ bool type_set_offsets(Type *t) {
} }
} else if (is_type_tuple(t)) { } else if (is_type_tuple(t)) {
if (!t->Tuple.are_offsets_set) { if (!t->Tuple.are_offsets_set) {
t->Struct.are_offsets_being_processed = true; t->Tuple.are_offsets_being_processed = true;
t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false); t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false);
t->Struct.are_offsets_being_processed = false; t->Tuple.are_offsets_being_processed = false;
t->Tuple.are_offsets_set = true; t->Tuple.are_offsets_set = true;
return true; return true;
} }
@@ -2913,9 +3026,22 @@ gbString write_type_to_string(gbString str, Type *type) {
isize comma_index = 0; isize comma_index = 0;
for_array(i, type->Tuple.variables) { for_array(i, type->Tuple.variables) {
Entity *var = type->Tuple.variables[i]; Entity *var = type->Tuple.variables[i];
if (var != nullptr) { if (var == nullptr) {
continue;
}
String name = var->token.string;
if (var->kind == Entity_Constant) { if (var->kind == Entity_Constant) {
// Ignore str = gb_string_appendc(str, "$");
str = gb_string_append_length(str, name.text, name.len);
if (!is_type_untyped(var->type)) {
str = gb_string_appendc(str, ": ");
str = write_type_to_string(str, var->type);
str = gb_string_appendc(str, " = ");
str = write_exact_value_to_string(str, var->Constant.value);
} else {
str = gb_string_appendc(str, "=");
str = write_exact_value_to_string(str, var->Constant.value);
}
continue; continue;
} }
@@ -2938,10 +3064,16 @@ gbString write_type_to_string(gbString str, Type *type) {
} else { } else {
GB_ASSERT(var->kind == Entity_TypeName); GB_ASSERT(var->kind == Entity_TypeName);
if (var->type->kind == Type_Generic) { if (var->type->kind == Type_Generic) {
str = gb_string_appendc(str, "type/"); str = gb_string_appendc(str, "typeid/");
str = write_type_to_string(str, var->type); str = write_type_to_string(str, var->type);
} else { } else {
str = gb_string_appendc(str, "type"); if (var->kind == Entity_TypeName) {
str = gb_string_appendc(str, "$");
str = gb_string_append_length(str, name.text, name.len);
str = gb_string_appendc(str, "=");
str = write_type_to_string(str, var->type);
} else {
str = gb_string_appendc(str, "typeid");
} }
} }
} }
-1
View File
@@ -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)
-1
View File
@@ -40,7 +40,6 @@
* Implementation of libutf8proc. * Implementation of libutf8proc.
*/ */
#include "utf8proc.h" #include "utf8proc.h"
#include "utf8proc_data.c" #include "utf8proc_data.c"