mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Better using; foreign system libraries; optional semicolons
This commit is contained in:
+81
-81
@@ -3,166 +3,166 @@
|
|||||||
#load "file.odin"
|
#load "file.odin"
|
||||||
|
|
||||||
print_string :: proc(s: string) {
|
print_string :: proc(s: string) {
|
||||||
file_write(file_get_standard(FileStandard.OUTPUT), s as []byte);
|
file_write(file_get_standard(FileStandard.OUTPUT), s as []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_reverse :: proc(b: []byte) {
|
byte_reverse :: proc(b: []byte) {
|
||||||
n := len(b);
|
n := len(b)
|
||||||
for i := 0; i < n/2; i++ {
|
for i := 0; i < n/2; i++ {
|
||||||
b[i], b[n-1-i] = b[n-1-i], b[i];
|
b[i], b[n-1-i] = b[n-1-i], b[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||||
buf: [4]byte;
|
buf: [4]byte
|
||||||
i := r as u32;
|
i := r as u32
|
||||||
mask: byte : 0x3f;
|
mask: byte : 0x3f
|
||||||
if i <= 1<<7-1 {
|
if i <= 1<<7-1 {
|
||||||
buf[0] = r as byte;
|
buf[0] = r as byte
|
||||||
return buf, 1;
|
return buf, 1
|
||||||
}
|
}
|
||||||
if i <= 1<<11-1 {
|
if i <= 1<<11-1 {
|
||||||
buf[0] = 0xc0 | (r>>6) as byte;
|
buf[0] = 0xc0 | (r>>6) as byte
|
||||||
buf[1] = 0x80 | (r) as byte & mask;
|
buf[1] = 0x80 | (r) as byte & mask
|
||||||
return buf, 2;
|
return buf, 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid or Surrogate range
|
// Invalid or Surrogate range
|
||||||
if i > 0x0010ffff ||
|
if i > 0x0010ffff ||
|
||||||
(i >= 0xd800 && i <= 0xdfff) {
|
(i >= 0xd800 && i <= 0xdfff) {
|
||||||
r = 0xfffd;
|
r = 0xfffd
|
||||||
}
|
}
|
||||||
|
|
||||||
if i <= 1<<16-1 {
|
if i <= 1<<16-1 {
|
||||||
buf[0] = 0xe0 | (r>>12) as byte;
|
buf[0] = 0xe0 | (r>>12) as byte
|
||||||
buf[1] = 0x80 | (r>>6) as byte & mask;
|
buf[1] = 0x80 | (r>>6) as byte & mask
|
||||||
buf[2] = 0x80 | (r) as byte & mask;
|
buf[2] = 0x80 | (r) as byte & mask
|
||||||
return buf, 3;
|
return buf, 3
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = 0xf0 | (r>>18) as byte;
|
buf[0] = 0xf0 | (r>>18) as byte
|
||||||
buf[1] = 0x80 | (r>>12) as byte & mask;
|
buf[1] = 0x80 | (r>>12) as byte & mask
|
||||||
buf[2] = 0x80 | (r>>6) as byte & mask;
|
buf[2] = 0x80 | (r>>6) as byte & mask
|
||||||
buf[3] = 0x80 | (r) as byte & mask;
|
buf[3] = 0x80 | (r) as byte & mask
|
||||||
return buf, 4;
|
return buf, 4
|
||||||
}
|
}
|
||||||
|
|
||||||
print_rune :: proc(r: rune) {
|
print_rune :: proc(r: rune) {
|
||||||
buf, n := encode_rune(r);
|
buf, n := encode_rune(r)
|
||||||
str := buf[:n] as string;
|
str := buf[:n] as string
|
||||||
print_string(str);
|
print_string(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
print_space :: proc() { print_rune(#rune " "); }
|
print_space :: proc() { print_rune(#rune " ") }
|
||||||
print_nl :: proc() { print_rune(#rune "\n"); }
|
print_nl :: proc() { print_rune(#rune "\n") }
|
||||||
|
|
||||||
print_int :: proc(i: int) {
|
print_int :: proc(i: int) {
|
||||||
print_int_base(i, 10);
|
print_int_base(i, 10);
|
||||||
}
|
}
|
||||||
print_int_base :: proc(i, base: int) {
|
print_int_base :: proc(i, base: int) {
|
||||||
NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
|
NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
|
||||||
|
|
||||||
buf: [65]byte;
|
buf: [65]byte
|
||||||
len := 0;
|
len := 0
|
||||||
negative := false;
|
negative := false
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
negative = true;
|
negative = true
|
||||||
i = -i;
|
i = -i
|
||||||
}
|
}
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
buf[len] = #rune "0";
|
buf[len] = #rune "0"
|
||||||
len++;
|
len++
|
||||||
}
|
}
|
||||||
for i > 0 {
|
for i > 0 {
|
||||||
buf[len] = NUM_TO_CHAR_TABLE[i % base];
|
buf[len] = NUM_TO_CHAR_TABLE[i % base]
|
||||||
len++;
|
len++;
|
||||||
i /= base;
|
i /= base
|
||||||
}
|
}
|
||||||
|
|
||||||
if negative {
|
if negative {
|
||||||
buf[len] = #rune "-";
|
buf[len] = #rune "-"
|
||||||
len++;
|
len++
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_reverse(buf[:len]);
|
byte_reverse(buf[:len])
|
||||||
print_string(buf[:len] as string);
|
print_string(buf[:len] as string)
|
||||||
}
|
}
|
||||||
|
|
||||||
print_uint :: proc(i: uint) {
|
print_uint :: proc(i: uint) {
|
||||||
print__uint(i, 10, 0, #rune " ");
|
print__uint(i, 10, 0, #rune " ")
|
||||||
}
|
}
|
||||||
print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) {
|
print__uint :: proc(i, base: uint, min_width: int, pad_char: byte) {
|
||||||
NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
|
NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
|
||||||
|
|
||||||
buf: [65]byte;
|
buf: [65]byte
|
||||||
len := 0;
|
len := 0
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
buf[len] = #rune "0";
|
buf[len] = #rune "0"
|
||||||
len++;
|
len++
|
||||||
}
|
}
|
||||||
for i > 0 {
|
for i > 0 {
|
||||||
buf[len] = NUM_TO_CHAR_TABLE[i % base];
|
buf[len] = NUM_TO_CHAR_TABLE[i % base]
|
||||||
len++;
|
len++
|
||||||
i /= base;
|
i /= base
|
||||||
}
|
}
|
||||||
for len < min_width {
|
for len < min_width {
|
||||||
buf[len] = pad_char;
|
buf[len] = pad_char
|
||||||
len++;
|
len++
|
||||||
}
|
}
|
||||||
|
|
||||||
byte_reverse(buf[:len]);
|
byte_reverse(buf[:len])
|
||||||
print_string(buf[:len] as string);
|
print_string(buf[:len] as string)
|
||||||
}
|
}
|
||||||
|
|
||||||
print_bool :: proc(b : bool) {
|
print_bool :: proc(b : bool) {
|
||||||
if b { print_string("true"); }
|
if b { print_string("true") }
|
||||||
else { print_string("false"); }
|
else { print_string("false") }
|
||||||
}
|
}
|
||||||
|
|
||||||
print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " "); }
|
print_pointer :: proc(p: rawptr) #inline { print__uint(p as uint, 16, 0, #rune " ") }
|
||||||
|
|
||||||
print_f32 :: proc(f: f32) #inline { print__f64(f as f64, 7); }
|
print_f32 :: proc(f: f32) #inline { print__f64(f as f64, 7) }
|
||||||
print_f64 :: proc(f: f64) #inline { print__f64(f, 10); }
|
print_f64 :: proc(f: f64) #inline { print__f64(f, 10) }
|
||||||
|
|
||||||
print__f64 :: proc(f: f64, decimal_places: int) {
|
print__f64 :: proc(f: f64, decimal_places: int) {
|
||||||
if f == 0 {
|
if f == 0 {
|
||||||
print_rune(#rune "0");
|
print_rune(#rune "0")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if f < 0 {
|
if f < 0 {
|
||||||
print_rune(#rune "-");
|
print_rune(#rune "-")
|
||||||
f = -f;
|
f = -f
|
||||||
}
|
}
|
||||||
|
|
||||||
print_u64 :: proc(i: u64) {
|
print_u64 :: proc(i: u64) {
|
||||||
NUM_TO_CHAR_TABLE :: "0123456789";
|
NUM_TO_CHAR_TABLE :: "0123456789"
|
||||||
|
|
||||||
buf: [22]byte;
|
buf: [22]byte
|
||||||
len := 0;
|
len := 0
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
buf[len] = #rune "0";
|
buf[len] = #rune "0"
|
||||||
len++;
|
len++
|
||||||
}
|
}
|
||||||
for i > 0 {
|
for i > 0 {
|
||||||
buf[len] = NUM_TO_CHAR_TABLE[i % 10];
|
buf[len] = NUM_TO_CHAR_TABLE[i % 10]
|
||||||
len++;
|
len++
|
||||||
i /= 10;
|
i /= 10
|
||||||
}
|
}
|
||||||
byte_reverse(buf[:len]);
|
byte_reverse(buf[:len])
|
||||||
print_string(buf[:len] as string);
|
print_string(buf[:len] as string)
|
||||||
}
|
}
|
||||||
|
|
||||||
i := f as u64;
|
i := f as u64
|
||||||
print_u64(i);
|
print_u64(i)
|
||||||
f -= i as f64;
|
f -= i as f64
|
||||||
|
|
||||||
print_rune(#rune ".");
|
print_rune(#rune ".")
|
||||||
|
|
||||||
mult := 10.0;
|
mult := 10.0
|
||||||
for decimal_places := 6; decimal_places >= 0; decimal_places-- {
|
for decimal_places := 6; decimal_places >= 0; decimal_places-- {
|
||||||
i = (f * mult) as u64;
|
i = (f * mult) as u64
|
||||||
print_u64(i as u64);
|
print_u64(i as u64)
|
||||||
f -= i as f64 / mult;
|
f -= i as f64 / mult
|
||||||
mult *= 10;
|
mult *= 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-745
@@ -3,760 +3,28 @@
|
|||||||
#load "game.odin"
|
#load "game.odin"
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
// _ = hellope();
|
|
||||||
// variables();
|
|
||||||
// procedures();
|
|
||||||
// constants();
|
|
||||||
// types();
|
|
||||||
// data_control();
|
|
||||||
// using_fields();
|
|
||||||
|
|
||||||
Entity :: type struct {
|
|
||||||
guid: u64;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
Frog :: type struct {
|
|
||||||
using entity: Entity;
|
|
||||||
jump_height: f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
e: Entity;
|
|
||||||
frog : Frog;
|
|
||||||
frog.name = "Ribbit";
|
|
||||||
|
|
||||||
a: [16]u32;
|
|
||||||
x := ^a[1];
|
|
||||||
y := ^a[5];
|
|
||||||
d := ptr_sub(y, ptr_offset(x, 1));
|
|
||||||
print_int(d); nl();
|
|
||||||
|
|
||||||
Thing :: type struct {
|
Thing :: type struct {
|
||||||
CONSTANT :: 123;
|
using x: struct { a, b: int }
|
||||||
Thing :: type struct {
|
|
||||||
y: f32;
|
|
||||||
|
|
||||||
z: int;
|
|
||||||
w: int;
|
|
||||||
}
|
|
||||||
|
|
||||||
x: Thing;
|
|
||||||
}
|
|
||||||
|
|
||||||
test :: proc() -> int {
|
|
||||||
t_outer: Thing;
|
|
||||||
t_outer.x = Thing.Thing{};
|
|
||||||
using Thing;
|
|
||||||
t_inner: Thing;
|
|
||||||
t_inner.y = 1;
|
|
||||||
print_int(CONSTANT); nl();
|
|
||||||
return CONSTANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
test__ := test();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// run_game();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
hellope :: proc() -> int {
|
|
||||||
print_string("Hellope, 世界\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Line comment
|
|
||||||
/*
|
|
||||||
Block Comment
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Nested /*
|
|
||||||
Block /*
|
|
||||||
Comment
|
|
||||||
*/
|
|
||||||
*/
|
|
||||||
*/
|
|
||||||
|
|
||||||
apple, banana, carrot: bool;
|
|
||||||
box, carboard: bool = true, false;
|
|
||||||
hellope_value: int = hellope(); // The procedure is ran just before `main`
|
|
||||||
|
|
||||||
variables :: proc() {
|
|
||||||
i: int; // initialized with zero value
|
|
||||||
j: int = 1;
|
|
||||||
x, y: int = 1, 2;
|
|
||||||
|
|
||||||
// Type inference
|
|
||||||
apple, banana, 世界 := true, 123, "world";
|
|
||||||
|
|
||||||
|
|
||||||
// Basic Types of the Language
|
|
||||||
//
|
|
||||||
// bool
|
|
||||||
//
|
|
||||||
// i8 i16 i32 i64 i128
|
|
||||||
// u8 u16 u32 u64 u128
|
|
||||||
//
|
|
||||||
// f32 f64
|
|
||||||
//
|
|
||||||
// int uint (size_of(int) == size_of(uint) == size_of(rawptr))
|
|
||||||
//
|
|
||||||
// rawptr (equivalent to void * in C/C++)
|
|
||||||
//
|
|
||||||
// string
|
|
||||||
//
|
|
||||||
// byte - alias for u8
|
|
||||||
// rune - alias for i32 // Unicode Codepoint
|
|
||||||
//
|
|
||||||
// "untyped" types can implicitly convert to any of the "typed" types
|
|
||||||
// Default Type
|
|
||||||
// untyped bool - bool
|
|
||||||
// untyped integer - int
|
|
||||||
// untyped float - f64
|
|
||||||
// untyped pointer - rawptr
|
|
||||||
// untyped string - string
|
|
||||||
// untyped rune - rune/i32
|
|
||||||
|
|
||||||
|
|
||||||
// Zero values
|
|
||||||
zero_numeric := 0;
|
|
||||||
zero_boolean := false;
|
|
||||||
zero_pointer := null;
|
|
||||||
zero_string1 := ""; // Escaped string
|
|
||||||
zero_string2 := ``; // Raw string
|
|
||||||
// Compound types have a different kind of zero value
|
|
||||||
|
|
||||||
// Unary operators
|
|
||||||
// +a
|
|
||||||
// -a
|
|
||||||
// ~a
|
|
||||||
// !a
|
|
||||||
|
|
||||||
// Binary operators
|
|
||||||
// a + b add
|
|
||||||
// a - b sub
|
|
||||||
// a ~ b xor
|
|
||||||
// a | b or
|
|
||||||
|
|
||||||
// a * b mul
|
|
||||||
// a / b quo
|
|
||||||
// a % b mod
|
|
||||||
// a & b and
|
|
||||||
// a &~ b bitclear == a & (~b)
|
|
||||||
// a << b shl
|
|
||||||
// a >> b shr
|
|
||||||
|
|
||||||
// a as Type // Type cast
|
|
||||||
// a transmute Type // Bit cast
|
|
||||||
|
|
||||||
// a == b eq
|
|
||||||
// a != b ne
|
|
||||||
// a < b lt
|
|
||||||
// a > b gt
|
|
||||||
// a <= b le
|
|
||||||
// a >= b ge
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
procedures :: proc() {
|
|
||||||
add :: proc(x: int, y: int) -> int {
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
print_int(add(3, 4)); // 7
|
|
||||||
print_nl();
|
|
||||||
|
|
||||||
add_v2 :: proc(x, y: int) -> int {
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
fibonacci :: proc(n: int) -> int {
|
|
||||||
if n < 2 {
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
return fibonacci(n-1) + fibonacci(n-2);
|
|
||||||
}
|
|
||||||
print_int(fibonacci(12)); nl();
|
|
||||||
|
|
||||||
|
|
||||||
swap_strings :: proc(x, y: string) -> (string, string) {
|
|
||||||
return y, x;
|
|
||||||
}
|
|
||||||
a, b := swap_strings("Hellope\n", "World\n");
|
|
||||||
print_string(a);
|
|
||||||
print_string(b);
|
|
||||||
|
|
||||||
a, b = b, a; // Quirk of grammar the of multiple assignments
|
|
||||||
// Swap variables
|
|
||||||
print_string(a);
|
|
||||||
print_string(b);
|
|
||||||
|
|
||||||
// Not a hint like C/C++, it's mandatory (unless it cannot do it but it will warn)
|
|
||||||
proc1 :: proc(a, b: int) #inline {
|
|
||||||
print_int(a + b);
|
|
||||||
}
|
|
||||||
proc2 :: proc(a, b: int) #no_inline {
|
|
||||||
print_int(a + b);
|
|
||||||
}
|
|
||||||
|
|
||||||
print_int(3 ''add 4); // Infix style
|
|
||||||
print_nl();
|
|
||||||
print_int(12 'fibonacci); // Postfix style
|
|
||||||
print_nl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TAU :: 6.28318530718;
|
|
||||||
|
|
||||||
constants :: proc() {
|
|
||||||
TAU :: 6.28318530718; // untyped float
|
|
||||||
WORLD_JAPANESE :: "世界"; // untyped string
|
|
||||||
|
|
||||||
TAU_32 : f32 : 6.28318530718;
|
|
||||||
TAU_AS_32 :: 6.28318530718 as f32;
|
|
||||||
|
|
||||||
PI :: TAU / 2;
|
|
||||||
|
|
||||||
CLOSE_TO_PI :: 3;
|
|
||||||
|
|
||||||
DIFF :: (PI - CLOSE_TO_PI) / PI; // Evaluated at compile time
|
|
||||||
|
|
||||||
a := TAU; // the constant's value becomes typed as f64
|
|
||||||
b := CLOSE_TO_PI; // the constant's value becomes typed as int
|
|
||||||
c := DIFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
nl :: proc() { print_nl(); }
|
|
||||||
|
|
||||||
types :: proc() {
|
|
||||||
|
|
||||||
x: int = 123;
|
|
||||||
y := x; // y: int = x;
|
|
||||||
// z: f32 = x; // invalid
|
|
||||||
z: f32 = x as f32;
|
|
||||||
|
|
||||||
|
|
||||||
ptr_z := ^z; // Pascal notation
|
|
||||||
ptr_z^ = 123; // Derefence Notation
|
|
||||||
w: f32 = ptr_z^; // 123
|
|
||||||
print_f32(z); nl();
|
|
||||||
|
|
||||||
// ^z - pointer to z
|
|
||||||
// z^ - z from pointer
|
|
||||||
|
|
||||||
// Implicit conversion to and from rawptr
|
|
||||||
r_ptr: rawptr = ptr_z;
|
|
||||||
ptr_z = r_ptr;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
f32_array: [12]f32; // Array of 12 f32
|
|
||||||
f32_array[0] = 2;
|
|
||||||
f32_array[1] = 3;
|
|
||||||
// f32_array[-1] = 2; // Error - compile time check
|
|
||||||
// f32_array[13] = 2; // Error - compile time check
|
|
||||||
f32_array_len := len(f32_array); // builtin procedure
|
|
||||||
f32_array_cap := cap(f32_array); // == len(f32_array)
|
|
||||||
|
|
||||||
|
|
||||||
mda: [2][3][4]int; // Column-major
|
|
||||||
// mda[x][y][z]
|
|
||||||
|
|
||||||
|
|
||||||
api: [2]^f32;
|
|
||||||
papi: ^[2]^f32;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
f32_slice: []f32; // Slice / Array reference
|
|
||||||
f32_slice = f32_array[0:5];
|
|
||||||
f32_slice = f32_array[:5];
|
|
||||||
f32_slice = f32_array[:]; // f32_array[0:len(f32_array)-1];
|
|
||||||
|
|
||||||
f32_slice = f32_array[1:5:7]; // low:1, high:5, max:7
|
|
||||||
// len: 5-1 == 4
|
|
||||||
// cap: 7-1 == 6
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
append_success := append(^f32_slice, 1);
|
|
||||||
_ = append(^f32_slice, 2);
|
|
||||||
|
|
||||||
_ = copy(f32_array[0:2], f32_array[2:4]); // You can use memcpy/memmove if you want
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
s := "Hellope World";
|
|
||||||
sub_string: string = s[5:10];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
v0: {4}f32; // Vector of 4 f32
|
|
||||||
v0[0] = 1;
|
|
||||||
v0[1] = 3;
|
|
||||||
v0[2] = 6;
|
|
||||||
v0[3] = 10;
|
|
||||||
|
|
||||||
v1 := v0 + v0; // Simd Arithmetic
|
|
||||||
v1 = v1 - v0;
|
|
||||||
v1 *= v0; // i.e. hadamard product
|
|
||||||
v1 /= v0;
|
|
||||||
|
|
||||||
// builtin procedure
|
|
||||||
v2 := swizzle(v0, 3, 2, 1, 0); // {10, 6, 3, 1}
|
|
||||||
|
|
||||||
v3: {4}bool = v0 == v2;
|
|
||||||
// LLVM rant?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Vec4 :: type {4}f32;
|
|
||||||
Array3Int :: type [3]int;
|
|
||||||
|
|
||||||
Vec3 :: type struct {
|
|
||||||
x, y, z: f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryNode :: type struct {
|
|
||||||
left, right: ^BinaryNode; // same format as procedure argument
|
|
||||||
data: rawptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddProc :: type proc(a, b: int) -> int
|
|
||||||
|
|
||||||
Packed :: type struct #packed {
|
|
||||||
a: u8;
|
|
||||||
b: u16;
|
|
||||||
c: u32;
|
|
||||||
}
|
|
||||||
static_assert(size_of(Packed) == 7); // builtin procedure
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
MyInt :: type int;
|
|
||||||
x: int = 1;
|
|
||||||
y: MyInt = 2;
|
|
||||||
// z := x + y; // Failure - types cannot implicit convert*
|
|
||||||
z := x as MyInt + y; // Type cast using `as`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
// From: Quake III Arena
|
|
||||||
Q_rsqrt :: proc(number: f32) -> f32 {
|
|
||||||
i: i32;
|
|
||||||
x2, y: f32;
|
|
||||||
THREE_HALFS :: 1.5;
|
|
||||||
|
|
||||||
x2 = number * 0.5;
|
|
||||||
y = number;
|
|
||||||
i = (^y as ^i32)^; // evil floating point bit level hacking
|
|
||||||
i = 0x5f3759df - i>>1; // what the fuck?
|
|
||||||
y = (^i as ^f32)^;
|
|
||||||
y = y * (THREE_HALFS - (x2 * y *y)); // 1st iteration
|
|
||||||
// y = y * (THREE_HALFS - (x2 * y *y)); // 2nd iteration, this can be removed
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_rsqrt_v2 :: proc(number: f32) -> f32 {
|
|
||||||
THREE_HALFS :: 1.5;
|
|
||||||
|
|
||||||
x2 := number * 0.5;
|
|
||||||
y := number;
|
|
||||||
i := y transmute i32; // evil floating point bit level hacking
|
|
||||||
i = 0x5f3759df - i>>1; // what the fuck?
|
|
||||||
y = i transmute f32;
|
|
||||||
y = y * (THREE_HALFS - (x2 * y *y)); // 1st iteration
|
|
||||||
// y = y * (THREE_HALFS - (x2 * y *y)); // 2nd iteration, this can be removed
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): transmute only works if the size of the types are equal
|
|
||||||
|
|
||||||
/*
|
|
||||||
// in C
|
|
||||||
union {
|
|
||||||
i32 i;
|
|
||||||
f32 y;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Enumeration
|
|
||||||
Thing :: type enum {
|
|
||||||
APPLE,
|
|
||||||
FROG,
|
|
||||||
TREE,
|
|
||||||
TOMB,
|
|
||||||
}
|
|
||||||
a := Thing.APPLE;
|
|
||||||
|
|
||||||
Sized :: type enum u64 {
|
|
||||||
APPLE,
|
|
||||||
FROG,
|
|
||||||
TREE,
|
|
||||||
TOMB,
|
|
||||||
}
|
|
||||||
static_assert(size_of(Sized) == size_of(u64));
|
|
||||||
|
|
||||||
Certain :: type enum {
|
|
||||||
APPLE = 3,
|
|
||||||
FROG,
|
|
||||||
TREE = 7,
|
|
||||||
TOMB,
|
|
||||||
}
|
|
||||||
static_assert(Certain.TOMB == 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Untagged union
|
|
||||||
BitHack :: type union {
|
|
||||||
i: i32;
|
|
||||||
f: f32;
|
|
||||||
}
|
|
||||||
b: BitHack;
|
|
||||||
b.f = 123;
|
|
||||||
print_int_base(b.i as int, 16); print_nl();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Manually tagged union
|
|
||||||
|
|
||||||
EntityKind :: type enum {
|
|
||||||
Invalid,
|
|
||||||
Constant,
|
|
||||||
Variable,
|
|
||||||
TypeName,
|
|
||||||
Procedure,
|
|
||||||
Builtin,
|
|
||||||
Count,
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity :: type struct {
|
|
||||||
kind: EntityKind;
|
|
||||||
guid: u64;
|
|
||||||
|
|
||||||
// Other data
|
|
||||||
|
|
||||||
/*using*/
|
|
||||||
data: union {
|
|
||||||
constant: struct{};
|
|
||||||
variable: struct{
|
|
||||||
visited, is_field, used, anonymous: bool;
|
|
||||||
};
|
|
||||||
procedure: struct { used: bool; };
|
|
||||||
buitlin: struct { id: i32; };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Tagged unions are not added yet but are planned
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ // Compound Literals
|
|
||||||
a := [3]int{1, 2, 3};
|
|
||||||
b := [3]int{};
|
|
||||||
c := [..]int{1, 2, 3};
|
|
||||||
|
|
||||||
d := []int{1, 2, 3}; // slice
|
|
||||||
|
|
||||||
e := {4}f32{1, 2, 3, 4};
|
|
||||||
f := {4}f32{1}; // broadcasts to all
|
|
||||||
// g := {4}f32{1, 2}; // require either 1 or 4 elements
|
|
||||||
|
|
||||||
Vec2 :: type {2}f32;
|
|
||||||
|
|
||||||
h := Vec2{1, 2};
|
|
||||||
|
|
||||||
i := Vec2{5} * h; // For strong type safety
|
|
||||||
// FORENOTE: 5 * h was originally allowed but it was an edge case in the
|
|
||||||
// compiler I didn't think it was enough to justify have it it.
|
|
||||||
|
|
||||||
print_f32(i[0]); print_rune(#rune ",");
|
|
||||||
print_f32(i[1]); print_nl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ // First class procedures
|
|
||||||
|
|
||||||
do_thing :: proc(p: proc(a, b: int) -> int) {
|
|
||||||
print_int(p(3, 4)); nl();
|
|
||||||
}
|
|
||||||
|
|
||||||
add :: proc(a, b: int) -> int {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
add_lambda := proc(a, b: int) -> int {
|
|
||||||
return a - b;
|
|
||||||
}; // note semicolon
|
|
||||||
|
|
||||||
do_thing(add);
|
|
||||||
do_thing(add_lambda);
|
|
||||||
do_thing(proc(a, b: int) -> int { // Anonymous
|
|
||||||
return a * b;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ // strings and runes
|
|
||||||
escaped := "Hellope World\n";
|
|
||||||
raw := `Hellope World\n`;
|
|
||||||
print_string(escaped);
|
|
||||||
print_string(raw); nl();
|
|
||||||
|
|
||||||
// Crap shader example
|
|
||||||
shader_string :=
|
|
||||||
`#version 410
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 a_position;
|
|
||||||
layout (location = 1) in vec3 a_normal;
|
|
||||||
layout (location = 2) in vec2 a_tex_coord;
|
|
||||||
|
|
||||||
out vec3 v_position;
|
|
||||||
out vec3 v_normal;
|
|
||||||
out vec2 v_tex_coord;
|
|
||||||
|
|
||||||
uniform mat4 u_model_view;
|
|
||||||
uniform mat3 u_normal;
|
|
||||||
uniform mat4 u_proj;
|
|
||||||
uniform mat4 u_mvp;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
v_tex_coord = a_tex_coord;
|
|
||||||
v_normal = normalize(u_normal * a_normal);
|
|
||||||
v_position = vec3(u_model_view * vec4(a_position, 1.0));
|
|
||||||
|
|
||||||
gl_Position = u_mvp * vec4(a_position, 1.0);
|
|
||||||
}`;
|
|
||||||
|
|
||||||
|
|
||||||
hearts1 := #rune "💕";
|
|
||||||
hearts2 := #rune "\U0001f495"; // 32 bit
|
|
||||||
hearts3 := #rune "\xf0\x9f\x92\x95";
|
|
||||||
|
|
||||||
㐒 := #rune "㐒";
|
|
||||||
㐒16 := #rune "\u4db5"; // 16 bit but will be `rune`
|
|
||||||
// String ideas "nicked" from Go, so far. I think I might change how some of it works later.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{ // size, align, offset
|
|
||||||
Thing :: type struct {
|
|
||||||
a: u8;
|
|
||||||
b: u16;
|
|
||||||
c, d, e: u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
s := size_of(Thing);
|
|
||||||
a := align_of(Thing);
|
|
||||||
o := offset_of(Thing, b);
|
|
||||||
|
|
||||||
t: Thing;
|
|
||||||
|
|
||||||
sv := size_of_val(t);
|
|
||||||
av := align_of_val(t);
|
|
||||||
ov := offset_of_val(t.b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data_control :: proc() {
|
|
||||||
sum := 0;
|
|
||||||
for i := 0; i < 12; i++ {
|
|
||||||
sum += 1;
|
|
||||||
}
|
|
||||||
print_string("sum = "); print_int(sum); nl();
|
|
||||||
|
|
||||||
sum = 1;
|
|
||||||
for ; sum < 1000000; {
|
|
||||||
sum += sum;
|
|
||||||
}
|
|
||||||
print_string("sum = "); print_int(sum); nl();
|
|
||||||
|
|
||||||
sum = 1;
|
|
||||||
for sum < 1000000 {
|
|
||||||
sum += sum;
|
|
||||||
}
|
|
||||||
print_string("sum = "); print_int(sum); nl();
|
|
||||||
|
|
||||||
// loop
|
|
||||||
// for { } == for true {}
|
|
||||||
|
|
||||||
// Question: Should I separate all these concepts and rename it?
|
|
||||||
//
|
|
||||||
// range - iterable
|
|
||||||
// for - c style
|
|
||||||
// while
|
|
||||||
// loop - while true
|
|
||||||
|
|
||||||
// Notes:
|
|
||||||
// conditions _must_ a boolean expression
|
|
||||||
// i++ and i-- are statements, not expressions
|
|
||||||
|
|
||||||
|
|
||||||
x := 2;
|
|
||||||
if x < 3 {
|
|
||||||
print_string("x < 2\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unified initializer syntax - same as for statements
|
|
||||||
if x := 2; x < 3 {
|
|
||||||
print_string("x < 2\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if x := 4; x < 3 {
|
|
||||||
print_string("Never called\n");
|
|
||||||
} else {
|
|
||||||
print_string("This is called\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // String comparison
|
|
||||||
a := "Hellope";
|
|
||||||
b := "World";
|
|
||||||
if a < b {
|
|
||||||
print_string("a < b\n");
|
|
||||||
}
|
|
||||||
if a != b {
|
|
||||||
print_string("a != b\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ // Defer statement
|
|
||||||
defer print_string("日本語\n");
|
|
||||||
print_string("Japanese\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
defer print_string("1\n");
|
using t := new(Thing)
|
||||||
defer print_string("2\n");
|
defer delete(t)
|
||||||
defer print_string("3\n");
|
a = 321
|
||||||
|
print_int(a); nl()
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
// {
|
||||||
prev_allocator := context.allocator;
|
// using t := new(Thing)
|
||||||
context.allocator = __default_allocator();
|
// defer delete(t)
|
||||||
defer context.allocator = prev_allocator;
|
// a = 1337
|
||||||
|
// print_int(a); nl()
|
||||||
|
// }
|
||||||
|
|
||||||
File :: type struct { filename: string; };
|
// run_game()
|
||||||
FileError :: type int;
|
|
||||||
open_file :: proc(filename: string) -> (File, FileError) {
|
|
||||||
return File{}, 0;
|
|
||||||
}
|
|
||||||
close_file :: proc(f: ^File) {}
|
|
||||||
f, err := open_file("Test");
|
|
||||||
if err != 0 {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
defer close_file(^f);
|
|
||||||
|
|
||||||
// Rest of code!!!
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
blah := new(int);
|
|
||||||
defer {
|
|
||||||
defer print_string("!");
|
|
||||||
defer print_int(i);
|
|
||||||
defer print_string("dealloc");
|
|
||||||
delete(blah);
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == 3 {
|
|
||||||
// defers called
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == 5 {
|
|
||||||
// defers called
|
|
||||||
return; // End of procedure
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == 8 {
|
|
||||||
// defers called
|
|
||||||
break; // never happens
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer print_string("It'll never happen, mate 1");
|
|
||||||
print_string("It'll never happen, mate 2");
|
|
||||||
print_string("It'll never happen, mate 3");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using_fields :: proc() {
|
nl :: proc() #inline { print_nl() }
|
||||||
{ // Everyday stuff
|
|
||||||
Vec3 :: type struct { x, y, z: f32; }
|
|
||||||
|
|
||||||
Entity :: type struct {
|
|
||||||
name: string;
|
|
||||||
using pos: Vec3;
|
|
||||||
vel: Vec3;
|
|
||||||
}
|
|
||||||
t: Entity;
|
|
||||||
t.y = 456;
|
|
||||||
print_f32(t.y); print_nl();
|
|
||||||
print_f32(t.pos.y); print_nl();
|
|
||||||
print_f32(t.vel.y); print_nl();
|
|
||||||
|
|
||||||
|
|
||||||
Frog :: type struct { // Subtype (kind of)
|
|
||||||
using entity: Entity;
|
|
||||||
colour: u32;
|
|
||||||
jump_height: f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
f: Frog;
|
|
||||||
f.y = 1337;
|
|
||||||
print_f32(f.y); print_nl();
|
|
||||||
print_f32(f.pos.y); print_nl();
|
|
||||||
print_f32(f.vel.y); print_nl();
|
|
||||||
|
|
||||||
|
|
||||||
Buffalo :: type struct {
|
|
||||||
using entity: Entity;
|
|
||||||
speed: f32;
|
|
||||||
noise_level: f32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{ // Crazy Shit
|
|
||||||
Vec2 :: type union {
|
|
||||||
using _xy: struct { x, y: f32; };
|
|
||||||
e: [2]f32;
|
|
||||||
v: {2}f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity :: type struct {
|
|
||||||
using pos: ^Vec2;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
t: Entity;
|
|
||||||
t.pos = new(Vec2);
|
|
||||||
defer delete(t.pos);
|
|
||||||
t.x = 123;
|
|
||||||
print_f32(t._xy.x); print_nl();
|
|
||||||
print_f32(t.pos.x); print_nl();
|
|
||||||
print_f32(t.pos._xy.x); print_nl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+44
-44
@@ -1,37 +1,37 @@
|
|||||||
#load "win32.odin"
|
#load "win32.odin"
|
||||||
|
|
||||||
File :: type struct {
|
File :: type struct {
|
||||||
Handle :: type HANDLE;
|
Handle :: type HANDLE
|
||||||
handle: Handle;
|
handle: Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
file_open :: proc(name: string) -> (File, bool) {
|
file_open :: proc(name: string) -> (File, bool) {
|
||||||
buf: [300]byte;
|
buf: [300]byte
|
||||||
_ = copy(buf[:], name as []byte);
|
_ = copy(buf[:], name as []byte)
|
||||||
f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)};
|
f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}
|
||||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle;
|
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
||||||
|
|
||||||
return f, success;
|
return f, success
|
||||||
}
|
}
|
||||||
|
|
||||||
file_create :: proc(name: string) -> (File, bool) {
|
file_create :: proc(name: string) -> (File, bool) {
|
||||||
buf: [300]byte;
|
buf: [300]byte
|
||||||
_ = copy(buf[:], name as []byte);
|
_ = copy(buf[:], name as []byte)
|
||||||
f := File{
|
f := File{
|
||||||
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
|
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
|
||||||
};
|
}
|
||||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle;
|
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
||||||
return f, success;
|
return f, success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
file_close :: proc(f: ^File) {
|
file_close :: proc(f: ^File) {
|
||||||
CloseHandle(f.handle);
|
CloseHandle(f.handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
file_write :: proc(f: ^File, buf: []byte) -> bool {
|
file_write :: proc(f: ^File, buf: []byte) -> bool {
|
||||||
bytes_written: i32;
|
bytes_written: i32
|
||||||
return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0;
|
return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
FileStandard :: type enum {
|
FileStandard :: type enum {
|
||||||
@@ -47,60 +47,60 @@ __std_files: [FileStandard.COUNT as int]File;
|
|||||||
file_get_standard :: proc(std: FileStandard) -> ^File {
|
file_get_standard :: proc(std: FileStandard) -> ^File {
|
||||||
// using FileStandard;
|
// using FileStandard;
|
||||||
if (!__std_file_set) {
|
if (!__std_file_set) {
|
||||||
using FileStandard;
|
using FileStandard
|
||||||
__std_files[INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE);
|
__std_files[INPUT] .handle = GetStdHandle(STD_INPUT_HANDLE)
|
||||||
__std_files[OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
__std_files[OUTPUT].handle = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||||
__std_files[ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE);
|
__std_files[ERROR] .handle = GetStdHandle(STD_ERROR_HANDLE)
|
||||||
__std_file_set = true;
|
__std_file_set = true
|
||||||
}
|
}
|
||||||
return ^__std_files[std];
|
return ^__std_files[std]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
read_entire_file :: proc(name: string) -> (string, bool) {
|
read_entire_file :: proc(name: string) -> (string, bool) {
|
||||||
buf: [300]byte;
|
buf: [300]byte
|
||||||
_ = copy(buf[:], name as []byte);
|
_ = copy(buf[:], name as []byte)
|
||||||
c_string := ^buf[0];
|
c_string := ^buf[0]
|
||||||
|
|
||||||
|
|
||||||
f, file_ok := file_open(name);
|
f, file_ok := file_open(name)
|
||||||
if !file_ok {
|
if !file_ok {
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
defer file_close(^f);
|
defer file_close(^f)
|
||||||
|
|
||||||
length: i64;
|
length: i64
|
||||||
file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0;
|
file_size_ok := GetFileSizeEx(f.handle as HANDLE, ^length) != 0
|
||||||
if !file_size_ok {
|
if !file_size_ok {
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new_slice(u8, length);
|
data := new_slice(u8, length)
|
||||||
if ^data[0] == null {
|
if ^data[0] == null {
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
single_read_length: i32;
|
single_read_length: i32
|
||||||
total_read: i64;
|
total_read: i64
|
||||||
|
|
||||||
for total_read < length {
|
for total_read < length {
|
||||||
remaining := length - total_read;
|
remaining := length - total_read
|
||||||
to_read: u32;
|
to_read: u32
|
||||||
MAX :: 0x7fffffff;
|
MAX :: 0x7fffffff
|
||||||
if remaining <= MAX {
|
if remaining <= MAX {
|
||||||
to_read = remaining as u32;
|
to_read = remaining as u32
|
||||||
} else {
|
} else {
|
||||||
to_read = MAX;
|
to_read = MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null);
|
ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null)
|
||||||
if single_read_length <= 0 {
|
if single_read_length <= 0 {
|
||||||
delete(data);
|
delete(data)
|
||||||
return "", false;
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
total_read += single_read_length as i64;
|
total_read += single_read_length as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
return data as string, true;
|
return data as string, true
|
||||||
}
|
}
|
||||||
|
|||||||
+89
-89
@@ -2,55 +2,55 @@
|
|||||||
#load "opengl.odin"
|
#load "opengl.odin"
|
||||||
#load "math.odin"
|
#load "math.odin"
|
||||||
|
|
||||||
TWO_HEARTS :: #rune "💕";
|
TWO_HEARTS :: #rune "💕"
|
||||||
|
|
||||||
win32_perf_count_freq := GetQueryPerformanceFrequency();
|
win32_perf_count_freq := GetQueryPerformanceFrequency()
|
||||||
time_now :: proc() -> f64 {
|
time_now :: proc() -> f64 {
|
||||||
if win32_perf_count_freq == 0 {
|
if win32_perf_count_freq == 0 {
|
||||||
debug_trap();
|
debug_trap()
|
||||||
}
|
}
|
||||||
|
|
||||||
counter: i64;
|
counter: i64
|
||||||
_ = QueryPerformanceCounter(^counter);
|
_ = QueryPerformanceCounter(^counter)
|
||||||
result := counter as f64 / win32_perf_count_freq as f64;
|
result := counter as f64 / win32_perf_count_freq as f64
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
win32_print_last_error :: proc() {
|
win32_print_last_error :: proc() {
|
||||||
err_code := GetLastError() as int;
|
err_code := GetLastError() as int
|
||||||
if err_code != 0 {
|
if err_code != 0 {
|
||||||
print_string("GetLastError: ");
|
print_string("GetLastError: ")
|
||||||
print_int(err_code);
|
print_int(err_code)
|
||||||
print_string("\n");
|
print_string("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yuk!
|
// Yuk!
|
||||||
to_c_string :: proc(s: string) -> ^u8 {
|
to_c_string :: proc(s: string) -> ^u8 {
|
||||||
c_str: ^u8 = alloc(len(s)+1);
|
c_str: ^u8 = alloc(len(s)+1)
|
||||||
memory_copy(c_str, ^s[0], len(s));
|
memory_copy(c_str, ^s[0], len(s))
|
||||||
ptr_offset(c_str, len(s))^ = 0;
|
ptr_offset(c_str, len(s))^ = 0
|
||||||
return c_str;
|
return c_str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Window :: type struct {
|
Window :: type struct {
|
||||||
width, height: int;
|
width, height: int
|
||||||
wc: WNDCLASSEXA;
|
wc: WNDCLASSEXA
|
||||||
dc: HDC;
|
dc: HDC
|
||||||
hwnd: HWND;
|
hwnd: HWND
|
||||||
opengl_context, rc: HGLRC;
|
opengl_context, rc: HGLRC
|
||||||
c_title: ^u8;
|
c_title: ^u8
|
||||||
}
|
}
|
||||||
|
|
||||||
make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (Window, bool) {
|
make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (Window, bool) {
|
||||||
w: Window;
|
w: Window
|
||||||
w.width, w.height = msg, height;
|
w.width, w.height = msg, height
|
||||||
|
|
||||||
class_name := "Win32-Odin-Window\x00";
|
class_name := "Win32-Odin-Window\x00"
|
||||||
c_class_name := ^class_name[0];
|
c_class_name := ^class_name[0]
|
||||||
w.c_title = to_c_string(title);
|
w.c_title = to_c_string(title)
|
||||||
|
|
||||||
instance := GetModuleHandleA(null);
|
instance := GetModuleHandleA(null)
|
||||||
|
|
||||||
w.wc = WNDCLASSEXA{
|
w.wc = WNDCLASSEXA{
|
||||||
size = size_of(WNDCLASSEXA) as u32,
|
size = size_of(WNDCLASSEXA) as u32,
|
||||||
@@ -61,7 +61,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
|||||||
};
|
};
|
||||||
|
|
||||||
if RegisterClassExA(^w.wc) == 0 {
|
if RegisterClassExA(^w.wc) == 0 {
|
||||||
return w, false;
|
return w, false
|
||||||
}
|
}
|
||||||
|
|
||||||
w.hwnd = CreateWindowExA(0,
|
w.hwnd = CreateWindowExA(0,
|
||||||
@@ -69,14 +69,14 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
|||||||
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
w.width as i32, w.height as i32,
|
w.width as i32, w.height as i32,
|
||||||
null, null, instance, null);
|
null, null, instance, null)
|
||||||
|
|
||||||
if w.hwnd == null {
|
if w.hwnd == null {
|
||||||
win32_print_last_error();
|
win32_print_last_error()
|
||||||
return w, false;
|
return w, false
|
||||||
}
|
}
|
||||||
|
|
||||||
w.dc = GetDC(w.hwnd);
|
w.dc = GetDC(w.hwnd)
|
||||||
|
|
||||||
{
|
{
|
||||||
pfd := PIXELFORMATDESCRIPTOR{
|
pfd := PIXELFORMATDESCRIPTOR{
|
||||||
@@ -89,126 +89,126 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W
|
|||||||
depth_bits = 24,
|
depth_bits = 24,
|
||||||
stencil_bits = 8,
|
stencil_bits = 8,
|
||||||
layer_type = PFD_MAIN_PLANE,
|
layer_type = PFD_MAIN_PLANE,
|
||||||
};
|
}
|
||||||
|
|
||||||
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), null);
|
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), null)
|
||||||
w.opengl_context = wglCreateContext(w.dc);
|
w.opengl_context = wglCreateContext(w.dc)
|
||||||
wglMakeCurrent(w.dc, w.opengl_context);
|
wglMakeCurrent(w.dc, w.opengl_context)
|
||||||
|
|
||||||
attribs := [8]i32{
|
attribs := [8]i32{
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||||
0, // NOTE(bill): tells the proc that this is the end of attribs
|
0, // NOTE(bill): tells the proc that this is the end of attribs
|
||||||
};
|
}
|
||||||
|
|
||||||
wgl_string := "wglCreateContextAttribsARB\x00";
|
wgl_string := "wglCreateContextAttribsARB\x00"
|
||||||
c_wgl_string := ^wgl_string[0];
|
c_wgl_string := ^wgl_string[0]
|
||||||
wglCreateContextAttribsARB := wglGetProcAddress(c_wgl_string) as wglCreateContextAttribsARBType;
|
wglCreateContextAttribsARB := wglGetProcAddress(c_wgl_string) as wglCreateContextAttribsARBType
|
||||||
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
|
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0])
|
||||||
wglMakeCurrent(w.dc, w.rc);
|
wglMakeCurrent(w.dc, w.rc)
|
||||||
SwapBuffers(w.dc);
|
SwapBuffers(w.dc)
|
||||||
}
|
}
|
||||||
|
|
||||||
return w, true;
|
return w, true
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_window :: proc(w: ^Window) {
|
destroy_window :: proc(w: ^Window) {
|
||||||
heap_free(w.c_title);
|
heap_free(w.c_title)
|
||||||
}
|
}
|
||||||
|
|
||||||
display_window :: proc(w: ^Window) {
|
display_window :: proc(w: ^Window) {
|
||||||
SwapBuffers(w.dc);
|
SwapBuffers(w.dc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Entity :: type struct {
|
Entity :: type struct {
|
||||||
pos: Vec2;
|
pos: Vec2
|
||||||
dim: Vec2;
|
dim: Vec2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
run_game :: proc() {
|
run_game :: proc() {
|
||||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
||||||
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
||||||
ExitProcess(0);
|
ExitProcess(0)
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
return DefWindowProcA(hwnd, msg, wparam, lparam)
|
||||||
}
|
}
|
||||||
|
|
||||||
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
|
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc)
|
||||||
if !window_success {
|
if !window_success {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
defer destroy_window(^window);
|
defer destroy_window(^window)
|
||||||
|
|
||||||
|
|
||||||
prev_time := time_now();
|
prev_time := time_now()
|
||||||
running := true;
|
running := true
|
||||||
|
|
||||||
pos := Vec2{100, 100};
|
pos := Vec2{100, 100}
|
||||||
|
|
||||||
for running {
|
for running {
|
||||||
curr_time := time_now();
|
curr_time := time_now()
|
||||||
dt := (curr_time - prev_time) as f32;
|
dt := (curr_time - prev_time) as f32
|
||||||
prev_time = curr_time;
|
prev_time = curr_time
|
||||||
|
|
||||||
msg: MSG;
|
msg: MSG
|
||||||
for PeekMessageA(^msg, null, 0, 0, PM_REMOVE) > 0 {
|
for PeekMessageA(^msg, null, 0, 0, PM_REMOVE) > 0 {
|
||||||
if msg.message == WM_QUIT {
|
if msg.message == WM_QUIT {
|
||||||
running = false;
|
running = false
|
||||||
}
|
}
|
||||||
_ = TranslateMessage(^msg);
|
_ = TranslateMessage(^msg)
|
||||||
_ = DispatchMessageA(^msg);
|
_ = DispatchMessageA(^msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_key_down(VK_ESCAPE) {
|
if is_key_down(VK_ESCAPE) {
|
||||||
running = false;
|
running = false
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
SPEED :: 500;
|
SPEED :: 500
|
||||||
v: Vec2;
|
v: Vec2
|
||||||
|
|
||||||
if is_key_down(VK_RIGHT) { v[0] += 1; }
|
if is_key_down(VK_RIGHT) { v[0] += 1 }
|
||||||
if is_key_down(VK_LEFT) { v[0] -= 1; }
|
if is_key_down(VK_LEFT) { v[0] -= 1 }
|
||||||
if is_key_down(VK_UP) { v[1] += 1; }
|
if is_key_down(VK_UP) { v[1] += 1 }
|
||||||
if is_key_down(VK_DOWN) { v[1] -= 1; }
|
if is_key_down(VK_DOWN) { v[1] -= 1 }
|
||||||
|
|
||||||
v = vec2_norm0(v);
|
v = vec2_norm0(v)
|
||||||
|
|
||||||
pos += v * Vec2{SPEED * dt};
|
pos += v * Vec2{SPEED * dt}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
glClearColor(0.5, 0.7, 1.0, 1.0);
|
glClearColor(0.5, 0.7, 1.0, 1.0)
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT)
|
||||||
|
|
||||||
glLoadIdentity();
|
glLoadIdentity()
|
||||||
glOrtho(0, window.width as f64,
|
glOrtho(0, window.width as f64,
|
||||||
0, window.height as f64, 0, 1);
|
0, window.height as f64, 0, 1)
|
||||||
|
|
||||||
draw_rect :: proc(x, y, w, h: f32) {
|
draw_rect :: proc(x, y, w, h: f32) {
|
||||||
glBegin(GL_TRIANGLES);
|
glBegin(GL_TRIANGLES)
|
||||||
|
|
||||||
glColor3f(1, 0, 0); glVertex3f(x, y, 0);
|
glColor3f(1, 0, 0); glVertex3f(x, y, 0)
|
||||||
glColor3f(0, 1, 0); glVertex3f(x+w, y, 0);
|
glColor3f(0, 1, 0); glVertex3f(x+w, y, 0)
|
||||||
glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0);
|
glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0)
|
||||||
|
|
||||||
glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0);
|
glColor3f(0, 0, 1); glVertex3f(x+w, y+h, 0)
|
||||||
glColor3f(1, 1, 0); glVertex3f(x, y+h, 0);
|
glColor3f(1, 1, 0); glVertex3f(x, y+h, 0)
|
||||||
glColor3f(1, 0, 0); glVertex3f(x, y, 0);
|
glColor3f(1, 0, 0); glVertex3f(x, y, 0)
|
||||||
|
|
||||||
glEnd();
|
glEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_rect(pos[0], pos[1], 50, 50);
|
draw_rect(pos[0], pos[1], 50, 50)
|
||||||
|
|
||||||
display_window(^window);
|
display_window(^window)
|
||||||
ms_to_sleep := (16 - 1000*dt) as i32;
|
ms_to_sleep := (16 - 1000*dt) as i32
|
||||||
if ms_to_sleep > 0 {
|
if ms_to_sleep > 0 {
|
||||||
sleep_ms(ms_to_sleep);
|
sleep_ms(ms_to_sleep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-91
@@ -1,162 +1,162 @@
|
|||||||
MATH_TAU :: 6.28318530717958647692528676655900576;
|
MATH_TAU :: 6.28318530717958647692528676655900576
|
||||||
MATH_PI :: 3.14159265358979323846264338327950288;
|
MATH_PI :: 3.14159265358979323846264338327950288
|
||||||
MATH_ONE_OVER_TAU :: 0.636619772367581343075535053490057448;
|
MATH_ONE_OVER_TAU :: 0.636619772367581343075535053490057448
|
||||||
MATH_ONE_OVER_PI :: 0.159154943091895335768883763372514362;
|
MATH_ONE_OVER_PI :: 0.159154943091895335768883763372514362
|
||||||
|
|
||||||
MATH_E :: 2.71828182845904523536;
|
MATH_E :: 2.71828182845904523536
|
||||||
MATH_SQRT_TWO :: 1.41421356237309504880168872420969808;
|
MATH_SQRT_TWO :: 1.41421356237309504880168872420969808
|
||||||
MATH_SQRT_THREE :: 1.73205080756887729352744634150587236;
|
MATH_SQRT_THREE :: 1.73205080756887729352744634150587236
|
||||||
MATH_SQRT_FIVE :: 2.23606797749978969640917366873127623;
|
MATH_SQRT_FIVE :: 2.23606797749978969640917366873127623
|
||||||
|
|
||||||
MATH_LOG_TWO :: 0.693147180559945309417232121458176568;
|
MATH_LOG_TWO :: 0.693147180559945309417232121458176568
|
||||||
MATH_LOG_TEN :: 2.30258509299404568401799145468436421;
|
MATH_LOG_TEN :: 2.30258509299404568401799145468436421
|
||||||
|
|
||||||
MATH_EPSILON :: 1.19209290e-7;
|
MATH_EPSILON :: 1.19209290e-7
|
||||||
|
|
||||||
τ :: MATH_TAU;
|
τ :: MATH_TAU
|
||||||
π :: MATH_PI;
|
π :: MATH_PI
|
||||||
|
|
||||||
Vec2 :: type {2}f32;
|
Vec2 :: type {2}f32
|
||||||
Vec3 :: type {3}f32;
|
Vec3 :: type {3}f32
|
||||||
Vec4 :: type {4}f32;
|
Vec4 :: type {4}f32
|
||||||
|
|
||||||
Mat2 :: type {4}f32;
|
Mat2 :: type {4}f32
|
||||||
Mat3 :: type {9}f32;
|
Mat3 :: type {9}f32
|
||||||
Mat4 :: type {16}f32;
|
Mat4 :: type {16}f32
|
||||||
|
|
||||||
|
|
||||||
fsqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
fsqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
|
||||||
fsin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
|
fsin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
|
||||||
fcos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
fcos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
|
||||||
flerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
|
flerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t }
|
||||||
fclamp :: proc(x, lower, upper: f32) -> f32 { return fmin(fmax(x, lower), upper); }
|
fclamp :: proc(x, lower, upper: f32) -> f32 { return fmin(fmax(x, lower), upper) }
|
||||||
fclamp01 :: proc(x: f32) -> f32 { return fclamp(x, 0, 1); }
|
fclamp01 :: proc(x: f32) -> f32 { return fclamp(x, 0, 1) }
|
||||||
fabs :: proc(x: f32) -> f32 { if x < 0 { x = -x; } return x; }
|
fabs :: proc(x: f32) -> f32 { if x < 0 { x = -x } return x }
|
||||||
fsign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
fsign :: proc(x: f32) -> f32 { if x >= 0 { return +1 } return -1 }
|
||||||
|
|
||||||
fmin :: proc(a, b: f32) -> f32 { if a < b { return a; } return b; }
|
fmin :: proc(a, b: f32) -> f32 { if a < b { return a } return b }
|
||||||
fmax :: proc(a, b: f32) -> f32 { if a > b { return a; } return b; }
|
fmax :: proc(a, b: f32) -> f32 { if a > b { return a } return b }
|
||||||
fmin3 :: proc(a, b, c: f32) -> f32 { return fmin(fmin(a, b), c); }
|
fmin3 :: proc(a, b, c: f32) -> f32 { return fmin(fmin(a, b), c) }
|
||||||
fmax3 :: proc(a, b, c: f32) -> f32 { return fmax(fmax(a, b), c); }
|
fmax3 :: proc(a, b, c: f32) -> f32 { return fmax(fmax(a, b), c) }
|
||||||
|
|
||||||
|
|
||||||
copy_sign :: proc(x, y: f32) -> f32 {
|
copy_sign :: proc(x, y: f32) -> f32 {
|
||||||
ix := x transmute u32;
|
ix := x transmute u32
|
||||||
iy := y transmute u32;
|
iy := y transmute u32
|
||||||
ix &= 0x7fffffff;
|
ix &= 0x7fffffff
|
||||||
ix |= iy & 0x80000000;
|
ix |= iy & 0x80000000
|
||||||
return ix transmute f32;
|
return ix transmute f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
round :: proc(x: f32) -> f32 {
|
round :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return floor(x + 0.5);
|
return floor(x + 0.5)
|
||||||
}
|
}
|
||||||
return ceil(x - 0.5);
|
return ceil(x - 0.5)
|
||||||
}
|
}
|
||||||
floor :: proc(x: f32) -> f32 {
|
floor :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return x as int as f32;
|
return x as int as f32
|
||||||
}
|
}
|
||||||
return (x-0.5) as int as f32;
|
return (x-0.5) as int as f32
|
||||||
}
|
}
|
||||||
ceil :: proc(x: f32) -> f32 {
|
ceil :: proc(x: f32) -> f32 {
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
return x as int as f32;
|
return x as int as f32
|
||||||
}
|
}
|
||||||
return ((x as int)+1) as f32;
|
return ((x as int)+1) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
remainder :: proc(x, y: f32) -> f32 {
|
remainder :: proc(x, y: f32) -> f32 {
|
||||||
return x - round(x/y) * y;
|
return x - round(x/y) * y
|
||||||
}
|
}
|
||||||
|
|
||||||
fmod :: proc(x, y: f32) -> f32 {
|
fmod :: proc(x, y: f32) -> f32 {
|
||||||
y = fabs(y);
|
y = fabs(y)
|
||||||
result := remainder(fabs(x), y);
|
result := remainder(fabs(x), y)
|
||||||
if fsign(result) < 0 {
|
if fsign(result) < 0 {
|
||||||
result += y;
|
result += y
|
||||||
}
|
}
|
||||||
return copy_sign(result, x);
|
return copy_sign(result, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
to_radians :: proc(degrees: f32) -> f32 { return degrees * MATH_TAU / 360; }
|
to_radians :: proc(degrees: f32) -> f32 { return degrees * MATH_TAU / 360 }
|
||||||
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU; }
|
to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / MATH_TAU }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1]; }
|
dot2 :: proc(a, b: Vec2) -> f32 { c := a*b; return c[0] + c[1] }
|
||||||
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2]; }
|
dot3 :: proc(a, b: Vec3) -> f32 { c := a*b; return c[0] + c[1] + c[2] }
|
||||||
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3]; }
|
dot4 :: proc(a, b: Vec4) -> f32 { c := a*b; return c[0] + c[1] + c[2] + c[3] }
|
||||||
|
|
||||||
cross :: proc(x, y: Vec3) -> Vec3 {
|
cross :: proc(x, y: Vec3) -> Vec3 {
|
||||||
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1);
|
a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1)
|
||||||
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0);
|
b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0)
|
||||||
return a - b;
|
return a - b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v); }
|
vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v) }
|
||||||
vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v); }
|
vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v) }
|
||||||
vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v); }
|
vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v) }
|
||||||
|
|
||||||
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)}; }
|
vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} }
|
||||||
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)}; }
|
vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} }
|
||||||
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)}; }
|
vec4_norm :: proc(v: Vec4) -> Vec4 { return v / Vec4{vec4_mag(v)} }
|
||||||
|
|
||||||
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
vec2_norm0 :: proc(v: Vec2) -> Vec2 {
|
||||||
m := vec2_mag(v);
|
m := vec2_mag(v)
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec2{0};
|
return Vec2{0}
|
||||||
}
|
}
|
||||||
return v / Vec2{m};
|
return v / Vec2{m}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
vec3_norm0 :: proc(v: Vec3) -> Vec3 {
|
||||||
m := vec3_mag(v);
|
m := vec3_mag(v)
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec3{0};
|
return Vec3{0}
|
||||||
}
|
}
|
||||||
return v / Vec3{m};
|
return v / Vec3{m}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
vec4_norm0 :: proc(v: Vec4) -> Vec4 {
|
||||||
m := vec4_mag(v);
|
m := vec4_mag(v)
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return Vec4{0};
|
return Vec4{0}
|
||||||
}
|
}
|
||||||
return v / Vec4{m};
|
return v / Vec4{m}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
F32_DIG :: 6;
|
F32_DIG :: 6
|
||||||
F32_EPSILON :: 1.192092896e-07;
|
F32_EPSILON :: 1.192092896e-07
|
||||||
F32_GUARD :: 0;
|
F32_GUARD :: 0
|
||||||
F32_MANT_DIG :: 24;
|
F32_MANT_DIG :: 24
|
||||||
F32_MAX :: 3.402823466e+38;
|
F32_MAX :: 3.402823466e+38
|
||||||
F32_MAX_10_EXP :: 38;
|
F32_MAX_10_EXP :: 38
|
||||||
F32_MAX_EXP :: 128;
|
F32_MAX_EXP :: 128
|
||||||
F32_MIN :: 1.175494351e-38;
|
F32_MIN :: 1.175494351e-38
|
||||||
F32_MIN_10_EXP :: -37;
|
F32_MIN_10_EXP :: -37
|
||||||
F32_MIN_EXP :: -125;
|
F32_MIN_EXP :: -125
|
||||||
F32_NORMALIZE :: 0;
|
F32_NORMALIZE :: 0
|
||||||
F32_RADIX :: 2;
|
F32_RADIX :: 2
|
||||||
F32_ROUNDS :: 1;
|
F32_ROUNDS :: 1
|
||||||
|
|
||||||
F64_DIG :: 15; // # of decimal digits of precision
|
F64_DIG :: 15 // # of decimal digits of precision
|
||||||
F64_EPSILON :: 2.2204460492503131e-016; // smallest such that 1.0+F64_EPSILON != 1.0
|
F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0
|
||||||
F64_MANT_DIG :: 53; // # of bits in mantissa
|
F64_MANT_DIG :: 53 // # of bits in mantissa
|
||||||
F64_MAX :: 1.7976931348623158e+308; // max value
|
F64_MAX :: 1.7976931348623158e+308 // max value
|
||||||
F64_MAX_10_EXP :: 308; // max decimal exponent
|
F64_MAX_10_EXP :: 308 // max decimal exponent
|
||||||
F64_MAX_EXP :: 1024; // max binary exponent
|
F64_MAX_EXP :: 1024 // max binary exponent
|
||||||
F64_MIN :: 2.2250738585072014e-308; // min positive value
|
F64_MIN :: 2.2250738585072014e-308 // min positive value
|
||||||
F64_MIN_10_EXP :: -307; // min decimal exponent
|
F64_MIN_10_EXP :: -307 // min decimal exponent
|
||||||
F64_MIN_EXP :: -1021; // min binary exponent
|
F64_MIN_EXP :: -1021 // min binary exponent
|
||||||
F64_RADIX :: 2; // exponent radix
|
F64_RADIX :: 2 // exponent radix
|
||||||
F64_ROUNDS :: 1; // addition rounding: near
|
F64_ROUNDS :: 1 // addition rounding: near
|
||||||
|
|||||||
+24
-22
@@ -1,29 +1,31 @@
|
|||||||
GL_ZERO :: 0x0000;
|
#foreign_system_library "opengl32"
|
||||||
GL_ONE :: 0x0001;
|
|
||||||
GL_TRIANGLES :: 0x0004;
|
|
||||||
GL_BLEND :: 0x0BE2;
|
|
||||||
GL_SRC_ALPHA :: 0x0302;
|
|
||||||
GL_ONE_MINUS_SRC_ALPHA :: 0x0303;
|
|
||||||
GL_TEXTURE_2D :: 0x0DE1;
|
|
||||||
GL_RGBA8 :: 0x8058;
|
|
||||||
GL_UNSIGNED_BYTE :: 0x1401;
|
|
||||||
GL_BGRA_EXT :: 0x80E1;
|
|
||||||
GL_TEXTURE_MAX_LEVEL :: 0x813D;
|
|
||||||
GL_RGBA :: 0x1908;
|
|
||||||
|
|
||||||
GL_NEAREST :: 0x2600;
|
GL_ZERO :: 0x0000
|
||||||
GL_LINEAR :: 0x2601;
|
GL_ONE :: 0x0001
|
||||||
|
GL_TRIANGLES :: 0x0004
|
||||||
|
GL_BLEND :: 0x0be2
|
||||||
|
GL_SRC_ALPHA :: 0x0302
|
||||||
|
GL_ONE_MINUS_SRC_ALPHA :: 0x0303
|
||||||
|
GL_TEXTURE_2D :: 0x0de1
|
||||||
|
GL_RGBA8 :: 0x8058
|
||||||
|
GL_UNSIGNED_BYTE :: 0x1401
|
||||||
|
GL_BGRA_EXT :: 0x80e1
|
||||||
|
GL_TEXTURE_MAX_LEVEL :: 0x813d
|
||||||
|
GL_RGBA :: 0x1908
|
||||||
|
|
||||||
GL_DEPTH_BUFFER_BIT :: 0x00000100;
|
GL_NEAREST :: 0x2600
|
||||||
GL_STENCIL_BUFFER_BIT :: 0x00000400;
|
GL_LINEAR :: 0x2601
|
||||||
GL_COLOR_BUFFER_BIT :: 0x00004000;
|
|
||||||
|
|
||||||
GL_TEXTURE_MAX_ANISOTROPY_EXT :: 0x84FE;
|
GL_DEPTH_BUFFER_BIT :: 0x00000100
|
||||||
|
GL_STENCIL_BUFFER_BIT :: 0x00000400
|
||||||
|
GL_COLOR_BUFFER_BIT :: 0x00004000
|
||||||
|
|
||||||
GL_TEXTURE_MAG_FILTER :: 0x2800;
|
GL_TEXTURE_MAX_ANISOTROPY_EXT :: 0x84fe
|
||||||
GL_TEXTURE_MIN_FILTER :: 0x2801;
|
|
||||||
GL_TEXTURE_WRAP_S :: 0x2802;
|
GL_TEXTURE_MAG_FILTER :: 0x2800
|
||||||
GL_TEXTURE_WRAP_T :: 0x2803;
|
GL_TEXTURE_MIN_FILTER :: 0x2801
|
||||||
|
GL_TEXTURE_WRAP_S :: 0x2802
|
||||||
|
GL_TEXTURE_WRAP_T :: 0x2803
|
||||||
|
|
||||||
glClear :: proc(mask: u32) #foreign
|
glClear :: proc(mask: u32) #foreign
|
||||||
glClearColor :: proc(r, g, b, a: f32) #foreign
|
glClearColor :: proc(r, g, b, a: f32) #foreign
|
||||||
|
|||||||
+166
-170
@@ -4,167 +4,167 @@ debug_trap :: proc() #foreign "llvm.debugtrap"
|
|||||||
|
|
||||||
// TODO(bill): make custom heap procedures
|
// TODO(bill): make custom heap procedures
|
||||||
heap_alloc :: proc(len: int) -> rawptr {
|
heap_alloc :: proc(len: int) -> rawptr {
|
||||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
|
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
|
||||||
}
|
}
|
||||||
heap_free :: proc(ptr: rawptr) {
|
heap_free :: proc(ptr: rawptr) {
|
||||||
_ = HeapFree(GetProcessHeap(), 0, ptr);
|
_ = HeapFree(GetProcessHeap(), 0, ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
|
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
|
||||||
s1, s2: ^u8 = dst, src;
|
s1, s2: ^u8 = dst, src
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
a := ptr_offset(s1, i)^;
|
a := ptr_offset(s1, i)^
|
||||||
b := ptr_offset(s2, i)^;
|
b := ptr_offset(s2, i)^
|
||||||
if a != b {
|
if a != b {
|
||||||
return (a - b) as int;
|
return (a - b) as int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_copy :: proc(dst, src: rawptr, n: int) #inline {
|
memory_copy :: proc(dst, src: rawptr, n: int) #inline {
|
||||||
if dst == src {
|
if dst == src {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
v128b :: type {4}u32;
|
v128b :: type {4}u32
|
||||||
static_assert(align_of(v128b) == 16);
|
static_assert(align_of(v128b) == 16)
|
||||||
|
|
||||||
d, s: ^u8 = dst, src;
|
d, s: ^u8 = dst, src
|
||||||
|
|
||||||
for ; s as uint % 16 != 0 && n != 0; n-- {
|
for ; s as uint % 16 != 0 && n != 0; n-- {
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
d, s = ptr_offset(d, 1), ptr_offset(s, 1);
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if d as uint % 16 == 0 {
|
if d as uint % 16 == 0 {
|
||||||
for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 {
|
for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 {
|
||||||
(d as ^v128b)^ = (s as ^v128b)^;
|
(d as ^v128b)^ = (s as ^v128b)^
|
||||||
}
|
}
|
||||||
|
|
||||||
if n&8 != 0 {
|
if n&8 != 0 {
|
||||||
(d as ^u64)^ = (s as ^u64)^;
|
(d as ^u64)^ = (s as ^u64)^
|
||||||
d, s = ptr_offset(d, 8), ptr_offset(s, 8);
|
d, s = ptr_offset(d, 8), ptr_offset(s, 8)
|
||||||
}
|
}
|
||||||
if n&4 != 0 {
|
if n&4 != 0 {
|
||||||
(d as ^u32)^ = (s as ^u32)^;
|
(d as ^u32)^ = (s as ^u32)^;
|
||||||
d, s = ptr_offset(d, 4), ptr_offset(s, 4);
|
d, s = ptr_offset(d, 4), ptr_offset(s, 4)
|
||||||
}
|
}
|
||||||
if n&2 != 0 {
|
if n&2 != 0 {
|
||||||
(d as ^u16)^ = (s as ^u16)^;
|
(d as ^u16)^ = (s as ^u16)^
|
||||||
d, s = ptr_offset(d, 2), ptr_offset(s, 2);
|
d, s = ptr_offset(d, 2), ptr_offset(s, 2)
|
||||||
}
|
}
|
||||||
if n&1 != 0 {
|
if n&1 != 0 {
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
d, s = ptr_offset(d, 1), ptr_offset(s, 1);
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill): Little endian only
|
// IMPORTANT NOTE(bill): Little endian only
|
||||||
LS :: proc(a, b: u32) -> u32 #inline { return a << b; }
|
LS :: proc(a, b: u32) -> u32 #inline { return a << b }
|
||||||
RS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
|
RS :: proc(a, b: u32) -> u32 #inline { return a >> b }
|
||||||
/* NOTE(bill): Big endian version
|
/* NOTE(bill): Big endian version
|
||||||
LS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
|
LS :: proc(a, b: u32) -> u32 #inline { return a >> b; }
|
||||||
RS :: proc(a, b: u32) -> u32 #inline { return a << b; }
|
RS :: proc(a, b: u32) -> u32 #inline { return a << b; }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
w, x: u32;
|
w, x: u32
|
||||||
|
|
||||||
if d as uint % 4 == 1 {
|
if d as uint % 4 == 1 {
|
||||||
w = (s as ^u32)^;
|
w = (s as ^u32)^
|
||||||
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
n -= 3;
|
n -= 3
|
||||||
|
|
||||||
for n > 16 {
|
for n > 16 {
|
||||||
d32 := d as ^u32;
|
d32 := d as ^u32
|
||||||
s32 := ptr_offset(s, 1) as ^u32;
|
s32 := ptr_offset(s, 1) as ^u32
|
||||||
x = s32^; d32^ = LS(w, 24) | RS(x, 8);
|
x = s32^; d32^ = LS(w, 24) | RS(x, 8)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
w = s32^; d32^ = LS(x, 24) | RS(w, 8);
|
w = s32^; d32^ = LS(x, 24) | RS(w, 8)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
x = s32^; d32^ = LS(w, 24) | RS(x, 8);
|
x = s32^; d32^ = LS(w, 24) | RS(x, 8)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
w = s32^; d32^ = LS(x, 24) | RS(w, 8);
|
w = s32^; d32^ = LS(x, 24) | RS(w, 8)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
|
||||||
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16;
|
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if d as uint % 4 == 2 {
|
} else if d as uint % 4 == 2 {
|
||||||
w = (s as ^u32)^;
|
w = (s as ^u32)^
|
||||||
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1);
|
d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1)
|
||||||
n -= 2;
|
n -= 2
|
||||||
|
|
||||||
for n > 17 {
|
for n > 17 {
|
||||||
d32 := d as ^u32;
|
d32 := d as ^u32
|
||||||
s32 := ptr_offset(s, 2) as ^u32;
|
s32 := ptr_offset(s, 2) as ^u32
|
||||||
x = s32^; d32^ = LS(w, 16) | RS(x, 16);
|
x = s32^; d32^ = LS(w, 16) | RS(x, 16)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
w = s32^; d32^ = LS(x, 16) | RS(w, 16);
|
w = s32^; d32^ = LS(x, 16) | RS(w, 16)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
x = s32^; d32^ = LS(w, 16) | RS(x, 16);
|
x = s32^; d32^ = LS(w, 16) | RS(x, 16)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
w = s32^; d32^ = LS(x, 16) | RS(w, 16);
|
w = s32^; d32^ = LS(x, 16) | RS(w, 16)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
|
||||||
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16;
|
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if d as uint % 4 == 3 {
|
} else if d as uint % 4 == 3 {
|
||||||
w = (s as ^u32)^;
|
w = (s as ^u32)^
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
n -= 1;
|
n -= 1
|
||||||
|
|
||||||
for n > 18 {
|
for n > 18 {
|
||||||
d32 := d as ^u32;
|
d32 := d as ^u32
|
||||||
s32 := ptr_offset(s, 3) as ^u32;
|
s32 := ptr_offset(s, 3) as ^u32
|
||||||
x = s32^; d32^ = LS(w, 8) | RS(x, 24);
|
x = s32^; d32^ = LS(w, 8) | RS(x, 24)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
w = s32^; d32^ = LS(x, 8) | RS(w, 24);
|
w = s32^; d32^ = LS(x, 8) | RS(w, 24)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
x = s32^; d32^ = LS(w, 8) | RS(x, 24);
|
x = s32^; d32^ = LS(w, 8) | RS(x, 24)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
w = s32^; d32^ = LS(x, 8) | RS(w, 24);
|
w = s32^; d32^ = LS(x, 8) | RS(w, 24)
|
||||||
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1);
|
d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1)
|
||||||
|
|
||||||
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16;
|
d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n&16 != 0 {
|
if n&16 != 0 {
|
||||||
(d as ^v128b)^ = (s as ^v128b)^;
|
(d as ^v128b)^ = (s as ^v128b)^
|
||||||
d, s = ptr_offset(d, 16), ptr_offset(s, 16);
|
d, s = ptr_offset(d, 16), ptr_offset(s, 16)
|
||||||
}
|
}
|
||||||
if n&8 != 0 {
|
if n&8 != 0 {
|
||||||
(d as ^u64)^ = (s as ^u64)^;
|
(d as ^u64)^ = (s as ^u64)^
|
||||||
d, s = ptr_offset(d, 8), ptr_offset(s, 8);
|
d, s = ptr_offset(d, 8), ptr_offset(s, 8)
|
||||||
}
|
}
|
||||||
if n&4 != 0 {
|
if n&4 != 0 {
|
||||||
(d as ^u32)^ = (s as ^u32)^;
|
(d as ^u32)^ = (s as ^u32)^;
|
||||||
d, s = ptr_offset(d, 4), ptr_offset(s, 4);
|
d, s = ptr_offset(d, 4), ptr_offset(s, 4)
|
||||||
}
|
}
|
||||||
if n&2 != 0 {
|
if n&2 != 0 {
|
||||||
(d as ^u16)^ = (s as ^u16)^;
|
(d as ^u16)^ = (s as ^u16)^
|
||||||
d, s = ptr_offset(d, 2), ptr_offset(s, 2);
|
d, s = ptr_offset(d, 2), ptr_offset(s, 2)
|
||||||
}
|
}
|
||||||
if n&1 != 0 {
|
if n&1 != 0 {
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_move :: proc(dst, src: rawptr, n: int) #inline {
|
memory_move :: proc(dst, src: rawptr, n: int) #inline {
|
||||||
d, s: ^u8 = dst, src;
|
d, s: ^u8 = dst, src
|
||||||
if d == s {
|
if d == s {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
|
if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s {
|
||||||
memory_copy(d, s, n);
|
memory_copy(d, s, n)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bill): Vectorize the shit out of this
|
// TODO(bill): Vectorize the shit out of this
|
||||||
@@ -172,94 +172,94 @@ memory_move :: proc(dst, src: rawptr, n: int) #inline {
|
|||||||
if s as int % size_of(int) == d as int % size_of(int) {
|
if s as int % size_of(int) == d as int % size_of(int) {
|
||||||
for d as int % size_of(int) != 0 {
|
for d as int % size_of(int) != 0 {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
n--;
|
n--
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
d, s = ptr_offset(d, 1), ptr_offset(s, 1);
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
}
|
}
|
||||||
di, si := d as ^int, s as ^int;
|
di, si := d as ^int, s as ^int
|
||||||
for n >= size_of(int) {
|
for n >= size_of(int) {
|
||||||
di^ = si^;
|
di^ = si^
|
||||||
di, si = ptr_offset(di, 1), ptr_offset(si, 1);
|
di, si = ptr_offset(di, 1), ptr_offset(si, 1)
|
||||||
n -= size_of(int);
|
n -= size_of(int)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ; n > 0; n-- {
|
for ; n > 0; n-- {
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
d, s = ptr_offset(d, 1), ptr_offset(s, 1);
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if s as int % size_of(int) == d as int % size_of(int) {
|
if s as int % size_of(int) == d as int % size_of(int) {
|
||||||
for ptr_offset(d, n) as int % size_of(int) != 0 {
|
for ptr_offset(d, n) as int % size_of(int) != 0 {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
n--;
|
n--
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
d, s = ptr_offset(d, 1), ptr_offset(s, 1);
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
}
|
}
|
||||||
for n >= size_of(int) {
|
for n >= size_of(int) {
|
||||||
n -= size_of(int);
|
n -= size_of(int)
|
||||||
di := ptr_offset(d, n) as ^int;
|
di := ptr_offset(d, n) as ^int
|
||||||
si := ptr_offset(s, n) as ^int;
|
si := ptr_offset(s, n) as ^int
|
||||||
di^ = si^;
|
di^ = si^
|
||||||
}
|
}
|
||||||
for ; n > 0; n-- {
|
for ; n > 0; n-- {
|
||||||
d^ = s^;
|
d^ = s^
|
||||||
d, s = ptr_offset(d, 1), ptr_offset(s, 1);
|
d, s = ptr_offset(d, 1), ptr_offset(s, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for n > 0 {
|
for n > 0 {
|
||||||
n--;
|
n--
|
||||||
dn := ptr_offset(d, n);
|
dn := ptr_offset(d, n)
|
||||||
sn := ptr_offset(s, n);
|
sn := ptr_offset(s, n)
|
||||||
dn^ = sn^;
|
dn^ = sn^
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_eq :: proc(a, b : string) -> bool {
|
__string_eq :: proc(a, b: string) -> bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
if ^a[0] == ^b[0] {
|
if ^a[0] == ^b[0] {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
return memory_compare(^a[0], ^b[0], len(a)) == 0;
|
return memory_compare(^a[0], ^b[0], len(a)) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_ne :: proc(a, b : string) -> bool #inline {
|
__string_ne :: proc(a, b : string) -> bool #inline {
|
||||||
return !__string_eq(a, b);
|
return !__string_eq(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_cmp :: proc(a, b : string) -> int {
|
__string_cmp :: proc(a, b : string) -> int {
|
||||||
min_len := len(a);
|
min_len := len(a)
|
||||||
if len(b) < min_len {
|
if len(b) < min_len {
|
||||||
min_len = len(b);
|
min_len = len(b)
|
||||||
}
|
}
|
||||||
for i := 0; i < min_len; i++ {
|
for i := 0; i < min_len; i++ {
|
||||||
x := a[i];
|
x := a[i]
|
||||||
y := b[i];
|
y := b[i]
|
||||||
if x < y {
|
if x < y {
|
||||||
return -1;
|
return -1
|
||||||
} else if x > y {
|
} else if x > y {
|
||||||
return +1;
|
return +1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a) < len(b) {
|
if len(a) < len(b) {
|
||||||
return -1;
|
return -1
|
||||||
} else if len(a) > len(b) {
|
} else if len(a) > len(b) {
|
||||||
return +1;
|
return +1
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0; }
|
__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
||||||
__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0; }
|
__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
||||||
__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0; }
|
__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
|
||||||
__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0; }
|
__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -275,117 +275,113 @@ AllocationMode :: type enum {
|
|||||||
|
|
||||||
AllocatorProc :: type proc(allocator_data: rawptr, mode: AllocationMode,
|
AllocatorProc :: type proc(allocator_data: rawptr, mode: AllocationMode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
||||||
|
|
||||||
Allocator :: type struct {
|
Allocator :: type struct {
|
||||||
procedure: AllocatorProc;
|
procedure: AllocatorProc;
|
||||||
data: rawptr;
|
data: rawptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Context :: type struct {
|
Context :: type struct {
|
||||||
thread_id: i32;
|
thread_id: i32
|
||||||
|
|
||||||
user_index: i32;
|
user_index: i32
|
||||||
user_data: rawptr;
|
user_data: rawptr
|
||||||
|
|
||||||
allocator: Allocator;
|
allocator: Allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
#thread_local context: Context;
|
#thread_local context: Context
|
||||||
|
|
||||||
DEFAULT_ALIGNMENT :: 2*size_of(int);
|
DEFAULT_ALIGNMENT :: 2*size_of(int)
|
||||||
|
|
||||||
|
|
||||||
__check_context :: proc() {
|
__check_context :: proc() {
|
||||||
static_assert(AllocationMode.ALLOC == 0);
|
|
||||||
static_assert(AllocationMode.DEALLOC == 1);
|
|
||||||
static_assert(AllocationMode.DEALLOC_ALL == 2);
|
|
||||||
static_assert(AllocationMode.RESIZE == 3);
|
|
||||||
|
|
||||||
if context.allocator.procedure == null {
|
if context.allocator.procedure == null {
|
||||||
context.allocator = __default_allocator();
|
context.allocator = __default_allocator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
|
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
|
||||||
|
|
||||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||||
__check_context();
|
__check_context()
|
||||||
a := context.allocator;
|
a := context.allocator
|
||||||
return a.procedure(a.data, AllocationMode.ALLOC, size, alignment, null, 0, 0);
|
return a.procedure(a.data, AllocationMode.ALLOC, size, alignment, null, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
dealloc :: proc(ptr: rawptr) #inline {
|
dealloc :: proc(ptr: rawptr) #inline {
|
||||||
__check_context();
|
__check_context()
|
||||||
a := context.allocator;
|
a := context.allocator
|
||||||
_ = a.procedure(a.data, AllocationMode.DEALLOC, 0, 0, ptr, 0, 0);
|
_ = a.procedure(a.data, AllocationMode.DEALLOC, 0, 0, ptr, 0, 0)
|
||||||
}
|
}
|
||||||
dealloc_all :: proc(ptr: rawptr) #inline {
|
dealloc_all :: proc(ptr: rawptr) #inline {
|
||||||
__check_context();
|
__check_context()
|
||||||
a := context.allocator;
|
a := context.allocator
|
||||||
_ = a.procedure(a.data, AllocationMode.DEALLOC_ALL, 0, 0, ptr, 0, 0);
|
_ = a.procedure(a.data, AllocationMode.DEALLOC_ALL, 0, 0, ptr, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
|
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
|
||||||
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
||||||
__check_context();
|
__check_context()
|
||||||
a := context.allocator;
|
a := context.allocator
|
||||||
return a.procedure(a.data, AllocationMode.RESIZE, new_size, alignment, ptr, old_size, 0);
|
return a.procedure(a.data, AllocationMode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
||||||
if old_memory == null {
|
if old_memory == null {
|
||||||
return alloc_align(new_size, alignment);
|
return alloc_align(new_size, alignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size == 0 {
|
if new_size == 0 {
|
||||||
dealloc(old_memory);
|
dealloc(old_memory)
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_size < old_size {
|
if new_size < old_size {
|
||||||
new_size = old_size;
|
new_size = old_size
|
||||||
}
|
}
|
||||||
|
|
||||||
if old_size == new_size {
|
if old_size == new_size {
|
||||||
return old_memory;
|
return old_memory
|
||||||
}
|
}
|
||||||
|
|
||||||
new_memory := alloc_align(new_size, alignment);
|
new_memory := alloc_align(new_size, alignment)
|
||||||
if new_memory == null {
|
if new_memory == null {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
_ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size));
|
_ = copy(slice_ptr(new_memory as ^u8, new_size), slice_ptr(old_memory as ^u8, old_size))
|
||||||
dealloc(old_memory);
|
dealloc(old_memory)
|
||||||
return new_memory;
|
return new_memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__default_allocator_proc :: proc(allocator_data: rawptr, mode: AllocationMode,
|
__default_allocator_proc :: proc(allocator_data: rawptr, mode: AllocationMode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
if mode == AllocationMode.ALLOC {
|
using AllocationMode
|
||||||
return heap_alloc(size);
|
if mode == ALLOC {
|
||||||
} else if mode == AllocationMode.RESIZE {
|
return heap_alloc(size)
|
||||||
return default_resize_align(old_memory, old_size, size, alignment);
|
} else if mode == RESIZE {
|
||||||
} else if mode == AllocationMode.DEALLOC {
|
return default_resize_align(old_memory, old_size, size, alignment)
|
||||||
heap_free(old_memory);
|
} else if mode == DEALLOC {
|
||||||
} else if mode == AllocationMode.DEALLOC_ALL {
|
heap_free(old_memory)
|
||||||
|
} else if mode == DEALLOC_ALL {
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
__default_allocator :: proc() -> Allocator {
|
__default_allocator :: proc() -> Allocator {
|
||||||
return Allocator{
|
return Allocator{
|
||||||
__default_allocator_proc,
|
__default_allocator_proc,
|
||||||
null,
|
null,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -7,24 +7,24 @@ type Bitmap: struct {
|
|||||||
make_bitmap :: proc(filename: string) -> Bitmap {
|
make_bitmap :: proc(filename: string) -> Bitmap {
|
||||||
stbi_load :: proc(filename: ^u8, x, y, comp: ^i32, req_comp: i32) -> ^u8 #foreign
|
stbi_load :: proc(filename: ^u8, x, y, comp: ^i32, req_comp: i32) -> ^u8 #foreign
|
||||||
|
|
||||||
c_buf: [1024]u8;
|
c_buf: [1024]u8
|
||||||
bytes := filename as []byte;
|
bytes := filename as []byte
|
||||||
str_len := copy(c_buf[:], bytes);
|
str_len := copy(c_buf[:], bytes)
|
||||||
|
|
||||||
b: Bitmap;
|
b: Bitmap
|
||||||
pixels := stbi_load(^c_buf[0], ^b.width, ^b.height, ^b.comp, 4);
|
pixels := stbi_load(^c_buf[0], ^b.width, ^b.height, ^b.comp, 4)
|
||||||
len := (b.width*b.height*b.comp) as int;
|
len := (b.width*b.height*b.comp) as int
|
||||||
b.data = pixels[:len];
|
b.data = slice_ptr(pixels, len)
|
||||||
|
|
||||||
return b;
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_bitmap :: proc(b: ^Bitmap) {
|
destroy_bitmap :: proc(b: ^Bitmap) {
|
||||||
stbi_image_free :: proc(retval_from_stbi_load: rawptr) #foreign
|
stbi_image_free :: proc(retval_from_stbi_load: rawptr) #foreign
|
||||||
|
|
||||||
stbi_image_free(^b.data[0]);
|
stbi_image_free(^b.data[0])
|
||||||
b.data = b.data[:0];
|
b.data = b.data[:0]
|
||||||
b.width = 0;
|
b.width = 0
|
||||||
b.height = 0;
|
b.height = 0
|
||||||
b.comp = 0;
|
b.comp = 0
|
||||||
}
|
}
|
||||||
|
|||||||
+239
-236
@@ -1,63 +1,66 @@
|
|||||||
CS_VREDRAW :: 1;
|
#foreign_system_library "user32"
|
||||||
CS_HREDRAW :: 2;
|
#foreign_system_library "gdi32"
|
||||||
CW_USEDEFAULT :: 0x80000000;
|
|
||||||
|
|
||||||
WS_OVERLAPPED :: 0;
|
CS_VREDRAW :: 1
|
||||||
WS_MAXIMIZEBOX :: 0x00010000;
|
CS_HREDRAW :: 2
|
||||||
WS_MINIMIZEBOX :: 0x00020000;
|
CW_USEDEFAULT :: 0x80000000
|
||||||
WS_THICKFRAME :: 0x00040000;
|
|
||||||
WS_SYSMENU :: 0x00080000;
|
|
||||||
WS_CAPTION :: 0x00C00000;
|
|
||||||
WS_VISIBLE :: 0x10000000;
|
|
||||||
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
|
|
||||||
|
|
||||||
WM_DESTROY :: 0x02;
|
WS_OVERLAPPED :: 0
|
||||||
WM_CLOSE :: 0x10;
|
WS_MAXIMIZEBOX :: 0x00010000
|
||||||
WM_QUIT :: 0x12;
|
WS_MINIMIZEBOX :: 0x00020000
|
||||||
|
WS_THICKFRAME :: 0x00040000
|
||||||
|
WS_SYSMENU :: 0x00080000
|
||||||
|
WS_CAPTION :: 0x00C00000
|
||||||
|
WS_VISIBLE :: 0x10000000
|
||||||
|
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
|
||||||
|
|
||||||
PM_REMOVE :: 1;
|
WM_DESTROY :: 0x02
|
||||||
|
WM_CLOSE :: 0x10
|
||||||
|
WM_QUIT :: 0x12
|
||||||
|
|
||||||
COLOR_BACKGROUND :: 1 as HBRUSH;
|
PM_REMOVE :: 1
|
||||||
|
|
||||||
|
COLOR_BACKGROUND :: 1 as HBRUSH
|
||||||
|
|
||||||
|
|
||||||
HANDLE :: type rawptr;
|
HANDLE :: type rawptr
|
||||||
HWND :: type HANDLE;
|
HWND :: type HANDLE
|
||||||
HDC :: type HANDLE;
|
HDC :: type HANDLE
|
||||||
HINSTANCE :: type HANDLE;
|
HINSTANCE :: type HANDLE
|
||||||
HICON :: type HANDLE;
|
HICON :: type HANDLE
|
||||||
HCURSOR :: type HANDLE;
|
HCURSOR :: type HANDLE
|
||||||
HMENU :: type HANDLE;
|
HMENU :: type HANDLE
|
||||||
HBRUSH :: type HANDLE;
|
HBRUSH :: type HANDLE
|
||||||
WPARAM :: type uint;
|
WPARAM :: type uint
|
||||||
LPARAM :: type int;
|
LPARAM :: type int
|
||||||
LRESULT :: type int;
|
LRESULT :: type int
|
||||||
ATOM :: type i16;
|
ATOM :: type i16
|
||||||
BOOL :: type i32;
|
BOOL :: type i32
|
||||||
POINT :: type struct { x, y: i32; };
|
POINT :: type struct { x, y: i32 }
|
||||||
|
|
||||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
|
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
|
||||||
|
|
||||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
||||||
|
|
||||||
WNDCLASSEXA :: type struct {
|
WNDCLASSEXA :: type struct {
|
||||||
size, style: u32;
|
size, style: u32
|
||||||
wnd_proc: WNDPROC;
|
wnd_proc: WNDPROC
|
||||||
cls_extra, wnd_extra: i32;
|
cls_extra, wnd_extra: i32
|
||||||
instance: HINSTANCE;
|
instance: HINSTANCE
|
||||||
icon: HICON;
|
icon: HICON
|
||||||
cursor: HCURSOR;
|
cursor: HCURSOR
|
||||||
background: HBRUSH;
|
background: HBRUSH
|
||||||
menu_name, class_name: ^u8;
|
menu_name, class_name: ^u8
|
||||||
sm: HICON;
|
sm: HICON
|
||||||
}
|
}
|
||||||
|
|
||||||
MSG :: type struct {
|
MSG :: type struct {
|
||||||
hwnd: HWND;
|
hwnd: HWND
|
||||||
message: u32;
|
message: u32
|
||||||
wparam: WPARAM;
|
wparam: WPARAM
|
||||||
lparam: LPARAM;
|
lparam: LPARAM
|
||||||
time: u32;
|
time: u32
|
||||||
pt: POINT;
|
pt: POINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +78,7 @@ QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign
|
|||||||
|
|
||||||
sleep_ms :: proc(ms: i32) {
|
sleep_ms :: proc(ms: i32) {
|
||||||
Sleep :: proc(ms: i32) -> i32 #foreign
|
Sleep :: proc(ms: i32) -> i32 #foreign
|
||||||
Sleep(ms);
|
Sleep(ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign
|
OutputDebugStringA :: proc(c_str: ^u8) #foreign
|
||||||
@@ -102,9 +105,9 @@ DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -
|
|||||||
|
|
||||||
|
|
||||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||||
r: i64;
|
r: i64
|
||||||
_ = QueryPerformanceFrequency(^r);
|
_ = QueryPerformanceFrequency(^r)
|
||||||
return r;
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,30 +124,30 @@ WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, ove
|
|||||||
|
|
||||||
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign
|
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign
|
||||||
|
|
||||||
FILE_SHARE_READ :: 0x00000001;
|
FILE_SHARE_READ :: 0x00000001
|
||||||
FILE_SHARE_WRITE :: 0x00000002;
|
FILE_SHARE_WRITE :: 0x00000002
|
||||||
FILE_SHARE_DELETE :: 0x00000004;
|
FILE_SHARE_DELETE :: 0x00000004
|
||||||
FILE_GENERIC_ALL :: 0x10000000;
|
FILE_GENERIC_ALL :: 0x10000000
|
||||||
FILE_GENERIC_EXECUTE :: 0x20000000;
|
FILE_GENERIC_EXECUTE :: 0x20000000
|
||||||
FILE_GENERIC_WRITE :: 0x40000000;
|
FILE_GENERIC_WRITE :: 0x40000000
|
||||||
FILE_GENERIC_READ :: 0x80000000;
|
FILE_GENERIC_READ :: 0x80000000
|
||||||
|
|
||||||
STD_INPUT_HANDLE :: -10;
|
STD_INPUT_HANDLE :: -10
|
||||||
STD_OUTPUT_HANDLE :: -11;
|
STD_OUTPUT_HANDLE :: -11
|
||||||
STD_ERROR_HANDLE :: -12;
|
STD_ERROR_HANDLE :: -12
|
||||||
|
|
||||||
CREATE_NEW :: 1;
|
CREATE_NEW :: 1
|
||||||
CREATE_ALWAYS :: 2;
|
CREATE_ALWAYS :: 2
|
||||||
OPEN_EXISTING :: 3;
|
OPEN_EXISTING :: 3
|
||||||
OPEN_ALWAYS :: 4;
|
OPEN_ALWAYS :: 4
|
||||||
TRUNCATE_EXISTING :: 5;
|
TRUNCATE_EXISTING :: 5
|
||||||
|
|
||||||
|
|
||||||
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign
|
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign
|
||||||
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign
|
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign
|
||||||
GetProcessHeap :: proc() -> HANDLE #foreign
|
GetProcessHeap :: proc() -> HANDLE #foreign
|
||||||
|
|
||||||
HEAP_ZERO_MEMORY :: 0x00000008;
|
HEAP_ZERO_MEMORY :: 0x00000008
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -159,37 +162,37 @@ HEAP_ZERO_MEMORY :: 0x00000008;
|
|||||||
|
|
||||||
// Windows OpenGL
|
// Windows OpenGL
|
||||||
|
|
||||||
PFD_TYPE_RGBA :: 0;
|
PFD_TYPE_RGBA :: 0
|
||||||
PFD_TYPE_COLORINDEX :: 1;
|
PFD_TYPE_COLORINDEX :: 1
|
||||||
PFD_MAIN_PLANE :: 0;
|
PFD_MAIN_PLANE :: 0
|
||||||
PFD_OVERLAY_PLANE :: 1;
|
PFD_OVERLAY_PLANE :: 1
|
||||||
PFD_UNDERLAY_PLANE :: -1;
|
PFD_UNDERLAY_PLANE :: -1
|
||||||
PFD_DOUBLEBUFFER :: 1;
|
PFD_DOUBLEBUFFER :: 1
|
||||||
PFD_STEREO :: 2;
|
PFD_STEREO :: 2
|
||||||
PFD_DRAW_TO_WINDOW :: 4;
|
PFD_DRAW_TO_WINDOW :: 4
|
||||||
PFD_DRAW_TO_BITMAP :: 8;
|
PFD_DRAW_TO_BITMAP :: 8
|
||||||
PFD_SUPPORT_GDI :: 16;
|
PFD_SUPPORT_GDI :: 16
|
||||||
PFD_SUPPORT_OPENGL :: 32;
|
PFD_SUPPORT_OPENGL :: 32
|
||||||
PFD_GENERIC_FORMAT :: 64;
|
PFD_GENERIC_FORMAT :: 64
|
||||||
PFD_NEED_PALETTE :: 128;
|
PFD_NEED_PALETTE :: 128
|
||||||
PFD_NEED_SYSTEM_PALETTE :: 0x00000100;
|
PFD_NEED_SYSTEM_PALETTE :: 0x00000100
|
||||||
PFD_SWAP_EXCHANGE :: 0x00000200;
|
PFD_SWAP_EXCHANGE :: 0x00000200
|
||||||
PFD_SWAP_COPY :: 0x00000400;
|
PFD_SWAP_COPY :: 0x00000400
|
||||||
PFD_SWAP_LAYER_BUFFERS :: 0x00000800;
|
PFD_SWAP_LAYER_BUFFERS :: 0x00000800
|
||||||
PFD_GENERIC_ACCELERATED :: 0x00001000;
|
PFD_GENERIC_ACCELERATED :: 0x00001000
|
||||||
PFD_DEPTH_DONTCARE :: 0x20000000;
|
PFD_DEPTH_DONTCARE :: 0x20000000
|
||||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000;
|
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
|
||||||
PFD_STEREO_DONTCARE :: 0x80000000;
|
PFD_STEREO_DONTCARE :: 0x80000000
|
||||||
|
|
||||||
HGLRC :: type HANDLE;
|
HGLRC :: type HANDLE
|
||||||
PROC :: type proc();
|
PROC :: type proc()
|
||||||
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
|
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
|
||||||
|
|
||||||
|
|
||||||
PIXELFORMATDESCRIPTOR :: type struct {
|
PIXELFORMATDESCRIPTOR :: type struct {
|
||||||
size,
|
size,
|
||||||
version,
|
version,
|
||||||
flags: u32;
|
flags: u32
|
||||||
|
|
||||||
pixel_type,
|
pixel_type,
|
||||||
color_bits,
|
color_bits,
|
||||||
@@ -210,11 +213,11 @@ PIXELFORMATDESCRIPTOR :: type struct {
|
|||||||
stencil_bits,
|
stencil_bits,
|
||||||
aux_buffers,
|
aux_buffers,
|
||||||
layer_type,
|
layer_type,
|
||||||
reserved: byte;
|
reserved: byte
|
||||||
|
|
||||||
layer_mask,
|
layer_mask,
|
||||||
visible_mask,
|
visible_mask,
|
||||||
damage_mask: u32;
|
damage_mask: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
||||||
@@ -223,10 +226,10 @@ ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign
|
|||||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign
|
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign
|
||||||
|
|
||||||
|
|
||||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
||||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
||||||
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
||||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
|
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
|
||||||
|
|
||||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign
|
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign
|
||||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign
|
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign
|
||||||
@@ -238,159 +241,159 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign
|
|||||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
|
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
|
||||||
|
|
||||||
is_key_down :: proc(key: int) -> bool {
|
is_key_down :: proc(key: int) -> bool {
|
||||||
return GetAsyncKeyState(key as i32) < 0;
|
return GetAsyncKeyState(key as i32) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VK_LBUTTON :: 0x01;
|
VK_LBUTTON :: 0x01
|
||||||
VK_RBUTTON :: 0x02;
|
VK_RBUTTON :: 0x02
|
||||||
VK_CANCEL :: 0x03;
|
VK_CANCEL :: 0x03
|
||||||
VK_MBUTTON :: 0x04;
|
VK_MBUTTON :: 0x04
|
||||||
|
|
||||||
VK_BACK :: 0x08;
|
VK_BACK :: 0x08
|
||||||
VK_TAB :: 0x09;
|
VK_TAB :: 0x09
|
||||||
|
|
||||||
VK_CLEAR :: 0x0C;
|
VK_CLEAR :: 0x0C
|
||||||
VK_RETURN :: 0x0D;
|
VK_RETURN :: 0x0D
|
||||||
|
|
||||||
VK_SHIFT :: 0x10;
|
VK_SHIFT :: 0x10
|
||||||
VK_CONTROL :: 0x11;
|
VK_CONTROL :: 0x11
|
||||||
VK_MENU :: 0x12;
|
VK_MENU :: 0x12
|
||||||
VK_PAUSE :: 0x13;
|
VK_PAUSE :: 0x13
|
||||||
VK_CAPITAL :: 0x14;
|
VK_CAPITAL :: 0x14
|
||||||
|
|
||||||
VK_KANA :: 0x15;
|
VK_KANA :: 0x15
|
||||||
VK_HANGEUL :: 0x15;
|
VK_HANGEUL :: 0x15
|
||||||
VK_HANGUL :: 0x15;
|
VK_HANGUL :: 0x15
|
||||||
VK_JUNJA :: 0x17;
|
VK_JUNJA :: 0x17
|
||||||
VK_FINAL :: 0x18;
|
VK_FINAL :: 0x18
|
||||||
VK_HANJA :: 0x19;
|
VK_HANJA :: 0x19
|
||||||
VK_KANJI :: 0x19;
|
VK_KANJI :: 0x19
|
||||||
|
|
||||||
VK_ESCAPE :: 0x1B;
|
VK_ESCAPE :: 0x1B
|
||||||
|
|
||||||
VK_CONVERT :: 0x1C;
|
VK_CONVERT :: 0x1C
|
||||||
VK_NONCONVERT :: 0x1D;
|
VK_NONCONVERT :: 0x1D
|
||||||
VK_ACCEPT :: 0x1E;
|
VK_ACCEPT :: 0x1E
|
||||||
VK_MODECHANGE :: 0x1F;
|
VK_MODECHANGE :: 0x1F
|
||||||
|
|
||||||
VK_SPACE :: 0x20;
|
VK_SPACE :: 0x20
|
||||||
VK_PRIOR :: 0x21;
|
VK_PRIOR :: 0x21
|
||||||
VK_NEXT :: 0x22;
|
VK_NEXT :: 0x22
|
||||||
VK_END :: 0x23;
|
VK_END :: 0x23
|
||||||
VK_HOME :: 0x24;
|
VK_HOME :: 0x24
|
||||||
VK_LEFT :: 0x25;
|
VK_LEFT :: 0x25
|
||||||
VK_UP :: 0x26;
|
VK_UP :: 0x26
|
||||||
VK_RIGHT :: 0x27;
|
VK_RIGHT :: 0x27
|
||||||
VK_DOWN :: 0x28;
|
VK_DOWN :: 0x28
|
||||||
VK_SELECT :: 0x29;
|
VK_SELECT :: 0x29
|
||||||
VK_PRINT :: 0x2A;
|
VK_PRINT :: 0x2A
|
||||||
VK_EXECUTE :: 0x2B;
|
VK_EXECUTE :: 0x2B
|
||||||
VK_SNAPSHOT :: 0x2C;
|
VK_SNAPSHOT :: 0x2C
|
||||||
VK_INSERT :: 0x2D;
|
VK_INSERT :: 0x2D
|
||||||
VK_DELETE :: 0x2E;
|
VK_DELETE :: 0x2E
|
||||||
VK_HELP :: 0x2F;
|
VK_HELP :: 0x2F
|
||||||
|
|
||||||
VK_0 :: #rune "0";
|
VK_0 :: #rune "0"
|
||||||
VK_1 :: #rune "1";
|
VK_1 :: #rune "1"
|
||||||
VK_2 :: #rune "2";
|
VK_2 :: #rune "2"
|
||||||
VK_3 :: #rune "3";
|
VK_3 :: #rune "3"
|
||||||
VK_4 :: #rune "4";
|
VK_4 :: #rune "4"
|
||||||
VK_5 :: #rune "5";
|
VK_5 :: #rune "5"
|
||||||
VK_6 :: #rune "6";
|
VK_6 :: #rune "6"
|
||||||
VK_7 :: #rune "7";
|
VK_7 :: #rune "7"
|
||||||
VK_8 :: #rune "8";
|
VK_8 :: #rune "8"
|
||||||
VK_9 :: #rune "9";
|
VK_9 :: #rune "9"
|
||||||
|
|
||||||
VK_A :: #rune "A";
|
VK_A :: #rune "A"
|
||||||
VK_B :: #rune "B";
|
VK_B :: #rune "B"
|
||||||
VK_C :: #rune "C";
|
VK_C :: #rune "C"
|
||||||
VK_D :: #rune "D";
|
VK_D :: #rune "D"
|
||||||
VK_E :: #rune "E";
|
VK_E :: #rune "E"
|
||||||
VK_F :: #rune "F";
|
VK_F :: #rune "F"
|
||||||
VK_G :: #rune "G";
|
VK_G :: #rune "G"
|
||||||
VK_H :: #rune "H";
|
VK_H :: #rune "H"
|
||||||
VK_I :: #rune "I";
|
VK_I :: #rune "I"
|
||||||
VK_J :: #rune "J";
|
VK_J :: #rune "J"
|
||||||
VK_K :: #rune "K";
|
VK_K :: #rune "K"
|
||||||
VK_L :: #rune "L";
|
VK_L :: #rune "L"
|
||||||
VK_M :: #rune "M";
|
VK_M :: #rune "M"
|
||||||
VK_N :: #rune "N";
|
VK_N :: #rune "N"
|
||||||
VK_O :: #rune "O";
|
VK_O :: #rune "O"
|
||||||
VK_P :: #rune "P";
|
VK_P :: #rune "P"
|
||||||
VK_Q :: #rune "Q";
|
VK_Q :: #rune "Q"
|
||||||
VK_R :: #rune "R";
|
VK_R :: #rune "R"
|
||||||
VK_S :: #rune "S";
|
VK_S :: #rune "S"
|
||||||
VK_T :: #rune "T";
|
VK_T :: #rune "T"
|
||||||
VK_U :: #rune "U";
|
VK_U :: #rune "U"
|
||||||
VK_V :: #rune "V";
|
VK_V :: #rune "V"
|
||||||
VK_W :: #rune "W";
|
VK_W :: #rune "W"
|
||||||
VK_X :: #rune "X";
|
VK_X :: #rune "X"
|
||||||
VK_Y :: #rune "Y";
|
VK_Y :: #rune "Y"
|
||||||
VK_Z :: #rune "Z";
|
VK_Z :: #rune "Z"
|
||||||
|
|
||||||
VK_LWIN :: 0x5B;
|
VK_LWIN :: 0x5B
|
||||||
VK_RWIN :: 0x5C;
|
VK_RWIN :: 0x5C
|
||||||
VK_APPS :: 0x5D;
|
VK_APPS :: 0x5D
|
||||||
|
|
||||||
VK_NUMPAD0 :: 0x60;
|
VK_NUMPAD0 :: 0x60
|
||||||
VK_NUMPAD1 :: 0x61;
|
VK_NUMPAD1 :: 0x61
|
||||||
VK_NUMPAD2 :: 0x62;
|
VK_NUMPAD2 :: 0x62
|
||||||
VK_NUMPAD3 :: 0x63;
|
VK_NUMPAD3 :: 0x63
|
||||||
VK_NUMPAD4 :: 0x64;
|
VK_NUMPAD4 :: 0x64
|
||||||
VK_NUMPAD5 :: 0x65;
|
VK_NUMPAD5 :: 0x65
|
||||||
VK_NUMPAD6 :: 0x66;
|
VK_NUMPAD6 :: 0x66
|
||||||
VK_NUMPAD7 :: 0x67;
|
VK_NUMPAD7 :: 0x67
|
||||||
VK_NUMPAD8 :: 0x68;
|
VK_NUMPAD8 :: 0x68
|
||||||
VK_NUMPAD9 :: 0x69;
|
VK_NUMPAD9 :: 0x69
|
||||||
VK_MULTIPLY :: 0x6A;
|
VK_MULTIPLY :: 0x6A
|
||||||
VK_ADD :: 0x6B;
|
VK_ADD :: 0x6B
|
||||||
VK_SEPARATOR :: 0x6C;
|
VK_SEPARATOR :: 0x6C
|
||||||
VK_SUBTRACT :: 0x6D;
|
VK_SUBTRACT :: 0x6D
|
||||||
VK_DECIMAL :: 0x6E;
|
VK_DECIMAL :: 0x6E
|
||||||
VK_DIVIDE :: 0x6F;
|
VK_DIVIDE :: 0x6F
|
||||||
VK_F1 :: 0x70;
|
VK_F1 :: 0x70
|
||||||
VK_F2 :: 0x71;
|
VK_F2 :: 0x71
|
||||||
VK_F3 :: 0x72;
|
VK_F3 :: 0x72
|
||||||
VK_F4 :: 0x73;
|
VK_F4 :: 0x73
|
||||||
VK_F5 :: 0x74;
|
VK_F5 :: 0x74
|
||||||
VK_F6 :: 0x75;
|
VK_F6 :: 0x75
|
||||||
VK_F7 :: 0x76;
|
VK_F7 :: 0x76
|
||||||
VK_F8 :: 0x77;
|
VK_F8 :: 0x77
|
||||||
VK_F9 :: 0x78;
|
VK_F9 :: 0x78
|
||||||
VK_F10 :: 0x79;
|
VK_F10 :: 0x79
|
||||||
VK_F11 :: 0x7A;
|
VK_F11 :: 0x7A
|
||||||
VK_F12 :: 0x7B;
|
VK_F12 :: 0x7B
|
||||||
VK_F13 :: 0x7C;
|
VK_F13 :: 0x7C
|
||||||
VK_F14 :: 0x7D;
|
VK_F14 :: 0x7D
|
||||||
VK_F15 :: 0x7E;
|
VK_F15 :: 0x7E
|
||||||
VK_F16 :: 0x7F;
|
VK_F16 :: 0x7F
|
||||||
VK_F17 :: 0x80;
|
VK_F17 :: 0x80
|
||||||
VK_F18 :: 0x81;
|
VK_F18 :: 0x81
|
||||||
VK_F19 :: 0x82;
|
VK_F19 :: 0x82
|
||||||
VK_F20 :: 0x83;
|
VK_F20 :: 0x83
|
||||||
VK_F21 :: 0x84;
|
VK_F21 :: 0x84
|
||||||
VK_F22 :: 0x85;
|
VK_F22 :: 0x85
|
||||||
VK_F23 :: 0x86;
|
VK_F23 :: 0x86
|
||||||
VK_F24 :: 0x87;
|
VK_F24 :: 0x87
|
||||||
|
|
||||||
VK_NUMLOCK :: 0x90;
|
VK_NUMLOCK :: 0x90
|
||||||
VK_SCROLL :: 0x91;
|
VK_SCROLL :: 0x91
|
||||||
|
|
||||||
VK_LSHIFT :: 0xA0;
|
VK_LSHIFT :: 0xA0
|
||||||
VK_RSHIFT :: 0xA1;
|
VK_RSHIFT :: 0xA1
|
||||||
VK_LCONTROL :: 0xA2;
|
VK_LCONTROL :: 0xA2
|
||||||
VK_RCONTROL :: 0xA3;
|
VK_RCONTROL :: 0xA3
|
||||||
VK_LMENU :: 0xA4;
|
VK_LMENU :: 0xA4
|
||||||
VK_RMENU :: 0xA5;
|
VK_RMENU :: 0xA5
|
||||||
VK_PROCESSKEY :: 0xE5;
|
VK_PROCESSKEY :: 0xE5
|
||||||
VK_ATTN :: 0xF6;
|
VK_ATTN :: 0xF6
|
||||||
VK_CRSEL :: 0xF7;
|
VK_CRSEL :: 0xF7
|
||||||
VK_EXSEL :: 0xF8;
|
VK_EXSEL :: 0xF8
|
||||||
VK_EREOF :: 0xF9;
|
VK_EREOF :: 0xF9
|
||||||
VK_PLAY :: 0xFA;
|
VK_PLAY :: 0xFA
|
||||||
VK_ZOOM :: 0xFB;
|
VK_ZOOM :: 0xFB
|
||||||
VK_NONAME :: 0xFC;
|
VK_NONAME :: 0xFC
|
||||||
VK_PA1 :: 0xFD;
|
VK_PA1 :: 0xFD
|
||||||
VK_OEM_CLEAR :: 0xFE;
|
VK_OEM_CLEAR :: 0xFE
|
||||||
|
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity)
|
|||||||
map_set(&i->definitions, key, entity);
|
map_set(&i->definitions, key, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||||
if (!are_strings_equal(entity->token.string, make_string("_"))) {
|
if (!are_strings_equal(entity->token.string, make_string("_"))) {
|
||||||
Entity *insert_entity = scope_insert_entity(scope, entity);
|
Entity *insert_entity = scope_insert_entity(scope, entity);
|
||||||
if (insert_entity) {
|
if (insert_entity) {
|
||||||
@@ -541,18 +541,20 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
|||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(entity->token.string),
|
LIT(entity->token.string),
|
||||||
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);
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
error(&c->error_collector, entity->token,
|
error(&c->error_collector, entity->token,
|
||||||
"Redeclararation of `%.*s` in this scope\n"
|
"Redeclararation of `%.*s` in this scope\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(entity->token.string),
|
LIT(entity->token.string),
|
||||||
LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column);
|
LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (identifier != NULL)
|
if (identifier != NULL)
|
||||||
add_entity_definition(&c->info, identifier, entity);
|
add_entity_definition(&c->info, identifier, entity);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
|
void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
|
||||||
@@ -733,6 +735,10 @@ void check_parsed_files(Checker *c) {
|
|||||||
case_ast_node(ld, LoadDecl, decl);
|
case_ast_node(ld, LoadDecl, decl);
|
||||||
// NOTE(bill): ignore
|
// NOTE(bill): ignore
|
||||||
case_end;
|
case_end;
|
||||||
|
case_ast_node(fsl, ForeignSystemLibrary, decl);
|
||||||
|
// NOTE(bill): ignore
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");
|
error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope");
|
||||||
|
|||||||
+13
-3
@@ -6,6 +6,7 @@ enum BuiltinProcId;
|
|||||||
ENTITY_KIND(Invalid), \
|
ENTITY_KIND(Invalid), \
|
||||||
ENTITY_KIND(Constant), \
|
ENTITY_KIND(Constant), \
|
||||||
ENTITY_KIND(Variable), \
|
ENTITY_KIND(Variable), \
|
||||||
|
ENTITY_KIND(UsingVariable), \
|
||||||
ENTITY_KIND(TypeName), \
|
ENTITY_KIND(TypeName), \
|
||||||
ENTITY_KIND(Procedure), \
|
ENTITY_KIND(Procedure), \
|
||||||
ENTITY_KIND(Builtin), \
|
ENTITY_KIND(Builtin), \
|
||||||
@@ -35,6 +36,7 @@ struct Entity {
|
|||||||
Token token;
|
Token token;
|
||||||
Type *type;
|
Type *type;
|
||||||
Entity *using_parent;
|
Entity *using_parent;
|
||||||
|
AstNode *using_expr;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct { ExactValue value; } Constant;
|
struct { ExactValue value; } Constant;
|
||||||
@@ -44,9 +46,9 @@ struct Entity {
|
|||||||
b8 is_field; // Is struct field
|
b8 is_field; // Is struct field
|
||||||
b8 anonymous; // Variable is an anonymous
|
b8 anonymous; // Variable is an anonymous
|
||||||
} Variable;
|
} Variable;
|
||||||
struct {
|
struct {} UsingVariable;
|
||||||
b8 used;
|
struct {} TypeName;
|
||||||
} Procedure;
|
struct { b8 used; } Procedure;
|
||||||
struct { BuiltinProcId id; } Builtin;
|
struct { BuiltinProcId id; } Builtin;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -72,6 +74,14 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||||
|
GB_ASSERT(parent != NULL);
|
||||||
|
Entity *entity = alloc_entity(a, Entity_UsingVariable, parent->scope, token, type);
|
||||||
|
entity->using_parent = parent;
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
|
Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
|
||||||
Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
|
||||||
entity->Constant.value = value;
|
entity->Constant.value = value;
|
||||||
|
|||||||
+23
-5
@@ -4,7 +4,7 @@ void check_expr_or_type (Checker *c, Operand *operand, AstNode *expre
|
|||||||
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL);
|
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL);
|
||||||
Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL);
|
Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL);
|
||||||
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
|
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
|
||||||
void check_selector (Checker *c, Operand *operand, AstNode *node);
|
Entity * check_selector (Checker *c, Operand *operand, AstNode *node);
|
||||||
void check_not_tuple (Checker *c, Operand *operand);
|
void check_not_tuple (Checker *c, Operand *operand);
|
||||||
b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
|
b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
|
||||||
void convert_to_typed (Checker *c, Operand *operand, Type *target_type);
|
void convert_to_typed (Checker *c, Operand *operand, Type *target_type);
|
||||||
@@ -143,6 +143,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
|
|||||||
error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str);
|
error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str);
|
||||||
} else {
|
} else {
|
||||||
map_set(entity_map, key, f);
|
map_set(entity_map, key, f);
|
||||||
|
add_entity(c, c->context.scope, NULL, f);
|
||||||
if (f->Variable.anonymous) {
|
if (f->Variable.anonymous) {
|
||||||
populate_using_entity_map(c, node, f->type, entity_map);
|
populate_using_entity_map(c, node, f->type, entity_map);
|
||||||
}
|
}
|
||||||
@@ -338,6 +339,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke
|
|||||||
} else {
|
} else {
|
||||||
map_set(&entity_map, key, e);
|
map_set(&entity_map, key, e);
|
||||||
fields[field_index++] = e;
|
fields[field_index++] = e;
|
||||||
|
add_entity(c, c->context.scope, name, e);
|
||||||
}
|
}
|
||||||
add_entity_use(&c->info, name, e);
|
add_entity_use(&c->info, name, e);
|
||||||
}
|
}
|
||||||
@@ -610,6 +612,11 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
|||||||
o->mode = Addressing_Builtin;
|
o->mode = Addressing_Builtin;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Entity_UsingVariable:
|
||||||
|
// TODO(bill): Entity_UsingVariable: is this correct?
|
||||||
|
o->mode = Addressing_Variable;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Compiler error: Unknown EntityKind");
|
GB_PANIC("Compiler error: Unknown EntityKind");
|
||||||
break;
|
break;
|
||||||
@@ -727,6 +734,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
|||||||
check_open_scope(c, e);
|
check_open_scope(c, e);
|
||||||
check_struct_type(c, type, e, cycle_checker);
|
check_struct_type(c, type, e, cycle_checker);
|
||||||
check_close_scope(c);
|
check_close_scope(c);
|
||||||
|
type->Struct.node = e;
|
||||||
goto end;
|
goto end;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -736,6 +744,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
|||||||
check_open_scope(c, e);
|
check_open_scope(c, e);
|
||||||
check_union_type(c, type, e, cycle_checker);
|
check_union_type(c, type, e, cycle_checker);
|
||||||
check_close_scope(c);
|
check_close_scope(c);
|
||||||
|
type->Union.node = e;
|
||||||
goto end;
|
goto end;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -1746,7 +1755,7 @@ Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Sele
|
|||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||||
GB_ASSERT(node->kind == AstNode_SelectorExpr);
|
GB_ASSERT(node->kind == AstNode_SelectorExpr);
|
||||||
|
|
||||||
ast_node(se, SelectorExpr, node);
|
ast_node(se, SelectorExpr, node);
|
||||||
@@ -1764,7 +1773,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
|||||||
error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
|
error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
operand->expr = node;
|
operand->expr = node;
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
add_entity_use(&c->info, selector, entity);
|
add_entity_use(&c->info, selector, entity);
|
||||||
|
|
||||||
@@ -1779,11 +1788,12 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
|||||||
if (operand->mode != Addressing_Variable)
|
if (operand->mode != Addressing_Variable)
|
||||||
operand->mode = Addressing_Value;
|
operand->mode = Addressing_Value;
|
||||||
}
|
}
|
||||||
|
return entity;
|
||||||
} else {
|
} else {
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
operand->expr = node;
|
operand->expr = node;
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
|
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
|
||||||
@@ -1886,7 +1896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
operand->mode = Addressing_Value;
|
operand->mode = Addressing_NoValue;
|
||||||
operand->type = NULL;
|
operand->type = NULL;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -2967,6 +2977,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
case AstNode_ArrayType:
|
case AstNode_ArrayType:
|
||||||
case AstNode_VectorType:
|
case AstNode_VectorType:
|
||||||
case AstNode_StructType:
|
case AstNode_StructType:
|
||||||
|
case AstNode_UnionType:
|
||||||
o->mode = Addressing_Type;
|
o->mode = Addressing_Type;
|
||||||
o->type = check_type(c, node);
|
o->type = check_type(c, node);
|
||||||
break;
|
break;
|
||||||
@@ -3240,6 +3251,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
str = gb_string_appendc(str, "}");
|
str = gb_string_appendc(str, "}");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(st, UnionType, node);
|
||||||
|
str = gb_string_appendc(str, "union{");
|
||||||
|
// str = write_field_list_to_string(str, st->decl_list, ", ");
|
||||||
|
str = gb_string_appendc(str, "}");
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
case_ast_node(et, EnumType, node);
|
case_ast_node(et, EnumType, node);
|
||||||
str = gb_string_appendc(str, "enum ");
|
str = gb_string_appendc(str, "enum ");
|
||||||
if (et->base_type != NULL) {
|
if (et->base_type != NULL) {
|
||||||
|
|||||||
+198
-110
@@ -436,6 +436,107 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void check_var_decl(Checker *c, AstNode *node) {
|
||||||
|
ast_node(vd, VarDecl, node);
|
||||||
|
isize entity_count = vd->name_count;
|
||||||
|
isize entity_index = 0;
|
||||||
|
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||||
|
switch (vd->kind) {
|
||||||
|
case Declaration_Mutable: {
|
||||||
|
Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||||
|
isize new_entity_count = 0;
|
||||||
|
|
||||||
|
for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
|
||||||
|
Entity *entity = NULL;
|
||||||
|
Token token = name->Ident.token;
|
||||||
|
if (name->kind == AstNode_Ident) {
|
||||||
|
String str = token.string;
|
||||||
|
Entity *found = NULL;
|
||||||
|
// NOTE(bill): Ignore assignments to `_`
|
||||||
|
b32 can_be_ignored = are_strings_equal(str, make_string("_"));
|
||||||
|
if (!can_be_ignored) {
|
||||||
|
found = current_scope_lookup_entity(c->context.scope, str);
|
||||||
|
}
|
||||||
|
if (found == NULL) {
|
||||||
|
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
||||||
|
if (!can_be_ignored) {
|
||||||
|
new_entities[new_entity_count++] = entity;
|
||||||
|
}
|
||||||
|
add_entity_definition(&c->info, name, entity);
|
||||||
|
} else {
|
||||||
|
entity = found;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(&c->error_collector, token, "A variable declaration must be an identifier");
|
||||||
|
}
|
||||||
|
if (entity == NULL)
|
||||||
|
entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
|
||||||
|
entities[entity_index++] = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *init_type = NULL;
|
||||||
|
if (vd->type) {
|
||||||
|
init_type = check_type(c, vd->type, NULL);
|
||||||
|
if (init_type == NULL)
|
||||||
|
init_type = t_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
|
Entity *e = entities[i];
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
if (e->Variable.visited) {
|
||||||
|
e->type = t_invalid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
e->Variable.visited = true;
|
||||||
|
|
||||||
|
if (e->type == NULL)
|
||||||
|
e->type = init_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
|
||||||
|
|
||||||
|
AstNode *name = vd->name_list;
|
||||||
|
for (isize i = 0; i < new_entity_count; i++, name = name->next) {
|
||||||
|
add_entity(c, c->context.scope, name, new_entities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Declaration_Immutable: {
|
||||||
|
for (AstNode *name = vd->name_list, *value = vd->value_list;
|
||||||
|
name != NULL && value != NULL;
|
||||||
|
name = name->next, value = value->next) {
|
||||||
|
GB_ASSERT(name->kind == AstNode_Ident);
|
||||||
|
ExactValue v = {ExactValue_Invalid};
|
||||||
|
ast_node(i, Ident, name);
|
||||||
|
Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v);
|
||||||
|
entities[entity_index++] = e;
|
||||||
|
check_const_decl(c, e, vd->type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
isize lhs_count = vd->name_count;
|
||||||
|
isize rhs_count = vd->value_count;
|
||||||
|
|
||||||
|
// TODO(bill): Better error messages or is this good enough?
|
||||||
|
if (rhs_count == 0 && vd->type == NULL) {
|
||||||
|
error(&c->error_collector, ast_node_token(node), "Missing type or initial expression");
|
||||||
|
} else if (lhs_count < rhs_count) {
|
||||||
|
error(&c->error_collector, ast_node_token(node), "Extra initial expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode *name = vd->name_list;
|
||||||
|
for (isize i = 0; i < entity_count; i++, name = name->next) {
|
||||||
|
add_entity(c, c->context.scope, name, entities[i]);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||||
switch (node->kind) {
|
switch (node->kind) {
|
||||||
@@ -688,16 +789,28 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
case_ast_node(us, UsingStmt, node);
|
case_ast_node(us, UsingStmt, node);
|
||||||
switch (us->node->kind) {
|
switch (us->node->kind) {
|
||||||
case_ast_node(es, ExprStmt, us->node);
|
case_ast_node(es, ExprStmt, us->node);
|
||||||
AstNode *ident = es->expr;
|
Entity *e = NULL;
|
||||||
GB_ASSERT(ident->kind == AstNode_Ident);
|
|
||||||
String name = ident->Ident.token.string;
|
b32 is_selector = false;
|
||||||
|
AstNode *expr = unparen_expr(es->expr);
|
||||||
|
if (expr->kind == AstNode_Ident) {
|
||||||
|
String name = expr->Ident.token.string;
|
||||||
|
e = scope_lookup_entity(c, c->context.scope, name);
|
||||||
|
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||||
|
Operand o = {};
|
||||||
|
check_expr_base(c, &o, expr->SelectorExpr.expr);
|
||||||
|
e = check_selector(c, &o, expr);
|
||||||
|
is_selector = true;
|
||||||
|
}
|
||||||
|
|
||||||
Entity *e = scope_lookup_entity(c, c->context.scope, name);
|
|
||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
error(&c->error_collector, us->token, "`using` applied to an unknown entity");
|
error(&c->error_collector, us->token, "`using` applied to an unknown entity");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gbString expr_str = expr_to_string(expr);
|
||||||
|
defer (gb_string_free(expr_str));
|
||||||
|
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_TypeName: {
|
case Entity_TypeName: {
|
||||||
Type *t = get_base_type(e->type);
|
Type *t = get_base_type(e->type);
|
||||||
@@ -706,20 +819,34 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
Entity *f = t->Enum.fields[i];
|
Entity *f = t->Enum.fields[i];
|
||||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of the constant: %.*s", LIT(name), LIT(found->token.string));
|
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of the constant: %.*s", expr_str, LIT(found->token.string));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
f->using_parent = e;
|
f->using_parent = e;
|
||||||
}
|
}
|
||||||
} else if (t->kind == Type_Struct) {
|
} else if (t->kind == Type_Struct) {
|
||||||
for (isize i = 0; i < t->Struct.other_field_count; i++) {
|
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
|
||||||
Entity *f = t->Struct.other_fields[i];
|
if (found != NULL) {
|
||||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
gb_for_array(i, (*found)->elements.entries) {
|
||||||
if (found != NULL) {
|
Entity *f = (*found)->elements.entries[i].value;
|
||||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(found->token.string));
|
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||||
return;
|
if (found != NULL) {
|
||||||
|
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f->using_parent = e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (isize i = 0; i < t->Struct.other_field_count; i++) {
|
||||||
|
// TODO(bill): using field types too
|
||||||
|
Entity *f = t->Struct.other_fields[i];
|
||||||
|
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||||
|
if (found != NULL) {
|
||||||
|
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f->using_parent = e;
|
||||||
}
|
}
|
||||||
f->using_parent = e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -733,13 +860,70 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
error(&c->error_collector, us->token, "`using` cannot be applied to a procedure");
|
error(&c->error_collector, us->token, "`using` cannot be applied to a procedure");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Entity_Variable:
|
||||||
|
case Entity_UsingVariable: {
|
||||||
|
Type *t = get_base_type(type_deref(e->type));
|
||||||
|
if (t->kind == Type_Struct || t->kind == Type_Union) {
|
||||||
|
// IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing
|
||||||
|
// for some variables to accessed to same
|
||||||
|
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
gb_for_array(i, (*found)->elements.entries) {
|
||||||
|
Entity *f = (*found)->elements.entries[i].value;
|
||||||
|
if (f->kind == Entity_Variable) {
|
||||||
|
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||||
|
if (is_selector) {
|
||||||
|
uvar->using_expr = expr;
|
||||||
|
}
|
||||||
|
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||||
|
if (prev != NULL) {
|
||||||
|
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("TODO(bill): using Ident");
|
GB_PANIC("TODO(bill): using Ident");
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(vd, VarDecl, us->node);
|
case_ast_node(vd, VarDecl, us->node);
|
||||||
GB_PANIC("TODO(bill): using VarDecl");
|
if (vd->name_count > 1) {
|
||||||
|
error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type");
|
||||||
|
}
|
||||||
|
check_var_decl(c, us->node);
|
||||||
|
ast_node(i, Ident, vd->name_list);
|
||||||
|
|
||||||
|
String name = i->token.string;
|
||||||
|
Entity *e = scope_lookup_entity(c, c->context.scope, name);
|
||||||
|
|
||||||
|
Type *t = get_base_type(type_deref(e->type));
|
||||||
|
if (t->kind == Type_Struct || t->kind == Type_Union) {
|
||||||
|
// IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing
|
||||||
|
// for some variables to accessed to same
|
||||||
|
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
gb_for_array(i, (*found)->elements.entries) {
|
||||||
|
Entity *f = (*found)->elements.entries[i].value;
|
||||||
|
if (f->kind == Entity_Variable) {
|
||||||
|
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||||
|
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||||
|
if (prev != NULL) {
|
||||||
|
error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union");
|
||||||
|
return;
|
||||||
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
@@ -755,103 +939,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
|
|
||||||
case_ast_node(vd, VarDecl, node);
|
case_ast_node(vd, VarDecl, node);
|
||||||
isize entity_count = vd->name_count;
|
check_var_decl(c, node);
|
||||||
isize entity_index = 0;
|
|
||||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
|
||||||
switch (vd->kind) {
|
|
||||||
case Declaration_Mutable: {
|
|
||||||
Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
|
||||||
isize new_entity_count = 0;
|
|
||||||
|
|
||||||
for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
|
|
||||||
Entity *entity = NULL;
|
|
||||||
Token token = name->Ident.token;
|
|
||||||
if (name->kind == AstNode_Ident) {
|
|
||||||
String str = token.string;
|
|
||||||
Entity *found = NULL;
|
|
||||||
// NOTE(bill): Ignore assignments to `_`
|
|
||||||
b32 can_be_ignored = are_strings_equal(str, make_string("_"));
|
|
||||||
if (!can_be_ignored) {
|
|
||||||
found = current_scope_lookup_entity(c->context.scope, str);
|
|
||||||
}
|
|
||||||
if (found == NULL) {
|
|
||||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
|
|
||||||
if (!can_be_ignored) {
|
|
||||||
new_entities[new_entity_count++] = entity;
|
|
||||||
}
|
|
||||||
add_entity_definition(&c->info, name, entity);
|
|
||||||
} else {
|
|
||||||
entity = found;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error(&c->error_collector, token, "A variable declaration must be an identifier");
|
|
||||||
}
|
|
||||||
if (entity == NULL)
|
|
||||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
|
|
||||||
entities[entity_index++] = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *init_type = NULL;
|
|
||||||
if (vd->type) {
|
|
||||||
init_type = check_type(c, vd->type, NULL);
|
|
||||||
if (init_type == NULL)
|
|
||||||
init_type = t_invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
|
||||||
Entity *e = entities[i];
|
|
||||||
GB_ASSERT(e != NULL);
|
|
||||||
if (e->Variable.visited) {
|
|
||||||
e->type = t_invalid;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
e->Variable.visited = true;
|
|
||||||
|
|
||||||
if (e->type == NULL)
|
|
||||||
e->type = init_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
|
|
||||||
|
|
||||||
AstNode *name = vd->name_list;
|
|
||||||
for (isize i = 0; i < new_entity_count; i++, name = name->next) {
|
|
||||||
add_entity(c, c->context.scope, name, new_entities[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Declaration_Immutable: {
|
|
||||||
for (AstNode *name = vd->name_list, *value = vd->value_list;
|
|
||||||
name != NULL && value != NULL;
|
|
||||||
name = name->next, value = value->next) {
|
|
||||||
GB_ASSERT(name->kind == AstNode_Ident);
|
|
||||||
ExactValue v = {ExactValue_Invalid};
|
|
||||||
ast_node(i, Ident, name);
|
|
||||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v);
|
|
||||||
entities[entity_index++] = e;
|
|
||||||
check_const_decl(c, e, vd->type, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
isize lhs_count = vd->name_count;
|
|
||||||
isize rhs_count = vd->value_count;
|
|
||||||
|
|
||||||
// TODO(bill): Better error messages or is this good enough?
|
|
||||||
if (rhs_count == 0 && vd->type == NULL) {
|
|
||||||
error(&c->error_collector, ast_node_token(node), "Missing type or initial expression");
|
|
||||||
} else if (lhs_count < rhs_count) {
|
|
||||||
error(&c->error_collector, ast_node_token(node), "Extra initial expression");
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *name = vd->name_list;
|
|
||||||
for (isize i = 0; i < entity_count; i++, name = name->next) {
|
|
||||||
add_entity(c, c->context.scope, name, entities[i]);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(pd, ProcDecl, node);
|
case_ast_node(pd, ProcDecl, node);
|
||||||
|
|||||||
@@ -107,18 +107,22 @@ struct Type {
|
|||||||
// Theses are arrays
|
// Theses are arrays
|
||||||
Entity **fields; // Entity_Variable
|
Entity **fields; // Entity_Variable
|
||||||
isize field_count; // == offset_count
|
isize field_count; // == offset_count
|
||||||
|
AstNode *node;
|
||||||
|
|
||||||
i64 * offsets;
|
i64 * offsets;
|
||||||
b32 are_offsets_set;
|
b32 are_offsets_set;
|
||||||
b32 is_packed;
|
b32 is_packed;
|
||||||
|
|
||||||
Entity **other_fields; // Entity_Constant or Entity_TypeName
|
Entity **other_fields; // Entity_Constant or Entity_TypeName
|
||||||
isize other_field_count;
|
isize other_field_count;
|
||||||
|
|
||||||
} Struct;
|
} Struct;
|
||||||
struct {
|
struct {
|
||||||
// IMPORTANT HACK(bill): The positions of fields and field_count
|
// IMPORTANT HACK(bill): The positions of fields, field_count, and node
|
||||||
// must be same for Struct and Union
|
// must be same for Struct and Union
|
||||||
Entity **fields; // Entity_Variable
|
Entity **fields; // Entity_Variable
|
||||||
isize field_count;
|
isize field_count;
|
||||||
|
AstNode *node;
|
||||||
} Union;
|
} Union;
|
||||||
struct { Type *elem; } Pointer;
|
struct { Type *elem; } Pointer;
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
+36
-1
@@ -2034,6 +2034,30 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
|
||||||
|
GB_ASSERT(e->kind == Entity_UsingVariable);
|
||||||
|
String name = e->token.string;
|
||||||
|
Entity *parent = e->using_parent;
|
||||||
|
ssaValue *p = NULL;
|
||||||
|
if (parent->kind == Entity_UsingVariable) {
|
||||||
|
p = ssa_add_using_variable(proc, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Selection sel = lookup_field(parent->type, name, Addressing_Variable);
|
||||||
|
GB_ASSERT(sel.entity != NULL);
|
||||||
|
ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
|
||||||
|
ssaValue *v = NULL;
|
||||||
|
if (pv != NULL) {
|
||||||
|
v = *pv;
|
||||||
|
} else {
|
||||||
|
v = ssa_build_addr(proc, e->using_expr).addr;
|
||||||
|
}
|
||||||
|
GB_ASSERT(v != NULL);
|
||||||
|
ssaValue *var = ssa_emit_deep_field_gep(proc, parent->type, v, sel);
|
||||||
|
map_set(&proc->module->values, hash_pointer(e), var);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||||
switch (expr->kind) {
|
switch (expr->kind) {
|
||||||
case_ast_node(i, Ident, expr);
|
case_ast_node(i, Ident, expr);
|
||||||
@@ -2047,9 +2071,13 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
|||||||
ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
|
ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
|
||||||
if (found) {
|
if (found) {
|
||||||
v = *found;
|
v = *found;
|
||||||
} else {
|
} else if (e->kind == Entity_UsingVariable) {
|
||||||
|
v = ssa_add_using_variable(proc, e);
|
||||||
|
}
|
||||||
|
if (v == NULL) {
|
||||||
GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e);
|
GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssa_make_addr(v, expr);
|
return ssa_make_addr(v, expr);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -2286,6 +2314,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
|||||||
case_ast_node(bs, EmptyStmt, node);
|
case_ast_node(bs, EmptyStmt, node);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(us, UsingStmt, node);
|
||||||
|
AstNode *decl = unparen_expr(us->node);
|
||||||
|
if (decl->kind == AstNode_VarDecl) {
|
||||||
|
ssa_build_stmt(proc, decl);
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(vd, VarDecl, node);
|
case_ast_node(vd, VarDecl, node);
|
||||||
if (vd->kind == Declaration_Mutable) {
|
if (vd->kind == Declaration_Mutable) {
|
||||||
if (vd->name_count == vd->value_count) { // 1:1 assigment
|
if (vd->name_count == vd->value_count) { // 1:1 assigment
|
||||||
|
|||||||
+14
-2
@@ -93,14 +93,26 @@ int main(int argc, char **argv) {
|
|||||||
#if 1
|
#if 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib");
|
||||||
|
char lib_str_buf[1024] = {};
|
||||||
|
gb_for_array(i, parser.system_libraries) {
|
||||||
|
String lib = parser.system_libraries[i];
|
||||||
|
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||||
|
" -l%.*s.lib", LIT(lib));
|
||||||
|
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
exit_code = win32_exec_command_line_app(
|
exit_code = win32_exec_command_line_app(
|
||||||
"clang -o %.*s.exe %.*s.bc "
|
"clang -o %.*s.exe %.*s.bc "
|
||||||
"-Wno-override-module "
|
"-Wno-override-module "
|
||||||
// "-nostartfiles "
|
// "-nostartfiles "
|
||||||
"-lKernel32.lib -lUser32.lib -lGdi32.lib -lOpengl32.lib "
|
"%s "
|
||||||
,
|
,
|
||||||
cast(int)base_name_len, output_name,
|
cast(int)base_name_len, output_name,
|
||||||
cast(int)base_name_len, output_name);
|
cast(int)base_name_len, output_name,
|
||||||
|
lib_str);
|
||||||
|
gb_string_free(lib_str);
|
||||||
if (exit_code != 0)
|
if (exit_code != 0)
|
||||||
return exit_code;
|
return exit_code;
|
||||||
|
|
||||||
|
|||||||
+79
-14
@@ -32,6 +32,7 @@ struct AstFile {
|
|||||||
|
|
||||||
AstScope *file_scope;
|
AstScope *file_scope;
|
||||||
AstScope *curr_scope;
|
AstScope *curr_scope;
|
||||||
|
AstNode *curr_proc;
|
||||||
isize scope_level;
|
isize scope_level;
|
||||||
|
|
||||||
ErrorCollector error_collector;
|
ErrorCollector error_collector;
|
||||||
@@ -60,6 +61,8 @@ struct Parser {
|
|||||||
String init_fullpath;
|
String init_fullpath;
|
||||||
gbArray(AstFile) files;
|
gbArray(AstFile) files;
|
||||||
gbArray(String) loads;
|
gbArray(String) loads;
|
||||||
|
gbArray(String) libraries;
|
||||||
|
gbArray(String) system_libraries;
|
||||||
isize load_index;
|
isize load_index;
|
||||||
isize total_token_count;
|
isize total_token_count;
|
||||||
};
|
};
|
||||||
@@ -193,6 +196,7 @@ AST_NODE_KIND(_DeclBegin, struct{}) \
|
|||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(TypeDecl, struct { Token token; AstNode *name, *type; }) \
|
AST_NODE_KIND(TypeDecl, struct { Token token; AstNode *name, *type; }) \
|
||||||
AST_NODE_KIND(LoadDecl, struct { Token token, filepath; }) \
|
AST_NODE_KIND(LoadDecl, struct { Token token, filepath; }) \
|
||||||
|
AST_NODE_KIND(ForeignSystemLibrary, struct { Token token, filepath; }) \
|
||||||
AST_NODE_KIND(_DeclEnd, struct{}) \
|
AST_NODE_KIND(_DeclEnd, struct{}) \
|
||||||
AST_NODE_KIND(_TypeBegin, struct{}) \
|
AST_NODE_KIND(_TypeBegin, struct{}) \
|
||||||
AST_NODE_KIND(Field, struct { \
|
AST_NODE_KIND(Field, struct { \
|
||||||
@@ -368,6 +372,8 @@ Token ast_node_token(AstNode *node) {
|
|||||||
return node->TypeDecl.token;
|
return node->TypeDecl.token;
|
||||||
case AstNode_LoadDecl:
|
case AstNode_LoadDecl:
|
||||||
return node->LoadDecl.token;
|
return node->LoadDecl.token;
|
||||||
|
case AstNode_ForeignSystemLibrary:
|
||||||
|
return node->ForeignSystemLibrary.token;
|
||||||
case AstNode_Field: {
|
case AstNode_Field: {
|
||||||
if (node->Field.name_list)
|
if (node->Field.name_list)
|
||||||
return ast_node_token(node->Field.name_list);
|
return ast_node_token(node->Field.name_list);
|
||||||
@@ -831,6 +837,12 @@ gb_inline AstNode *make_load_decl(AstFile *f, Token token, Token filepath) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) {
|
||||||
|
AstNode *result = make_node(f, AstNode_ForeignSystemLibrary);
|
||||||
|
result->ForeignSystemLibrary.token = token;
|
||||||
|
result->ForeignSystemLibrary.filepath = filepath;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
gb_inline b32 next_token(AstFile *f) {
|
gb_inline b32 next_token(AstFile *f) {
|
||||||
if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) {
|
if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) {
|
||||||
@@ -967,11 +979,15 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!allow_token(f, Token_Semicolon)) {
|
if (!allow_token(f, Token_Semicolon)) {
|
||||||
// CLEANUP(bill): Semicolon handling in parser
|
if (f->cursor[0].pos.line == f->cursor[-1].pos.line) {
|
||||||
ast_file_err(f, f->cursor[0],
|
if (f->cursor[0].kind != Token_CloseBrace) {
|
||||||
"Expected `;` after %.*s, got `%.*s`",
|
// CLEANUP(bill): Semicolon handling in parser
|
||||||
LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
|
ast_file_err(f, f->cursor[0],
|
||||||
return false;
|
"Expected `;` after %.*s, got `%.*s`",
|
||||||
|
LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1203,7 +1219,10 @@ AstNode *parse_operand(AstFile *f, b32 lhs) {
|
|||||||
// Parse Procedure Type or Literal
|
// Parse Procedure Type or Literal
|
||||||
case Token_proc: {
|
case Token_proc: {
|
||||||
AstScope *scope = NULL;
|
AstScope *scope = NULL;
|
||||||
|
AstNode *curr_proc = f->curr_proc;
|
||||||
AstNode *type = parse_proc_type(f, &scope);
|
AstNode *type = parse_proc_type(f, &scope);
|
||||||
|
f->curr_proc = type;
|
||||||
|
defer (f->curr_proc = curr_proc);
|
||||||
|
|
||||||
u64 tags = 0;
|
u64 tags = 0;
|
||||||
String foreign_name = {};
|
String foreign_name = {};
|
||||||
@@ -1862,8 +1881,13 @@ AstNode *parse_identifier_or_type(AstFile *f) {
|
|||||||
return make_enum_type(f, token, base_type, root, field_count);
|
return make_enum_type(f, token, base_type, root, field_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Token_proc:
|
case Token_proc: {
|
||||||
return parse_proc_type(f, NULL);
|
AstNode *curr_proc = f->curr_proc;
|
||||||
|
AstNode *type = parse_proc_type(f, NULL);
|
||||||
|
f->curr_proc = type;
|
||||||
|
f->curr_proc = curr_proc;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case Token_OpenParen: {
|
case Token_OpenParen: {
|
||||||
@@ -2126,10 +2150,14 @@ AstNode *parse_return_stmt(AstFile *f) {
|
|||||||
Token token = expect_token(f, Token_return);
|
Token token = expect_token(f, Token_return);
|
||||||
AstNode *result = NULL;
|
AstNode *result = NULL;
|
||||||
isize result_count = 0;
|
isize result_count = 0;
|
||||||
if (f->cursor[0].kind != Token_Semicolon)
|
|
||||||
|
if (f->cursor[0].kind != Token_Semicolon && f->cursor[0].kind != Token_CloseBrace &&
|
||||||
|
f->cursor[0].pos.line == token.pos.line) {
|
||||||
result = parse_rhs_expr_list(f, &result_count);
|
result = parse_rhs_expr_list(f, &result_count);
|
||||||
if (f->cursor[0].kind != Token_CloseBrace)
|
}
|
||||||
expect_token(f, Token_Semicolon);
|
if (f->cursor[0].kind != Token_CloseBrace) {
|
||||||
|
expect_semicolon_after_stmt(f, result);
|
||||||
|
}
|
||||||
|
|
||||||
return make_return_stmt(f, token, result, result_count);
|
return make_return_stmt(f, token, result, result_count);
|
||||||
}
|
}
|
||||||
@@ -2248,11 +2276,15 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
b32 valid = false;
|
b32 valid = false;
|
||||||
|
|
||||||
switch (node->kind) {
|
switch (node->kind) {
|
||||||
case AstNode_ExprStmt:
|
case AstNode_ExprStmt: {
|
||||||
if (node->ExprStmt.expr->kind == AstNode_Ident) {
|
AstNode *e = unparen_expr(node->ExprStmt.expr);
|
||||||
|
while (e->kind == AstNode_SelectorExpr) {
|
||||||
|
e = unparen_expr(e->SelectorExpr.selector);
|
||||||
|
}
|
||||||
|
if (e->kind == AstNode_Ident) {
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
case AstNode_VarDecl:
|
case AstNode_VarDecl:
|
||||||
if (node->VarDecl.kind == Declaration_Mutable) {
|
if (node->VarDecl.kind == Declaration_Mutable) {
|
||||||
valid = true;
|
valid = true;
|
||||||
@@ -2279,6 +2311,13 @@ AstNode *parse_stmt(AstFile *f) {
|
|||||||
}
|
}
|
||||||
ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope.");
|
ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope.");
|
||||||
return make_bad_decl(f, token, file_path);
|
return make_bad_decl(f, token, file_path);
|
||||||
|
} else if (are_strings_equal(s->TagStmt.name.string, make_string("foreign_system_library"))) {
|
||||||
|
Token file_path = expect_token(f, Token_String);
|
||||||
|
if (f->curr_scope == f->file_scope) {
|
||||||
|
return make_foreign_system_library(f, s->TagStmt.token, file_path);
|
||||||
|
}
|
||||||
|
ast_file_err(f, token, "You cannot using `foreign_system_library` within a procedure. This must be done at the file scope.");
|
||||||
|
return make_bad_decl(f, token, file_path);
|
||||||
} else if (are_strings_equal(s->TagStmt.name.string, make_string("thread_local"))) {
|
} else if (are_strings_equal(s->TagStmt.name.string, make_string("thread_local"))) {
|
||||||
AstNode *var_decl = parse_simple_stmt(f);
|
AstNode *var_decl = parse_simple_stmt(f);
|
||||||
if (var_decl->kind != AstNode_VarDecl ||
|
if (var_decl->kind != AstNode_VarDecl ||
|
||||||
@@ -2387,6 +2426,8 @@ void destroy_ast_file(AstFile *f) {
|
|||||||
b32 init_parser(Parser *p) {
|
b32 init_parser(Parser *p) {
|
||||||
gb_array_init(p->files, gb_heap_allocator());
|
gb_array_init(p->files, gb_heap_allocator());
|
||||||
gb_array_init(p->loads, gb_heap_allocator());
|
gb_array_init(p->loads, gb_heap_allocator());
|
||||||
|
gb_array_init(p->libraries, gb_heap_allocator());
|
||||||
|
gb_array_init(p->system_libraries, gb_heap_allocator());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2402,6 +2443,8 @@ void destroy_parser(Parser *p) {
|
|||||||
#endif
|
#endif
|
||||||
gb_array_free(p->files);
|
gb_array_free(p->files);
|
||||||
gb_array_free(p->loads);
|
gb_array_free(p->loads);
|
||||||
|
gb_array_free(p->libraries);
|
||||||
|
gb_array_free(p->system_libraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Returns true if it's added
|
// NOTE(bill): Returns true if it's added
|
||||||
@@ -2417,6 +2460,18 @@ b32 try_add_load_path(Parser *p, String import_file) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Returns true if it's added
|
||||||
|
b32 try_add_foreign_system_library_path(Parser *p, String import_file) {
|
||||||
|
gb_for_array(i, p->system_libraries) {
|
||||||
|
String import = p->system_libraries[i];
|
||||||
|
if (are_strings_equal(import, import_file)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gb_array_append(p->system_libraries, import_file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
gb_global Rune illegal_import_runes[] = {
|
gb_global Rune illegal_import_runes[] = {
|
||||||
'"', '\'', '`', ' ',
|
'"', '\'', '`', ' ',
|
||||||
'\\', // NOTE(bill): Disallow windows style filepaths
|
'\\', // NOTE(bill): Disallow windows style filepaths
|
||||||
@@ -2480,7 +2535,7 @@ void parse_file(Parser *p, AstFile *f) {
|
|||||||
String file_str = id->filepath.string;
|
String file_str = id->filepath.string;
|
||||||
|
|
||||||
if (!is_load_path_valid(file_str)) {
|
if (!is_load_path_valid(file_str)) {
|
||||||
ast_file_err(f, ast_node_token(node), "Invalid import path");
|
ast_file_err(f, ast_node_token(node), "Invalid `load` path");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2498,6 +2553,16 @@ void parse_file(Parser *p, AstFile *f) {
|
|||||||
if (!try_add_load_path(p, import_file)) {
|
if (!try_add_load_path(p, import_file)) {
|
||||||
gb_free(gb_heap_allocator(), import_file.text);
|
gb_free(gb_heap_allocator(), import_file.text);
|
||||||
}
|
}
|
||||||
|
} else if (node->kind == AstNode_ForeignSystemLibrary) {
|
||||||
|
auto *id = &node->ForeignSystemLibrary;
|
||||||
|
String file_str = id->filepath.string;
|
||||||
|
|
||||||
|
if (!is_load_path_valid(file_str)) {
|
||||||
|
ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_add_foreign_system_library_path(p, file_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user