mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Change casting syntax: cast(T)x transmute(T)x et al.
This commit is contained in:
@@ -9,14 +9,8 @@
|
|||||||
#import "sync.odin";
|
#import "sync.odin";
|
||||||
#import "utf8.odin";
|
#import "utf8.odin";
|
||||||
|
|
||||||
T :: struct { x, y: int };
|
|
||||||
thread_local t: T;
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
immutable using t := T{123, 321};
|
|
||||||
fmt.println(t);
|
|
||||||
|
|
||||||
|
|
||||||
// foo :: proc(x: ^i32) -> (int, int) {
|
// foo :: proc(x: ^i32) -> (int, int) {
|
||||||
// fmt.println("^int");
|
// fmt.println("^int");
|
||||||
// return 123, int(x^);
|
// return 123, int(x^);
|
||||||
|
|||||||
+6
-17
@@ -91,6 +91,10 @@ Type_Info :: union {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // NOTE(bill): only the ones that are needed (not all types)
|
||||||
|
// // This will be set by the compiler
|
||||||
|
// immutable __type_infos: []Type_Info;
|
||||||
|
|
||||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return nil;
|
return nil;
|
||||||
@@ -111,21 +115,6 @@ __debug_trap :: proc() #foreign "llvm.debugtrap"
|
|||||||
__trap :: proc() #foreign "llvm.trap"
|
__trap :: proc() #foreign "llvm.trap"
|
||||||
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
||||||
|
|
||||||
bit_reverse :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
|
||||||
bit_reverse :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
|
||||||
bit_reverse :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
|
|
||||||
|
|
||||||
byte_swap :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
|
|
||||||
byte_swap :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
|
|
||||||
byte_swap :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
|
||||||
|
|
||||||
fmuladd :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
|
||||||
fmuladd :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Allocator_Mode :: enum u8 {
|
Allocator_Mode :: enum u8 {
|
||||||
ALLOC,
|
ALLOC,
|
||||||
@@ -297,11 +286,11 @@ __string_eq :: proc(a, b: string) -> bool {
|
|||||||
if a.data == b.data {
|
if a.data == b.data {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return mem.compare(rawptr(a.data), rawptr(b.data), a.count) == 0;
|
return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, a.count) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_cmp :: proc(a, b: string) -> int {
|
__string_cmp :: proc(a, b: string) -> int {
|
||||||
return mem.compare(rawptr(a.data), rawptr(b.data), min(a.count, b.count));
|
return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, min(a.count, b.count));
|
||||||
}
|
}
|
||||||
|
|
||||||
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
||||||
|
|||||||
+92
-94
@@ -19,7 +19,7 @@ buffer_write :: proc(buf: ^Buffer, b: []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer_write_string :: proc(buf: ^Buffer, s: string) {
|
buffer_write_string :: proc(buf: ^Buffer, s: string) {
|
||||||
buffer_write(buf, []byte(s));
|
buffer_write(buf, cast([]byte)s);
|
||||||
}
|
}
|
||||||
buffer_write_byte :: proc(buf: ^Buffer, b: byte) {
|
buffer_write_byte :: proc(buf: ^Buffer, b: byte) {
|
||||||
if buf.length < buf.data.count {
|
if buf.length < buf.data.count {
|
||||||
@@ -29,7 +29,7 @@ buffer_write_byte :: proc(buf: ^Buffer, b: byte) {
|
|||||||
}
|
}
|
||||||
buffer_write_rune :: proc(buf: ^Buffer, r: rune) {
|
buffer_write_rune :: proc(buf: ^Buffer, r: rune) {
|
||||||
if r < utf8.RUNE_SELF {
|
if r < utf8.RUNE_SELF {
|
||||||
buffer_write_byte(buf, byte(r));
|
buffer_write_byte(buf, cast(byte)r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
|||||||
default:
|
default:
|
||||||
buffer_write_string(buf, if info.signed { give "i" } else { give "u"});
|
buffer_write_string(buf, if info.signed { give "i" } else { give "u"});
|
||||||
fi := Fmt_Info{buf = buf};
|
fi := Fmt_Info{buf = buf};
|
||||||
fmt_int(^fi, u64(8*info.size), false, 'd');
|
fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
|
||||||
}
|
}
|
||||||
|
|
||||||
case Float:
|
case Float:
|
||||||
@@ -142,7 +142,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
|||||||
if info.params == nil {
|
if info.params == nil {
|
||||||
buffer_write_string(buf, "()");
|
buffer_write_string(buf, "()");
|
||||||
} else {
|
} else {
|
||||||
count := (^Tuple)(info.params).fields.count;
|
count := (cast(^Tuple)info.params).fields.count;
|
||||||
if count == 1 { buffer_write_string(buf, "("); }
|
if count == 1 { buffer_write_string(buf, "("); }
|
||||||
buffer_write_type(buf, info.params);
|
buffer_write_type(buf, info.params);
|
||||||
if count == 1 { buffer_write_string(buf, ")"); }
|
if count == 1 { buffer_write_string(buf, ")"); }
|
||||||
@@ -170,7 +170,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
|||||||
case Array:
|
case Array:
|
||||||
buffer_write_string(buf, "[");
|
buffer_write_string(buf, "[");
|
||||||
fi := Fmt_Info{buf = buf};
|
fi := Fmt_Info{buf = buf};
|
||||||
fmt_int(^fi, u64(info.count), false, 'd');
|
fmt_int(^fi, cast(u64)info.count, false, 'd');
|
||||||
buffer_write_string(buf, "]");
|
buffer_write_string(buf, "]");
|
||||||
buffer_write_type(buf, info.elem);
|
buffer_write_type(buf, info.elem);
|
||||||
case Slice:
|
case Slice:
|
||||||
@@ -180,7 +180,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
|||||||
case Vector:
|
case Vector:
|
||||||
buffer_write_string(buf, "[vector ");
|
buffer_write_string(buf, "[vector ");
|
||||||
fi := Fmt_Info{buf = buf};
|
fi := Fmt_Info{buf = buf};
|
||||||
fmt_int(^fi, u64(info.count), false, 'd');
|
fmt_int(^fi, cast(u64)info.count, false, 'd');
|
||||||
buffer_write_string(buf, "]");
|
buffer_write_string(buf, "]");
|
||||||
buffer_write_type(buf, info.elem);
|
buffer_write_type(buf, info.elem);
|
||||||
|
|
||||||
@@ -221,7 +221,6 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
|
|||||||
buffer_write_string(buf, "enum ");
|
buffer_write_string(buf, "enum ");
|
||||||
buffer_write_type(buf, info.base);
|
buffer_write_type(buf, info.base);
|
||||||
buffer_write_string(buf, " {}");
|
buffer_write_string(buf, " {}");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,14 +306,14 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
|
|||||||
|
|
||||||
i := 0;
|
i := 0;
|
||||||
for _ : offset..<s.count {
|
for _ : offset..<s.count {
|
||||||
c := rune(s[offset]);
|
c := cast(rune)s[offset];
|
||||||
if !is_digit(c) {
|
if !is_digit(c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
result *= 10;
|
result *= 10;
|
||||||
result += int(c - '0');
|
result += cast(int)(c - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, offset, i != 0;
|
return result, offset, i != 0;
|
||||||
@@ -361,14 +360,14 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) {
|
|||||||
arg.type_info = type_info_base(arg.type_info);
|
arg.type_info = type_info_base(arg.type_info);
|
||||||
match type i : arg {
|
match type i : arg {
|
||||||
case int: num = i;
|
case int: num = i;
|
||||||
case i8: num = int(i);
|
case i8: num = cast(int)i;
|
||||||
case i16: num = int(i);
|
case i16: num = cast(int)i;
|
||||||
case i32: num = int(i);
|
case i32: num = cast(int)i;
|
||||||
case i64: num = int(i);
|
case i64: num = cast(int)i;
|
||||||
case u8: num = int(i);
|
case u8: num = cast(int)i;
|
||||||
case u16: num = int(i);
|
case u16: num = cast(int)i;
|
||||||
case u32: num = int(i);
|
case u32: num = cast(int)i;
|
||||||
case u64: num = int(i);
|
case u64: num = cast(int)i;
|
||||||
default:
|
default:
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
@@ -421,7 +420,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
|
fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) {
|
||||||
negative := signed && i64(u) < 0;
|
negative := signed && cast(i64)u < 0;
|
||||||
if negative {
|
if negative {
|
||||||
u = -u;
|
u = -u;
|
||||||
}
|
}
|
||||||
@@ -461,7 +460,7 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri
|
|||||||
panic("fmt_integer: unknown base, whoops");
|
panic("fmt_integer: unknown base, whoops");
|
||||||
}
|
}
|
||||||
|
|
||||||
while b := u64(base); u >= b {
|
while b := cast(u64)base; u >= b {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
next := u / b;
|
next := u / b;
|
||||||
buf[i] = digits[u%b];
|
buf[i] = digits[u%b];
|
||||||
@@ -504,7 +503,7 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri
|
|||||||
if !fi.width_set || fi.width == 0 {
|
if !fi.width_set || fi.width == 0 {
|
||||||
buffer_write(fi.buf, buf[i:]);
|
buffer_write(fi.buf, buf[i:]);
|
||||||
} else {
|
} else {
|
||||||
width := fi.width - utf8.rune_count(string(buf[i:]));
|
width := fi.width - utf8.rune_count(cast(string)buf[i:]);
|
||||||
if fi.minus {
|
if fi.minus {
|
||||||
// Right pad
|
// Right pad
|
||||||
buffer_write(fi.buf, buf[i:]);
|
buffer_write(fi.buf, buf[i:]);
|
||||||
@@ -533,9 +532,9 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) {
|
|||||||
case 'd': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER);
|
case 'd': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER);
|
||||||
case 'x': fmt_integer(fi, u, 16, signed, __DIGITS_LOWER);
|
case 'x': fmt_integer(fi, u, 16, signed, __DIGITS_LOWER);
|
||||||
case 'X': fmt_integer(fi, u, 16, signed, __DIGITS_UPPER);
|
case 'X': fmt_integer(fi, u, 16, signed, __DIGITS_UPPER);
|
||||||
case 'c': fmt_rune(fi, rune(u));
|
case 'c': fmt_rune(fi, cast(rune)u);
|
||||||
case 'U':
|
case 'U':
|
||||||
r := rune(u);
|
r := cast(rune)u;
|
||||||
if r < 0 || r > utf8.MAX_RUNE {
|
if r < 0 || r > utf8.MAX_RUNE {
|
||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
} else {
|
} else {
|
||||||
@@ -566,24 +565,24 @@ __TEN_TO_19TH :: 1000000000000000000;
|
|||||||
__ddmulthi :: proc(ol: f64, xh, yh: f64) -> f64 {
|
__ddmulthi :: proc(ol: f64, xh, yh: f64) -> f64 {
|
||||||
bt: i64;
|
bt: i64;
|
||||||
oh := xh * yh;
|
oh := xh * yh;
|
||||||
bt = transmute(i64, xh);
|
bt = transmute(i64)xh;
|
||||||
bt &= i64(~u64(0)<<27);
|
bt &= cast(i64)(~cast(u64)0<<27);
|
||||||
ahi := transmute(f64, bt);
|
ahi := transmute(f64)bt;
|
||||||
alo := xh-ahi;
|
alo := xh-ahi;
|
||||||
bt = transmute(i64, yh);
|
bt = transmute(i64)yh;
|
||||||
bt &= i64(~u64(0)<<27);
|
bt &= cast(i64)(~cast(u64)0<<27);
|
||||||
bhi := transmute(f64, bt);
|
bhi := transmute(f64)bt;
|
||||||
blo := yh-bhi;
|
blo := yh-bhi;
|
||||||
return ((ahi*bhi-oh)+ahi*blo+alo*bhi)+alo*blo;
|
return ((ahi*bhi-oh)+ahi*blo+alo*bhi)+alo*blo;
|
||||||
}
|
}
|
||||||
|
|
||||||
__ddtoi64 :: proc(xh, xl: f64) -> i64 {
|
__ddtoi64 :: proc(xh, xl: f64) -> i64 {
|
||||||
ob := i64(xh);
|
ob := cast(i64)xh;
|
||||||
vh := f64(ob);
|
vh := cast(f64)ob;
|
||||||
ahi := xh-vh;
|
ahi := xh-vh;
|
||||||
t := ahi-xh;
|
t := ahi-xh;
|
||||||
alo := (xh-(ahi-t)) - (vh+t);
|
alo := (xh-(ahi-t)) - (vh+t);
|
||||||
ob += i64(ahi+alo+xl);
|
ob += cast(i64)(ahi+alo+xl);
|
||||||
return ob;
|
return ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,9 +669,9 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
e, tens: i32;
|
e, tens: i32;
|
||||||
d: f64 = val;
|
d: f64 = val;
|
||||||
|
|
||||||
bits := transmute(i64, d);
|
bits := transmute(i64)d;
|
||||||
expo := i32(bits>>52 & 2047);
|
expo := cast(i32)(bits>>52 & 2047);
|
||||||
neg := i32(bits>>63) != 0;
|
neg := cast(i32)(bits>>63) != 0;
|
||||||
if neg {
|
if neg {
|
||||||
d = -d;
|
d = -d;
|
||||||
}
|
}
|
||||||
@@ -692,7 +691,7 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
if bits<<1 == 0 {
|
if bits<<1 == 0 {
|
||||||
decimal_pos^ = 1;
|
decimal_pos^ = 1;
|
||||||
out[0] = '0';
|
out[0] = '0';
|
||||||
start^ = string(out[:1]);
|
start^ = cast(string)out[:1];
|
||||||
return neg;
|
return neg;
|
||||||
}
|
}
|
||||||
// find the right expo for denormals
|
// find the right expo for denormals
|
||||||
@@ -721,7 +720,7 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
bits = __ddtoi64(ph, pl);
|
bits = __ddtoi64(ph, pl);
|
||||||
|
|
||||||
// check if we undershot
|
// check if we undershot
|
||||||
if f64(bits) >= __TEN_TO_19TH {
|
if cast(f64)bits >= __TEN_TO_19TH {
|
||||||
tens += 1;
|
tens += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,10 +736,10 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
if frac_digits < 24 {
|
if frac_digits < 24 {
|
||||||
skip := false;
|
skip := false;
|
||||||
dg: u32 = 1;
|
dg: u32 = 1;
|
||||||
if u64(bits) >= __powten[9] {
|
if cast(u64)bits >= __powten[9] {
|
||||||
dg = 10;
|
dg = 10;
|
||||||
}
|
}
|
||||||
while u64(bits) >= __powten[dg] {
|
while cast(u64)bits >= __powten[dg] {
|
||||||
dg += 1;
|
dg += 1;
|
||||||
if dg == 20 {
|
if dg == 20 {
|
||||||
skip = true;
|
skip = true;
|
||||||
@@ -751,14 +750,14 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
if (!skip) {
|
if (!skip) {
|
||||||
r: u64;
|
r: u64;
|
||||||
// add 0.5 at the right position and round
|
// add 0.5 at the right position and round
|
||||||
e = i32(dg) - frac_digits;
|
e = cast(i32)dg - frac_digits;
|
||||||
if u32(e) < 24 {
|
if cast(u32)e < 24 {
|
||||||
r = __powten[e];
|
r = __powten[e];
|
||||||
bits += i64(r/2);
|
bits += cast(i64)(r/2);
|
||||||
if u64(bits) >= __powten[dg] {
|
if cast(u64)bits >= __powten[dg] {
|
||||||
tens += 1;
|
tens += 1;
|
||||||
}
|
}
|
||||||
bits /= i64(r);
|
bits /= cast(i64)(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -777,11 +776,11 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
bits /= 1000;
|
bits /= 1000;
|
||||||
}
|
}
|
||||||
if !skip {
|
if !skip {
|
||||||
n := u32(bits);
|
n := cast(u32)bits;
|
||||||
while n%1000 == 0 {
|
while n%1000 == 0 {
|
||||||
n /= 1000;
|
n /= 1000;
|
||||||
}
|
}
|
||||||
bits = i64(n);
|
bits = cast(i64)n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,15 +792,15 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
o := outp-8;
|
o := outp-8;
|
||||||
// do the conversion in chunks of u32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
|
// do the conversion in chunks of u32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
|
||||||
if bits >= 100000000 {
|
if bits >= 100000000 {
|
||||||
n = u32(bits%100000000);
|
n = cast(u32)(bits%100000000);
|
||||||
bits /= 100000000;
|
bits /= 100000000;
|
||||||
} else {
|
} else {
|
||||||
n = u32(bits);
|
n = cast(u32)bits;
|
||||||
bits = 0;
|
bits = 0;
|
||||||
}
|
}
|
||||||
while n != 0 {
|
while n != 0 {
|
||||||
outp -= 2;
|
outp -= 2;
|
||||||
(^u16)(outp)^ = (^u16)(^__digitpair[(n%100)*2])^;
|
(cast(^u16)outp)^ = (cast(^u16)^__digitpair[(n%100)*2])^;
|
||||||
n /= 100;
|
n /= 100;
|
||||||
e += 2;
|
e += 2;
|
||||||
}
|
}
|
||||||
@@ -820,7 +819,7 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
|
|||||||
}
|
}
|
||||||
|
|
||||||
decimal_pos^ = tens;
|
decimal_pos^ = tens;
|
||||||
start^ = string(slice_ptr(outp, e));
|
start^ = cast(string)slice_ptr(outp, e);
|
||||||
return neg;
|
return neg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,18 +838,18 @@ generic_ftoa :: proc(buf: []byte, val: f64, verb: rune, prec, bit_size: int) ->
|
|||||||
flt: ^Float_Info;
|
flt: ^Float_Info;
|
||||||
match bit_size {
|
match bit_size {
|
||||||
case 32:
|
case 32:
|
||||||
bits = u64(transmute(u32, f32(val)));
|
bits = cast(u64)transmute(u32)cast(f32)val;
|
||||||
flt = ^f32info;
|
flt = ^f32info;
|
||||||
case 64:
|
case 64:
|
||||||
bits = u64(val);
|
bits = cast(u64)val;
|
||||||
flt = ^f64info;
|
flt = ^f64info;
|
||||||
default:
|
default:
|
||||||
panic("illegal float bit_size");
|
panic("illegal float bit_size");
|
||||||
}
|
}
|
||||||
|
|
||||||
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
||||||
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||||
mant := bits & (u64(1)<<flt.mantbits - 1);
|
mant := bits & (cast(u64)1<<flt.mantbits - 1);
|
||||||
|
|
||||||
match exp {
|
match exp {
|
||||||
case 1<<flt.expbits-1:
|
case 1<<flt.expbits-1:
|
||||||
@@ -860,13 +859,13 @@ generic_ftoa :: proc(buf: []byte, val: f64, verb: rune, prec, bit_size: int) ->
|
|||||||
case neg: s = "-Inf";
|
case neg: s = "-Inf";
|
||||||
default: s = "+Inf";
|
default: s = "+Inf";
|
||||||
}
|
}
|
||||||
copy(buf, []byte(s));
|
copy(buf, cast([]byte)s);
|
||||||
return buf[:s.count];
|
return buf[:s.count];
|
||||||
|
|
||||||
case 0: // denormalized
|
case 0: // denormalized
|
||||||
exp+=1;
|
exp+=1;
|
||||||
default: // add implicit top bit
|
default: // add implicit top bit
|
||||||
mant |= u64(1)<<flt.mantbits;
|
mant |= cast(u64)1<<flt.mantbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -924,7 +923,7 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
|||||||
fmt_bad_verb(fi, verb);
|
fmt_bad_verb(fi, verb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
u := u64(uint(p));
|
u := cast(u64)cast(uint)p;
|
||||||
if !fi.hash || verb == 'v' {
|
if !fi.hash || verb == 'v' {
|
||||||
buffer_write_string(fi.buf, "0x");
|
buffer_write_string(fi.buf, "0x");
|
||||||
}
|
}
|
||||||
@@ -952,18 +951,18 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
ok := false;
|
ok := false;
|
||||||
a := any{type_info_base(e.base), v.data};
|
a := any{type_info_base(e.base), v.data};
|
||||||
match type v : a {
|
match type v : a {
|
||||||
case i8: i = i64(v);
|
case i8: i = cast(i64)v;
|
||||||
case i16: i = i64(v);
|
case i16: i = cast(i64)v;
|
||||||
case i32: i = i64(v);
|
case i32: i = cast(i64)v;
|
||||||
case i64: i = i64(v);
|
case i64: i = cast(i64)v;
|
||||||
case int: i = i64(v);
|
case int: i = cast(i64)v;
|
||||||
case u8: i = i64(v);
|
case u8: i = cast(i64)v;
|
||||||
case u16: i = i64(v);
|
case u16: i = cast(i64)v;
|
||||||
case u32: i = i64(v);
|
case u32: i = cast(i64)v;
|
||||||
case u64: i = i64(v);
|
case u64: i = cast(i64)v;
|
||||||
case uint: i = i64(v);
|
case uint: i = cast(i64)v;
|
||||||
case f32: f = f64(v);
|
case f32: f = cast(f64)v;
|
||||||
case f64: f = f64(v);
|
case f64: f = cast(f64)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_type_integer(e.base) {
|
if is_type_integer(e.base) {
|
||||||
@@ -1017,10 +1016,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
buffer_write_string(fi.buf, ", ");
|
buffer_write_string(fi.buf, ", ");
|
||||||
}
|
}
|
||||||
buffer_write_string(fi.buf, f.name);
|
buffer_write_string(fi.buf, f.name);
|
||||||
// bprint_any(fi.buf, f.offset);
|
|
||||||
buffer_write_string(fi.buf, " = ");
|
buffer_write_string(fi.buf, " = ");
|
||||||
data := (^byte)(v.data) + f.offset;
|
data := cast(^byte)v.data + f.offset;
|
||||||
fmt_arg(fi, any{f.type_info, rawptr(data)}, 'v');
|
fmt_arg(fi, any{f.type_info, cast(rawptr)data}, 'v');
|
||||||
}
|
}
|
||||||
buffer_write_byte(fi.buf, '}');
|
buffer_write_byte(fi.buf, '}');
|
||||||
|
|
||||||
@@ -1035,15 +1033,15 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
|
|
||||||
case Pointer:
|
case Pointer:
|
||||||
if v.type_info == type_info(^Type_Info) {
|
if v.type_info == type_info(^Type_Info) {
|
||||||
buffer_write_type(fi.buf, (^^Type_Info)(v.data)^);
|
buffer_write_type(fi.buf, (cast(^^Type_Info)v.data)^);
|
||||||
} else {
|
} else {
|
||||||
fmt_pointer(fi, (^rawptr)(v.data)^, verb);
|
fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Maybe:
|
case Maybe:
|
||||||
// TODO(bill): Correct verbs for Maybe types?
|
// TODO(bill): Correct verbs for Maybe types?
|
||||||
size := mem.size_of_type_info(info.elem);
|
size := mem.size_of_type_info(info.elem);
|
||||||
data := slice_ptr((^byte)(v.data), size+1);
|
data := slice_ptr(cast(^byte)v.data, size+1);
|
||||||
if data[size] != 0 {
|
if data[size] != 0 {
|
||||||
fmt_arg(fi, any{info.elem, v.data}, verb);
|
fmt_arg(fi, any{info.elem, v.data}, verb);
|
||||||
} else {
|
} else {
|
||||||
@@ -1062,8 +1060,8 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer_write_string(fi.buf, ", ");
|
buffer_write_string(fi.buf, ", ");
|
||||||
}
|
}
|
||||||
data := (^byte)(v.data) + i*info.elem_size;
|
data := cast(^byte)v.data + i*info.elem_size;
|
||||||
fmt_arg(fi, any{info.elem, rawptr(data)}, 'v');
|
fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v');
|
||||||
}
|
}
|
||||||
|
|
||||||
case Slice:
|
case Slice:
|
||||||
@@ -1074,13 +1072,13 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
|
|
||||||
buffer_write_byte(fi.buf, '[');
|
buffer_write_byte(fi.buf, '[');
|
||||||
defer buffer_write_byte(fi.buf, ']');
|
defer buffer_write_byte(fi.buf, ']');
|
||||||
slice := (^[]byte)(v.data);
|
slice := cast(^[]byte)v.data;
|
||||||
for i : 0..<slice.count {
|
for i : 0..<slice.count {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer_write_string(fi.buf, ", ");
|
buffer_write_string(fi.buf, ", ");
|
||||||
}
|
}
|
||||||
data := slice.data + i*info.elem_size;
|
data := slice.data + i*info.elem_size;
|
||||||
fmt_arg(fi, any{info.elem, rawptr(data)}, 'v');
|
fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v');
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vector:
|
case Vector:
|
||||||
@@ -1106,8 +1104,8 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
buffer_write_string(fi.buf, ", ");
|
buffer_write_string(fi.buf, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
data := (^byte)(v.data) + i*info.elem_size;
|
data := cast(^byte)v.data + i*info.elem_size;
|
||||||
fmt_value(fi, any{info.elem, rawptr(data)}, 'v');
|
fmt_value(fi, any{info.elem, cast(rawptr)data}, 'v');
|
||||||
}
|
}
|
||||||
|
|
||||||
case Struct:
|
case Struct:
|
||||||
@@ -1120,9 +1118,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
}
|
}
|
||||||
buffer_write_string(fi.buf, f.name);
|
buffer_write_string(fi.buf, f.name);
|
||||||
buffer_write_string(fi.buf, " = ");
|
buffer_write_string(fi.buf, " = ");
|
||||||
data := (^byte)(v.data) + f.offset;
|
data := cast(^byte)v.data + f.offset;
|
||||||
ti := f.type_info;
|
ti := f.type_info;
|
||||||
fmt_value(fi, any{ti, rawptr(data)}, 'v');
|
fmt_value(fi, any{ti, cast(rawptr)data}, 'v');
|
||||||
}
|
}
|
||||||
|
|
||||||
case Union:
|
case Union:
|
||||||
@@ -1136,7 +1134,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
|||||||
case Procedure:
|
case Procedure:
|
||||||
buffer_write_type(fi.buf, v.type_info);
|
buffer_write_type(fi.buf, v.type_info);
|
||||||
buffer_write_string(fi.buf, " @ ");
|
buffer_write_string(fi.buf, " @ ");
|
||||||
fmt_pointer(fi, (^rawptr)(v.data)^, 'p');
|
fmt_pointer(fi, (cast(^rawptr)v.data)^, 'p');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1161,19 +1159,19 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
|||||||
base_arg.type_info = type_info_base(base_arg.type_info);
|
base_arg.type_info = type_info_base(base_arg.type_info);
|
||||||
match type a : base_arg {
|
match type a : base_arg {
|
||||||
case bool: fmt_bool(fi, a, verb);
|
case bool: fmt_bool(fi, a, verb);
|
||||||
case f32: fmt_float(fi, f64(a), 32, verb);
|
case f32: fmt_float(fi, cast(f64)a, 32, verb);
|
||||||
case f64: fmt_float(fi, a, 64, verb);
|
case f64: fmt_float(fi, a, 64, verb);
|
||||||
|
|
||||||
case int: fmt_int(fi, u64(a), true, verb);
|
case int: fmt_int(fi, cast(u64)a, true, verb);
|
||||||
case i8: fmt_int(fi, u64(a), true, verb);
|
case i8: fmt_int(fi, cast(u64)a, true, verb);
|
||||||
case i16: fmt_int(fi, u64(a), true, verb);
|
case i16: fmt_int(fi, cast(u64)a, true, verb);
|
||||||
case i32: fmt_int(fi, u64(a), true, verb);
|
case i32: fmt_int(fi, cast(u64)a, true, verb);
|
||||||
case i64: fmt_int(fi, u64(a), true, verb);
|
case i64: fmt_int(fi, cast(u64)a, true, verb);
|
||||||
case uint: fmt_int(fi, u64(a), false, verb);
|
case uint: fmt_int(fi, cast(u64)a, false, verb);
|
||||||
case u8: fmt_int(fi, u64(a), false, verb);
|
case u8: fmt_int(fi, cast(u64)a, false, verb);
|
||||||
case u16: fmt_int(fi, u64(a), false, verb);
|
case u16: fmt_int(fi, cast(u64)a, false, verb);
|
||||||
case u32: fmt_int(fi, u64(a), false, verb);
|
case u32: fmt_int(fi, cast(u64)a, false, verb);
|
||||||
case u64: fmt_int(fi, u64(a), false, verb);
|
case u64: fmt_int(fi, cast(u64)a, false, verb);
|
||||||
case string: fmt_string(fi, a, verb);
|
case string: fmt_string(fi, a, verb);
|
||||||
default: fmt_value(fi, arg, verb);
|
default: fmt_value(fi, arg, verb);
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-31
@@ -1,58 +1,58 @@
|
|||||||
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
crc32 :: proc(data: rawptr, len: int) -> u32 {
|
||||||
result := ~u32(0);
|
result := ~cast(u32)0;
|
||||||
s := slice_ptr((^u8)(data), len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
for i : 0..<len {
|
for i : 0..<len {
|
||||||
b := u32(s[i]);
|
b := cast(u32)s[i];
|
||||||
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
|
||||||
}
|
}
|
||||||
return ~result;
|
return ~result;
|
||||||
}
|
}
|
||||||
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
crc64 :: proc(data: rawptr, len: int) -> u64 {
|
||||||
result := ~u64(0);
|
result := ~cast(u64)0;
|
||||||
s := slice_ptr((^u8)(data), len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
for i : 0..<len {
|
for i : 0..<len {
|
||||||
b := u64(s[i]);
|
b := cast(u64)s[i];
|
||||||
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
|
||||||
}
|
}
|
||||||
return ~result;
|
return ~result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
fnv32 :: proc(data: rawptr, len: int) -> u32 {
|
||||||
s := slice_ptr((^u8)(data), len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h: u32 = 0x811c9dc5;
|
h: u32 = 0x811c9dc5;
|
||||||
for i : 0..<len {
|
for i : 0..<len {
|
||||||
h = (h * 0x01000193) ~ u32(s[i]);
|
h = (h * 0x01000193) ~ cast(u32)s[i];
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
fnv64 :: proc(data: rawptr, len: int) -> u64 {
|
||||||
s := slice_ptr((^u8)(data), len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h: u64 = 0xcbf29ce484222325;
|
h: u64 = 0xcbf29ce484222325;
|
||||||
for i : 0..<len {
|
for i : 0..<len {
|
||||||
h = (h * 0x100000001b3) ~ u64(s[i]);
|
h = (h * 0x100000001b3) ~ cast(u64)s[i];
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
fnv32a :: proc(data: rawptr, len: int) -> u32 {
|
||||||
s := slice_ptr((^u8)(data), len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h: u32 = 0x811c9dc5;
|
h: u32 = 0x811c9dc5;
|
||||||
for i : 0..<len {
|
for i : 0..<len {
|
||||||
h = (h ~ u32(s[i])) * 0x01000193;
|
h = (h ~ cast(u32)s[i]) * 0x01000193;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
fnv64a :: proc(data: rawptr, len: int) -> u64 {
|
||||||
s := slice_ptr((^u8)(data), len);
|
s := slice_ptr(cast(^u8)data, len);
|
||||||
|
|
||||||
h :u64 = 0xcbf29ce484222325;
|
h :u64 = 0xcbf29ce484222325;
|
||||||
for i : 0..<len {
|
for i : 0..<len {
|
||||||
h = (h ~ u64(s[i])) * 0x100000001b3;
|
h = (h ~ cast(u64)s[i]) * 0x100000001b3;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
@@ -65,10 +65,10 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
m :: 0xc6a4a7935bd1e995;
|
m :: 0xc6a4a7935bd1e995;
|
||||||
r :: 47;
|
r :: 47;
|
||||||
|
|
||||||
h: u64 = SEED ~ (u64(len) * m);
|
h: u64 = SEED ~ (cast(u64)len * m);
|
||||||
|
|
||||||
data := slice_ptr((^u64)(data_), len/size_of(u64));
|
data := slice_ptr(cast(^u64)data_, len/size_of(u64));
|
||||||
data2 := slice_ptr((^u8)(data_), len);
|
data2 := slice_ptr(cast(^u8)data_, len);
|
||||||
|
|
||||||
for i : 0 ..< data.count {
|
for i : 0 ..< data.count {
|
||||||
k := data[i];
|
k := data[i];
|
||||||
@@ -82,14 +82,14 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match len & 7 {
|
match len & 7 {
|
||||||
case 7: h ~= u64(data2[6]) << 48; fallthrough;
|
case 7: h ~= cast(u64)data2[6] << 48; fallthrough;
|
||||||
case 6: h ~= u64(data2[5]) << 40; fallthrough;
|
case 6: h ~= cast(u64)data2[5] << 40; fallthrough;
|
||||||
case 5: h ~= u64(data2[4]) << 32; fallthrough;
|
case 5: h ~= cast(u64)data2[4] << 32; fallthrough;
|
||||||
case 4: h ~= u64(data2[3]) << 24; fallthrough;
|
case 4: h ~= cast(u64)data2[3] << 24; fallthrough;
|
||||||
case 3: h ~= u64(data2[2]) << 16; fallthrough;
|
case 3: h ~= cast(u64)data2[2] << 16; fallthrough;
|
||||||
case 2: h ~= u64(data2[1]) << 8; fallthrough;
|
case 2: h ~= cast(u64)data2[1] << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h ~= u64(data2[0]);
|
h ~= cast(u64)data2[0];
|
||||||
h *= m;
|
h *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,10 +102,10 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
m :: 0x5bd1e995;
|
m :: 0x5bd1e995;
|
||||||
r :: 24;
|
r :: 24;
|
||||||
|
|
||||||
h1: u32 = u32(SEED) ~ u32(len);
|
h1: u32 = cast(u32)SEED ~ cast(u32)len;
|
||||||
h2: u32 = SEED >> 32;
|
h2: u32 = SEED >> 32;
|
||||||
|
|
||||||
data := slice_ptr((^u32)(data_), len/size_of(u32));
|
data := slice_ptr(cast(^u32)data_, len/size_of(u32));
|
||||||
|
|
||||||
i := 0;
|
i := 0;
|
||||||
while len >= 8 {
|
while len >= 8 {
|
||||||
@@ -138,13 +138,13 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
data8 := slice_ptr((^u8)(data.data+i), 3); // NOTE(bill): This is unsafe
|
data8 := slice_ptr(cast(^u8)(data.data+i), 3); // NOTE(bill): This is unsafe
|
||||||
|
|
||||||
match len {
|
match len {
|
||||||
case 3: h2 ~= u32(data8[2]) << 16; fallthrough;
|
case 3: h2 ~= cast(u32)data8[2] << 16; fallthrough;
|
||||||
case 2: h2 ~= u32(data8[1]) << 8; fallthrough;
|
case 2: h2 ~= cast(u32)data8[1] << 8; fallthrough;
|
||||||
case 1:
|
case 1:
|
||||||
h2 ~= u32(data8[0]);
|
h2 ~= cast(u32)data8[0];
|
||||||
h2 *= m;
|
h2 *= m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
|
|||||||
h2 ~= h1>>19;
|
h2 ~= h1>>19;
|
||||||
h2 *= m;
|
h2 *= m;
|
||||||
|
|
||||||
h := u64(h1)<<32 | u64(h2);
|
h := cast(u64)(h1)<<32 | cast(u64)(h2);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-7
@@ -42,14 +42,24 @@ lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
|
|||||||
sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
||||||
sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||||
|
|
||||||
|
bit_reverse :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
||||||
|
bit_reverse :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
||||||
|
bit_reverse :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
|
||||||
|
|
||||||
|
byte_swap :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
|
||||||
|
byte_swap :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
|
||||||
|
byte_swap :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
||||||
|
|
||||||
|
fmuladd :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
||||||
|
fmuladd :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||||
|
|
||||||
|
|
||||||
copy_sign :: proc(x, y: f32) -> f32 {
|
copy_sign :: proc(x, y: f32) -> f32 {
|
||||||
ix := transmute(u32, x);
|
ix := transmute(u32)x;
|
||||||
iy := transmute(u32, y);
|
iy := transmute(u32)y;
|
||||||
ix &= 0x7fffffff;
|
ix &= 0x7fffffff;
|
||||||
ix |= iy & 0x80000000;
|
ix |= iy & 0x80000000;
|
||||||
return transmute(f32, ix);
|
return transmute(f32)ix;
|
||||||
}
|
}
|
||||||
round :: proc(x: f32) -> f32 {
|
round :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
@@ -59,15 +69,15 @@ round :: proc(x: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
floor :: proc(x: f32) -> f32 {
|
floor :: proc(x: f32) -> f32 {
|
||||||
if x >= 0 {
|
if x >= 0 {
|
||||||
return f32(int(x));
|
return cast(f32)cast(int)x;
|
||||||
}
|
}
|
||||||
return f32(int(x-0.5));
|
return cast(f32)cast(int)(x-0.5);
|
||||||
}
|
}
|
||||||
ceil :: proc(x: f32) -> f32 {
|
ceil :: proc(x: f32) -> f32 {
|
||||||
if x < 0 {
|
if x < 0 {
|
||||||
return f32(int(x));
|
return cast(f32)cast(int)x;
|
||||||
}
|
}
|
||||||
return f32(int(x)+1);
|
return cast(f32)cast(int)(x+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
remainder32 :: proc(x, y: f32) -> f32 {
|
remainder32 :: proc(x, y: f32) -> f32 {
|
||||||
|
|||||||
+12
-12
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
|
||||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||||
llvm_memset_64bit(data, byte(value), len, 1, false);
|
llvm_memset_64bit(data, cast(byte)value, len, 1, false);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,8 +26,8 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "_
|
|||||||
}
|
}
|
||||||
|
|
||||||
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
|
||||||
a := slice_ptr((^byte)(dst), n);
|
a := slice_ptr(cast(^byte)dst, n);
|
||||||
b := slice_ptr((^byte)(src), n);
|
b := slice_ptr(cast(^byte)src, n);
|
||||||
for i : 0..<n {
|
for i : 0..<n {
|
||||||
match {
|
match {
|
||||||
case a[i] < b[i]:
|
case a[i] < b[i]:
|
||||||
@@ -56,13 +56,13 @@ is_power_of_two :: proc(x: int) -> bool {
|
|||||||
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
|
||||||
assert(is_power_of_two(align));
|
assert(is_power_of_two(align));
|
||||||
|
|
||||||
a := uint(align);
|
a := cast(uint)align;
|
||||||
p := uint(ptr);
|
p := cast(uint)ptr;
|
||||||
modulo := p & (a-1);
|
modulo := p & (a-1);
|
||||||
if modulo != 0 {
|
if modulo != 0 {
|
||||||
p += a - modulo;
|
p += a - modulo;
|
||||||
}
|
}
|
||||||
return rawptr(p);
|
return cast(rawptr)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -73,19 +73,19 @@ Allocation_Header :: struct {
|
|||||||
|
|
||||||
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
|
||||||
header.size = size;
|
header.size = size;
|
||||||
ptr := (^int)(header+1);
|
ptr := cast(^int)(header+1);
|
||||||
|
|
||||||
while i := 0; rawptr(ptr) < data {
|
while i := 0; cast(rawptr)ptr < data {
|
||||||
(ptr+i)^ = -1;
|
(ptr+i)^ = -1;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
|
||||||
p := (^int)(data);
|
p := cast(^int)data;
|
||||||
while (p-1)^ == -1 {
|
while (p-1)^ == -1 {
|
||||||
p = (p-1);
|
p = (p-1);
|
||||||
}
|
}
|
||||||
return (^Allocation_Header)(p)-1;
|
return cast(^Allocation_Header)p-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||||
using Allocator_Mode;
|
using Allocator_Mode;
|
||||||
arena := (^Arena)(allocator_data);
|
arena := cast(^Arena)allocator_data;
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOC:
|
case ALLOC:
|
||||||
@@ -235,7 +235,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
|||||||
return WORD_SIZE;
|
return WORD_SIZE;
|
||||||
case Vector:
|
case Vector:
|
||||||
size := size_of_type_info(info.elem);
|
size := size_of_type_info(info.elem);
|
||||||
count := int(max(prev_pow2(i64(info.count)), 1));
|
count := cast(int)max(prev_pow2(cast(i64)info.count), 1);
|
||||||
total := size * count;
|
total := size * count;
|
||||||
return clamp(total, 1, MAX_ALIGN);
|
return clamp(total, 1, MAX_ALIGN);
|
||||||
case Struct:
|
case Struct:
|
||||||
|
|||||||
+2
-2
@@ -30,7 +30,7 @@ GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
_libgl := win32.LoadLibraryA(string("opengl32.dll\x00").data);
|
_libgl := win32.LoadLibraryA((cast(string)"opengl32.dll\x00").data);
|
||||||
|
|
||||||
GetProcAddress :: proc(name: string) -> proc() #cc_c {
|
GetProcAddress :: proc(name: string) -> proc() #cc_c {
|
||||||
assert(name[name.count-1] == 0);
|
assert(name[name.count-1] == 0);
|
||||||
@@ -100,7 +100,7 @@ UniformMatrix4fv: proc(loc: i32, count: u32, transpose: i32, value: ^f32) #cc_c
|
|||||||
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
GetUniformLocation: proc(program: u32, name: ^byte) -> i32 #cc_c;
|
||||||
|
|
||||||
init :: proc() {
|
init :: proc() {
|
||||||
set_proc_address :: proc(p: rawptr, name: string) #inline { (^(proc() #cc_c))(p)^ = GetProcAddress(name); }
|
set_proc_address :: proc(p: rawptr, name: string) #inline { (cast(^(proc() #cc_c))p)^ = GetProcAddress(name); }
|
||||||
|
|
||||||
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
set_proc_address(^GenBuffers, "glGenBuffers\x00");
|
||||||
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00");
|
||||||
|
|||||||
+32
-32
@@ -73,7 +73,7 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
|||||||
access |= FILE_APPEND_DATA;
|
access |= FILE_APPEND_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
share_mode := u32(FILE_SHARE_READ|FILE_SHARE_WRITE);
|
share_mode := cast(u32)(FILE_SHARE_READ|FILE_SHARE_WRITE);
|
||||||
sa: ^SECURITY_ATTRIBUTES = nil;
|
sa: ^SECURITY_ATTRIBUTES = nil;
|
||||||
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
|
sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
|
||||||
if mode&O_CLOEXEC == 0 {
|
if mode&O_CLOEXEC == 0 {
|
||||||
@@ -95,38 +95,38 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf: [300]byte;
|
buf: [300]byte;
|
||||||
copy(buf[:], []byte(path));
|
copy(buf[:], cast([]byte)path);
|
||||||
|
|
||||||
handle := Handle(CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil));
|
handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
|
||||||
if handle != INVALID_HANDLE {
|
if handle != INVALID_HANDLE {
|
||||||
return handle, ERROR_NONE;
|
return handle, ERROR_NONE;
|
||||||
}
|
}
|
||||||
err := GetLastError();
|
err := GetLastError();
|
||||||
return INVALID_HANDLE, Errno(err);
|
return INVALID_HANDLE, cast(Errno)err;
|
||||||
}
|
}
|
||||||
|
|
||||||
close :: proc(fd: Handle) {
|
close :: proc(fd: Handle) {
|
||||||
win32.CloseHandle(win32.HANDLE(fd));
|
win32.CloseHandle(cast(win32.HANDLE)fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
bytes_written: i32;
|
bytes_written: i32;
|
||||||
e := win32.WriteFile(win32.HANDLE(fd), data.data, i32(data.count), ^bytes_written, nil);
|
e := win32.WriteFile(cast(win32.HANDLE)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
|
||||||
if e == win32.FALSE {
|
if e == win32.FALSE {
|
||||||
err := win32.GetLastError();
|
err := win32.GetLastError();
|
||||||
return 0, Errno(err);
|
return 0, cast(Errno)err;
|
||||||
}
|
}
|
||||||
return int(bytes_written), ERROR_NONE;
|
return cast(int)bytes_written, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||||
bytes_read: i32;
|
bytes_read: i32;
|
||||||
e := win32.ReadFile(win32.HANDLE(fd), data.data, u32(data.count), ^bytes_read, nil);
|
e := win32.ReadFile(cast(win32.HANDLE)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
|
||||||
if e == win32.FALSE {
|
if e == win32.FALSE {
|
||||||
err := win32.GetLastError();
|
err := win32.GetLastError();
|
||||||
return 0, Errno(err);
|
return 0, cast(Errno)err;
|
||||||
}
|
}
|
||||||
return int(bytes_read), ERROR_NONE;
|
return cast(int)bytes_read, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||||
@@ -137,18 +137,18 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
|||||||
case 1: w = FILE_CURRENT;
|
case 1: w = FILE_CURRENT;
|
||||||
case 2: w = FILE_END;
|
case 2: w = FILE_END;
|
||||||
}
|
}
|
||||||
hi := i32(offset>>32);
|
hi := cast(i32)(offset>>32);
|
||||||
lo := i32(offset);
|
lo := cast(i32)(offset);
|
||||||
ft := GetFileType(HANDLE(fd));
|
ft := GetFileType(cast(HANDLE)fd);
|
||||||
if ft == FILE_TYPE_PIPE {
|
if ft == FILE_TYPE_PIPE {
|
||||||
return 0, ERROR_FILE_IS_PIPE;
|
return 0, ERROR_FILE_IS_PIPE;
|
||||||
}
|
}
|
||||||
dw_ptr := SetFilePointer(HANDLE(fd), lo, ^hi, w);
|
dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
|
||||||
if dw_ptr == INVALID_SET_FILE_POINTER {
|
if dw_ptr == INVALID_SET_FILE_POINTER {
|
||||||
err := GetLastError();
|
err := GetLastError();
|
||||||
return 0, Errno(err);
|
return 0, cast(Errno)err;
|
||||||
}
|
}
|
||||||
return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
|
return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -159,9 +159,9 @@ stderr := get_std_handle(win32.STD_ERROR_HANDLE);
|
|||||||
|
|
||||||
|
|
||||||
get_std_handle :: proc(h: int) -> Handle {
|
get_std_handle :: proc(h: int) -> Handle {
|
||||||
fd := win32.GetStdHandle(i32(h));
|
fd := win32.GetStdHandle(cast(i32)h);
|
||||||
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
|
||||||
return Handle(fd);
|
return cast(Handle)fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -171,9 +171,9 @@ get_std_handle :: proc(h: int) -> Handle {
|
|||||||
|
|
||||||
last_write_time :: proc(fd: Handle) -> File_Time {
|
last_write_time :: proc(fd: Handle) -> File_Time {
|
||||||
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
file_info: win32.BY_HANDLE_FILE_INFORMATION;
|
||||||
win32.GetFileInformationByHandle(win32.HANDLE(fd), ^file_info);
|
win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
|
||||||
lo := File_Time(file_info.last_write_time.lo);
|
lo := cast(File_Time)file_info.last_write_time.lo;
|
||||||
hi := File_Time(file_info.last_write_time.hi);
|
hi := cast(File_Time)file_info.last_write_time.hi;
|
||||||
return lo | hi << 32;
|
return lo | hi << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,14 +184,14 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
|||||||
|
|
||||||
assert(buf.count > name.count);
|
assert(buf.count > name.count);
|
||||||
|
|
||||||
copy(buf[:], []byte(name));
|
copy(buf[:], cast([]byte)name);
|
||||||
|
|
||||||
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
|
||||||
last_write_time = data.last_write_time;
|
last_write_time = data.last_write_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
l := File_Time(last_write_time.lo);
|
l := cast(File_Time)last_write_time.lo;
|
||||||
h := File_Time(last_write_time.hi);
|
h := cast(File_Time)last_write_time.hi;
|
||||||
return l | h << 32;
|
return l | h << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
|||||||
|
|
||||||
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
||||||
buf: [300]byte;
|
buf: [300]byte;
|
||||||
copy(buf[:], []byte(name));
|
copy(buf[:], cast([]byte)name);
|
||||||
|
|
||||||
fd, err := open(name, O_RDONLY, 0);
|
fd, err := open(name, O_RDONLY, 0);
|
||||||
if err != ERROR_NONE {
|
if err != ERROR_NONE {
|
||||||
@@ -210,7 +210,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
|||||||
defer close(fd);
|
defer close(fd);
|
||||||
|
|
||||||
length: i64;
|
length: i64;
|
||||||
file_size_ok := win32.GetFileSizeEx(win32.HANDLE(fd), ^length) != 0;
|
file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
|
||||||
if !file_size_ok {
|
if !file_size_ok {
|
||||||
return nil, false;
|
return nil, false;
|
||||||
}
|
}
|
||||||
@@ -228,18 +228,18 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
|
|||||||
to_read: u32;
|
to_read: u32;
|
||||||
MAX :: 1<<32-1;
|
MAX :: 1<<32-1;
|
||||||
if remaining <= MAX {
|
if remaining <= MAX {
|
||||||
to_read = u32(remaining);
|
to_read = cast(u32)remaining;
|
||||||
} else {
|
} else {
|
||||||
to_read = MAX;
|
to_read = MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
win32.ReadFile(win32.HANDLE(fd), ^data[total_read], to_read, ^single_read_length, nil);
|
win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
|
||||||
if single_read_length <= 0 {
|
if single_read_length <= 0 {
|
||||||
free(data.data);
|
free(data.data);
|
||||||
return nil, false;
|
return nil, false;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_read += i64(single_read_length);
|
total_read += cast(i64)single_read_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, true;
|
return data, true;
|
||||||
@@ -259,14 +259,14 @@ heap_free :: proc(ptr: rawptr) {
|
|||||||
|
|
||||||
|
|
||||||
exit :: proc(code: int) {
|
exit :: proc(code: int) {
|
||||||
win32.ExitProcess(u32(code));
|
win32.ExitProcess(cast(u32)code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc() -> int {
|
current_thread_id :: proc() -> int {
|
||||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||||
return int(GetCurrentThreadId());
|
return cast(int)GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -13,7 +13,7 @@ Mutex :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current_thread_id :: proc() -> i32 {
|
current_thread_id :: proc() -> i32 {
|
||||||
return i32(win32.GetCurrentThreadId());
|
return cast(i32)win32.GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_init :: proc(s: ^Semaphore) {
|
semaphore_init :: proc(s: ^Semaphore) {
|
||||||
@@ -25,7 +25,7 @@ semaphore_destroy :: proc(s: ^Semaphore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||||
win32.ReleaseSemaphore(s.handle, i32(count), nil);
|
win32.ReleaseSemaphore(s.handle, cast(i32)count, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ BOOL :: i32;
|
|||||||
WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
|
WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
|
||||||
|
|
||||||
|
|
||||||
INVALID_HANDLE_VALUE :: HANDLE(~int(0));
|
INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0);
|
||||||
|
|
||||||
FALSE: BOOL : 0;
|
FALSE: BOOL : 0;
|
||||||
TRUE: BOOL : 1;
|
TRUE: BOOL : 1;
|
||||||
@@ -46,7 +46,7 @@ WM_KEYUP :: 0x0101;
|
|||||||
|
|
||||||
PM_REMOVE :: 1;
|
PM_REMOVE :: 1;
|
||||||
|
|
||||||
COLOR_BACKGROUND :: HBRUSH(int(1));
|
COLOR_BACKGROUND :: cast(HBRUSH)(cast(int)1);
|
||||||
BLACK_BRUSH :: 4;
|
BLACK_BRUSH :: 4;
|
||||||
|
|
||||||
SM_CXSCREEN :: 0;
|
SM_CXSCREEN :: 0;
|
||||||
@@ -233,7 +233,7 @@ FILE_TYPE_DISK :: 0x0001;
|
|||||||
FILE_TYPE_CHAR :: 0x0002;
|
FILE_TYPE_CHAR :: 0x0002;
|
||||||
FILE_TYPE_PIPE :: 0x0003;
|
FILE_TYPE_PIPE :: 0x0003;
|
||||||
|
|
||||||
INVALID_SET_FILE_POINTER :: ~u32(0);
|
INVALID_SET_FILE_POINTER :: ~cast(u32)0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -402,7 +402,7 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
|
|||||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||||
|
|
||||||
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(i32(key)) < 0; }
|
is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; }
|
||||||
|
|
||||||
Key_Code :: enum i32 {
|
Key_Code :: enum i32 {
|
||||||
LBUTTON = 0x01,
|
LBUTTON = 0x01,
|
||||||
|
|||||||
+20
-20
@@ -1,7 +1,7 @@
|
|||||||
RUNE_ERROR :: '\ufffd';
|
RUNE_ERROR :: '\ufffd';
|
||||||
RUNE_SELF :: 0x80;
|
RUNE_SELF :: 0x80;
|
||||||
RUNE_BOM :: 0xfeff;
|
RUNE_BOM :: 0xfeff;
|
||||||
RUNE_EOF :: ~rune(0);
|
RUNE_EOF :: ~cast(rune)0;
|
||||||
MAX_RUNE :: '\U0010ffff';
|
MAX_RUNE :: '\U0010ffff';
|
||||||
UTF_MAX :: 4;
|
UTF_MAX :: 4;
|
||||||
|
|
||||||
@@ -40,15 +40,15 @@ accept_sizes := [256]byte{
|
|||||||
|
|
||||||
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||||
buf: [4]byte;
|
buf: [4]byte;
|
||||||
i := u32(r);
|
i := cast(u32)r;
|
||||||
mask: byte : 0x3f;
|
mask: byte : 0x3f;
|
||||||
if i <= 1<<7-1 {
|
if i <= 1<<7-1 {
|
||||||
buf[0] = byte(r);
|
buf[0] = cast(byte)r;
|
||||||
return buf, 1;
|
return buf, 1;
|
||||||
}
|
}
|
||||||
if i <= 1<<11-1 {
|
if i <= 1<<11-1 {
|
||||||
buf[0] = 0xc0 | byte(r>>6);
|
buf[0] = 0xc0 | cast(byte)(r>>6);
|
||||||
buf[1] = 0x80 | byte(r) & mask;
|
buf[1] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 2;
|
return buf, 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,16 +59,16 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if i <= 1<<16-1 {
|
if i <= 1<<16-1 {
|
||||||
buf[0] = 0xe0 | byte(r>>12);
|
buf[0] = 0xe0 | cast(byte)(r>>12);
|
||||||
buf[1] = 0x80 | byte(r>>6) & mask;
|
buf[1] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[2] = 0x80 | byte(r) & mask;
|
buf[2] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 3;
|
return buf, 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = 0xf0 | byte(r>>18);
|
buf[0] = 0xf0 | cast(byte)(r>>18);
|
||||||
buf[1] = 0x80 | byte(r>>12) & mask;
|
buf[1] = 0x80 | cast(byte)(r>>12) & mask;
|
||||||
buf[2] = 0x80 | byte(r>>6) & mask;
|
buf[2] = 0x80 | cast(byte)(r>>6) & mask;
|
||||||
buf[3] = 0x80 | byte(r) & mask;
|
buf[3] = 0x80 | cast(byte)r & mask;
|
||||||
return buf, 4;
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,12 +80,12 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
|||||||
b0 := s[0];
|
b0 := s[0];
|
||||||
x := accept_sizes[b0];
|
x := accept_sizes[b0];
|
||||||
if x >= 0xf0 {
|
if x >= 0xf0 {
|
||||||
mask := (rune(x) << 31) >> 31; // all zeros or all ones
|
mask := (cast(rune)x << 31) >> 31; // all zeros or all ones
|
||||||
return rune(b0) &~ mask | RUNE_ERROR&mask, 1;
|
return cast(rune)b0 &~ mask | RUNE_ERROR&mask, 1;
|
||||||
}
|
}
|
||||||
size := x & 7;
|
size := x & 7;
|
||||||
ar := accept_ranges[x>>4];
|
ar := accept_ranges[x>>4];
|
||||||
if n < int(size) {
|
if n < cast(int)size {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
b1 := s[1];
|
b1 := s[1];
|
||||||
@@ -99,20 +99,20 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
|||||||
MASK_4 :: 0b00000111;
|
MASK_4 :: 0b00000111;
|
||||||
|
|
||||||
if size == 2 {
|
if size == 2 {
|
||||||
return rune(b0&MASK_2)<<6 | rune(b1&MASK_X), 2;
|
return cast(rune)(b0&MASK_2)<<6 | cast(rune)(b1&MASK_X), 2;
|
||||||
}
|
}
|
||||||
b2 := s[2];
|
b2 := s[2];
|
||||||
if b2 < 0x80 || 0xbf < b2 {
|
if b2 < 0x80 || 0xbf < b2 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
if size == 3 {
|
if size == 3 {
|
||||||
return rune(b0&MASK_3)<<12 | rune(b1&MASK_X)<<6 | rune(b2&MASK_X), 3;
|
return cast(rune)(b0&MASK_3)<<12 | cast(rune)(b1&MASK_X)<<6 | cast(rune)(b2&MASK_X), 3;
|
||||||
}
|
}
|
||||||
b3 := s[3];
|
b3 := s[3];
|
||||||
if b3 < 0x80 || 0xbf < b3 {
|
if b3 < 0x80 || 0xbf < b3 {
|
||||||
return RUNE_ERROR, 1;
|
return RUNE_ERROR, 1;
|
||||||
}
|
}
|
||||||
return rune(b0&MASK_4)<<18 | rune(b1&MASK_X)<<12 | rune(b3&MASK_X)<<6 | rune(b3&MASK_X), 4;
|
return cast(rune)(b0&MASK_4)<<18 | cast(rune)(b1&MASK_X)<<12 | cast(rune)(b3&MASK_X)<<6 | cast(rune)(b3&MASK_X), 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ valid_string :: proc(s: string) -> bool {
|
|||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size := int(x & 7);
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ rune_count :: proc(s: string) -> int {
|
|||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size := int(x & 7);
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -372,8 +372,6 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
GB_ASSERT(e->type == NULL);
|
GB_ASSERT(e->type == NULL);
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
u32 flags = c->context.decl->var_decl_flags;
|
|
||||||
|
|
||||||
if (e->flags & EntityFlag_Visited) {
|
if (e->flags & EntityFlag_Visited) {
|
||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
return;
|
return;
|
||||||
|
|||||||
+203
-187
@@ -1094,10 +1094,10 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
|||||||
if (ue->op.kind == Token_Pointer) {
|
if (ue->op.kind == Token_Pointer) {
|
||||||
type = make_type_pointer(c->allocator, check_type(c, ue->expr));
|
type = make_type_pointer(c->allocator, check_type(c, ue->expr));
|
||||||
goto end;
|
goto end;
|
||||||
} else if (ue->op.kind == Token_Maybe) {
|
} /* else if (ue->op.kind == Token_Maybe) {
|
||||||
type = make_type_maybe(c->allocator, check_type(c, ue->expr));
|
type = make_type_maybe(c->allocator, check_type(c, ue->expr));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
} */
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ht, HelperType, e);
|
case_ast_node(ht, HelperType, e);
|
||||||
@@ -1133,7 +1133,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
|||||||
Type *elem = check_type(c, vt->elem);
|
Type *elem = check_type(c, vt->elem);
|
||||||
Type *be = base_type(elem);
|
Type *be = base_type(elem);
|
||||||
i64 count = check_array_count(c, vt->count);
|
i64 count = check_array_count(c, vt->count);
|
||||||
if (!is_type_boolean(be) && !is_type_numeric(be)) {
|
if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be))) {
|
||||||
err_str = type_to_string(elem);
|
err_str = type_to_string(elem);
|
||||||
error_node(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str);
|
error_node(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str);
|
||||||
}
|
}
|
||||||
@@ -2589,10 +2589,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
case BuiltinProc_align_of:
|
case BuiltinProc_align_of:
|
||||||
case BuiltinProc_offset_of:
|
case BuiltinProc_offset_of:
|
||||||
case BuiltinProc_type_info:
|
case BuiltinProc_type_info:
|
||||||
|
|
||||||
case BuiltinProc_transmute:
|
|
||||||
case BuiltinProc_union_cast:
|
|
||||||
case BuiltinProc_down_cast:
|
|
||||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -2837,186 +2833,6 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
operand->type = t_type_info_ptr;
|
operand->type = t_type_info_ptr;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
||||||
case BuiltinProc_transmute: {
|
|
||||||
Type *type = check_type(c, ce->args.e[0]);
|
|
||||||
check_expr(c, operand, ce->args.e[1]);
|
|
||||||
if (operand->mode == Addressing_Invalid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operand->mode == Addressing_Constant) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Cannot transmute constant expression: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_type_untyped(operand->type)) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Cannot transmute untyped expression: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 srcz = type_size_of(c->sizes, c->allocator, operand->type);
|
|
||||||
i64 dstz = type_size_of(c->sizes, c->allocator, type);
|
|
||||||
if (srcz != dstz) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
gbString type_str = type_to_string(type);
|
|
||||||
error_node(operand->expr, "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, srcz, dstz);
|
|
||||||
gb_string_free(type_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
operand->type = type;
|
|
||||||
} break;
|
|
||||||
case BuiltinProc_union_cast: {
|
|
||||||
Type *type = check_type(c, ce->args.e[0]);
|
|
||||||
check_expr(c, operand, ce->args.e[1]);
|
|
||||||
if (operand->mode == Addressing_Invalid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operand->mode == Addressing_Constant) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Cannot `union_cast` a constant expression: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_type_untyped(operand->type)) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Cannot `union_cast` an untyped expression: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool src_is_ptr = is_type_pointer(operand->type);
|
|
||||||
bool dst_is_ptr = is_type_pointer(type);
|
|
||||||
Type *src = type_deref(operand->type);
|
|
||||||
Type *dst = type_deref(type);
|
|
||||||
Type *bsrc = base_type(src);
|
|
||||||
Type *bdst = base_type(dst);
|
|
||||||
|
|
||||||
if (src_is_ptr != dst_is_ptr) {
|
|
||||||
gbString src_type_str = type_to_string(operand->type);
|
|
||||||
gbString dst_type_str = type_to_string(type);
|
|
||||||
error_node(operand->expr, "Invalid `union_cast` types: `%s` and `%s`", src_type_str, dst_type_str);
|
|
||||||
gb_string_free(dst_type_str);
|
|
||||||
gb_string_free(src_type_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_type_union(src)) {
|
|
||||||
error_node(operand->expr, "`union_cast` can only operate on unions");
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
for (isize i = 1; i < bsrc->Record.field_count; i++) {
|
|
||||||
Entity *f = bsrc->Record.fields[i];
|
|
||||||
if (are_types_identical(f->type, dst)) {
|
|
||||||
ok = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
gbString dst_type_str = type_to_string(type);
|
|
||||||
error_node(operand->expr, "Cannot `union_cast` `%s` to `%s`", expr_str, dst_type_str);
|
|
||||||
gb_string_free(dst_type_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
|
|
||||||
variables[0] = make_entity_param(c->allocator, NULL, empty_token, type, false, true);
|
|
||||||
variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true);
|
|
||||||
|
|
||||||
Type *tuple = make_type_tuple(c->allocator);
|
|
||||||
tuple->Tuple.variables = variables;
|
|
||||||
tuple->Tuple.variable_count = 2;
|
|
||||||
|
|
||||||
operand->type = tuple;
|
|
||||||
operand->mode = Addressing_Value;
|
|
||||||
} break;
|
|
||||||
case BuiltinProc_down_cast: {
|
|
||||||
Type *type = check_type(c, ce->args.e[0]);
|
|
||||||
check_expr(c, operand, ce->args.e[1]);
|
|
||||||
if (operand->mode == Addressing_Invalid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operand->mode == Addressing_Constant) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Cannot `down_cast` a constant expression: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_type_untyped(operand->type)) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Cannot `down_cast` an untyped expression: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(is_type_pointer(operand->type) && is_type_pointer(type))) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Can only `down_cast` pointers: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *src = type_deref(operand->type);
|
|
||||||
Type *dst = type_deref(type);
|
|
||||||
Type *bsrc = base_type(src);
|
|
||||||
Type *bdst = base_type(dst);
|
|
||||||
|
|
||||||
if (!(is_type_struct(bsrc) || is_type_raw_union(bsrc))) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Can only `down_cast` pointer from structs or unions: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(is_type_struct(bdst) || is_type_raw_union(bdst))) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Can only `down_cast` pointer to structs or unions: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String param_name = check_down_cast_name(dst, src);
|
|
||||||
if (param_name.len == 0) {
|
|
||||||
gbString expr_str = expr_to_string(operand->expr);
|
|
||||||
error_node(operand->expr, "Illegal `down_cast`: `%s`", expr_str);
|
|
||||||
gb_string_free(expr_str);
|
|
||||||
operand->mode = Addressing_Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
operand->mode = Addressing_Value;
|
|
||||||
operand->type = type;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
|
|
||||||
case BuiltinProc_compile_assert:
|
case BuiltinProc_compile_assert:
|
||||||
// compile_assert :: proc(cond: bool)
|
// compile_assert :: proc(cond: bool)
|
||||||
|
|
||||||
@@ -3835,6 +3651,13 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (operand->mode == Addressing_Type) {
|
if (operand->mode == Addressing_Type) {
|
||||||
|
gbString str = type_to_string(operand->type);
|
||||||
|
error_node(call, "Expected a procedure, got a type `%s`", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
operand->mode = Addressing_Invalid;
|
||||||
|
operand->expr = call;
|
||||||
|
return Expr_Stmt;
|
||||||
|
#if 0
|
||||||
Type *t = operand->type;
|
Type *t = operand->type;
|
||||||
gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
@@ -3852,6 +3675,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
|
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return Expr_Expr;
|
return Expr_Expr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operand->mode == Addressing_Builtin) {
|
if (operand->mode == Addressing_Builtin) {
|
||||||
@@ -3909,6 +3733,17 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
return Expr_Stmt;
|
return Expr_Stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ExprKind check_macro_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||||
|
GB_ASSERT(call->kind == AstNode_MacroCallExpr);
|
||||||
|
ast_node(mce, MacroCallExpr, call);
|
||||||
|
|
||||||
|
error_node(call, "Macro call expressions are not yet supported");
|
||||||
|
operand->mode = Addressing_Invalid;
|
||||||
|
operand->expr = call;
|
||||||
|
return Expr_Stmt;
|
||||||
|
}
|
||||||
|
|
||||||
void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
|
void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
|
||||||
check_expr_base(c, o, e, t);
|
check_expr_base(c, o, e, t);
|
||||||
check_not_tuple(c, o);
|
check_not_tuple(c, o);
|
||||||
@@ -4563,6 +4398,183 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
o->expr = node;
|
o->expr = node;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ce, CastExpr, node);
|
||||||
|
Type *t = check_type(c, ce->type);
|
||||||
|
check_expr(c, o, ce->expr);
|
||||||
|
if (o->mode == Addressing_Invalid) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
switch (ce->token.kind) {
|
||||||
|
case Token_cast:
|
||||||
|
check_conversion(c, o, t);
|
||||||
|
break;
|
||||||
|
case Token_transmute: {
|
||||||
|
if (o->mode == Addressing_Constant) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Cannot transmute constant expression: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_type_untyped(o->type)) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Cannot transmute untyped expression: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 srcz = type_size_of(c->sizes, c->allocator, o->type);
|
||||||
|
i64 dstz = type_size_of(c->sizes, c->allocator, t);
|
||||||
|
if (srcz != dstz) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
gbString type_str = type_to_string(t);
|
||||||
|
error_node(o->expr, "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, srcz, dstz);
|
||||||
|
gb_string_free(type_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
o->type = t;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Token_union_cast: {
|
||||||
|
if (o->mode == Addressing_Constant) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Cannot `union_cast` a constant expression: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_type_untyped(o->type)) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Cannot `union_cast` an untyped expression: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool src_is_ptr = is_type_pointer(o->type);
|
||||||
|
bool dst_is_ptr = is_type_pointer(t);
|
||||||
|
Type *src = type_deref(o->type);
|
||||||
|
Type *dst = type_deref(t);
|
||||||
|
Type *bsrc = base_type(src);
|
||||||
|
Type *bdst = base_type(dst);
|
||||||
|
|
||||||
|
if (src_is_ptr != dst_is_ptr) {
|
||||||
|
gbString src_type_str = type_to_string(o->type);
|
||||||
|
gbString dst_type_str = type_to_string(t);
|
||||||
|
error_node(o->expr, "Invalid `union_cast` types: `%s` and `%s`", src_type_str, dst_type_str);
|
||||||
|
gb_string_free(dst_type_str);
|
||||||
|
gb_string_free(src_type_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_type_union(src)) {
|
||||||
|
error_node(o->expr, "`union_cast` can only operate on unions");
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
for (isize i = 1; i < bsrc->Record.field_count; i++) {
|
||||||
|
Entity *f = bsrc->Record.fields[i];
|
||||||
|
if (are_types_identical(f->type, dst)) {
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
gbString dst_type_str = type_to_string(t);
|
||||||
|
error_node(o->expr, "Cannot `union_cast` `%s` to `%s`", expr_str, dst_type_str);
|
||||||
|
gb_string_free(dst_type_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity **variables = gb_alloc_array(c->allocator, Entity *, 2);
|
||||||
|
variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true);
|
||||||
|
variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true);
|
||||||
|
|
||||||
|
Type *tuple = make_type_tuple(c->allocator);
|
||||||
|
tuple->Tuple.variables = variables;
|
||||||
|
tuple->Tuple.variable_count = 2;
|
||||||
|
|
||||||
|
o->type = tuple;
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
} break;
|
||||||
|
case Token_down_cast: {
|
||||||
|
if (o->mode == Addressing_Constant) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Cannot `down_cast` a constant expression: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_type_untyped(o->type)) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Cannot `down_cast` an untyped expression: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(is_type_pointer(o->type) && is_type_pointer(t))) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Can only `down_cast` pointers: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *src = type_deref(o->type);
|
||||||
|
Type *dst = type_deref(t);
|
||||||
|
Type *bsrc = base_type(src);
|
||||||
|
Type *bdst = base_type(dst);
|
||||||
|
|
||||||
|
if (!(is_type_struct(bsrc) || is_type_raw_union(bsrc))) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Can only `down_cast` pointer from structs or unions: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(is_type_struct(bdst) || is_type_raw_union(bdst))) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Can only `down_cast` pointer to structs or unions: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
String param_name = check_down_cast_name(dst, src);
|
||||||
|
if (param_name.len == 0) {
|
||||||
|
gbString expr_str = expr_to_string(o->expr);
|
||||||
|
error_node(o->expr, "Illegal `down_cast`: `%s`", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
o->mode = Addressing_Value;
|
||||||
|
o->type = t;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
GB_PANIC("Unknown cast expression");
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
case_ast_node(ue, UnaryExpr, node);
|
case_ast_node(ue, UnaryExpr, node);
|
||||||
check_expr_base(c, o, ue->expr, type_hint);
|
check_expr_base(c, o, ue->expr, type_hint);
|
||||||
@@ -4719,6 +4731,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
return check_call_expr(c, o, node);
|
return check_call_expr(c, o, node);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ce, MacroCallExpr, node);
|
||||||
|
return check_macro_call_expr(c, o, node);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(de, DerefExpr, node);
|
case_ast_node(de, DerefExpr, node);
|
||||||
check_expr_or_type(c, o, de->expr);
|
check_expr_or_type(c, o, de->expr);
|
||||||
if (o->mode == Addressing_Invalid) {
|
if (o->mode == Addressing_Invalid) {
|
||||||
|
|||||||
+10
-11
@@ -1232,12 +1232,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
|
|
||||||
case_ast_node(vd, ValueDecl, node);
|
case_ast_node(vd, ValueDecl, node);
|
||||||
|
GB_ASSERT(!c->context.scope->is_file);
|
||||||
if (vd->is_var) {
|
if (vd->is_var) {
|
||||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
|
Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
|
||||||
isize entity_count = 0;
|
isize entity_count = 0;
|
||||||
|
|
||||||
if (vd->flags&VarDeclFlag_thread_local &&
|
if (vd->flags & VarDeclFlag_thread_local) {
|
||||||
!c->context.scope->is_file) {
|
vd->flags &= ~VarDeclFlag_thread_local;
|
||||||
error_node(node, "`thread_local` may only be applied to a variable declaration");
|
error_node(node, "`thread_local` may only be applied to a variable declaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1256,7 +1257,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, vd->flags&VarDeclFlag_immutable);
|
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL, vd->flags&VarDeclFlag_immutable);
|
||||||
add_entity_definition(&c->info, name, entity);
|
entity->identifier = name;
|
||||||
} else {
|
} else {
|
||||||
TokenPos pos = found->token.pos;
|
TokenPos pos = found->token.pos;
|
||||||
error(token,
|
error(token,
|
||||||
@@ -1297,10 +1298,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
check_arity_match(c, vd);
|
check_arity_match(c, vd);
|
||||||
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
if (entities[i] != NULL) {
|
add_entity(c, c->context.scope, entities[i]->identifier, entities[i]);
|
||||||
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((vd->flags & VarDeclFlag_using) != 0) {
|
if ((vd->flags & VarDeclFlag_using) != 0) {
|
||||||
@@ -1315,13 +1314,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bool is_immutable = false;
|
if (e->kind != Entity_Variable) {
|
||||||
if (e->kind == Entity_Variable) {
|
continue;
|
||||||
is_immutable = e->Variable.is_immutable;
|
|
||||||
}
|
}
|
||||||
|
bool is_immutable = e->Variable.is_immutable;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Type *t = base_type(type_deref(e->type));
|
Type *t = base_type(type_deref(e->type));
|
||||||
|
|
||||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||||
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||||
GB_ASSERT(found != NULL);
|
GB_ASSERT(found != NULL);
|
||||||
|
|||||||
+29
-26
@@ -62,7 +62,6 @@ typedef struct DeclInfo {
|
|||||||
AstNode *type_expr;
|
AstNode *type_expr;
|
||||||
AstNode *init_expr;
|
AstNode *init_expr;
|
||||||
AstNode *proc_lit; // AstNode_ProcLit
|
AstNode *proc_lit; // AstNode_ProcLit
|
||||||
u32 var_decl_flags;
|
|
||||||
|
|
||||||
MapBool deps; // Key: Entity *
|
MapBool deps; // Key: Entity *
|
||||||
} DeclInfo;
|
} DeclInfo;
|
||||||
@@ -136,10 +135,6 @@ typedef enum BuiltinProcId {
|
|||||||
BuiltinProc_type_info,
|
BuiltinProc_type_info,
|
||||||
BuiltinProc_type_info_of_val,
|
BuiltinProc_type_info_of_val,
|
||||||
|
|
||||||
BuiltinProc_transmute,
|
|
||||||
BuiltinProc_union_cast,
|
|
||||||
BuiltinProc_down_cast,
|
|
||||||
|
|
||||||
BuiltinProc_compile_assert,
|
BuiltinProc_compile_assert,
|
||||||
BuiltinProc_assert,
|
BuiltinProc_assert,
|
||||||
BuiltinProc_panic,
|
BuiltinProc_panic,
|
||||||
@@ -183,10 +178,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
|||||||
{STR_LIT("type_info"), 1, false, Expr_Expr},
|
{STR_LIT("type_info"), 1, false, Expr_Expr},
|
||||||
{STR_LIT("type_info_of_val"), 1, false, Expr_Expr},
|
{STR_LIT("type_info_of_val"), 1, false, Expr_Expr},
|
||||||
|
|
||||||
{STR_LIT("transmute"), 2, false, Expr_Expr},
|
|
||||||
{STR_LIT("union_cast"), 2, false, Expr_Expr},
|
|
||||||
{STR_LIT("down_cast"), 2, false, Expr_Expr},
|
|
||||||
|
|
||||||
{STR_LIT("compile_assert"), 1, false, Expr_Stmt},
|
{STR_LIT("compile_assert"), 1, false, Expr_Stmt},
|
||||||
{STR_LIT("assert"), 1, false, Expr_Stmt},
|
{STR_LIT("assert"), 1, false, Expr_Stmt},
|
||||||
{STR_LIT("panic"), 1, false, Expr_Stmt},
|
{STR_LIT("panic"), 1, false, Expr_Stmt},
|
||||||
@@ -524,8 +515,6 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
|
|||||||
Entity *prev = NULL;
|
Entity *prev = NULL;
|
||||||
if (found) {
|
if (found) {
|
||||||
prev = *found;
|
prev = *found;
|
||||||
GB_ASSERT(prev != entity);
|
|
||||||
|
|
||||||
if (prev->kind != Entity_Procedure &&
|
if (prev->kind != Entity_Procedure &&
|
||||||
entity->kind != Entity_Procedure) {
|
entity->kind != Entity_Procedure) {
|
||||||
return prev;
|
return prev;
|
||||||
@@ -533,6 +522,9 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prev != NULL && entity->kind == Entity_Procedure) {
|
if (prev != NULL && entity->kind == Entity_Procedure) {
|
||||||
|
if (s->is_global) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
map_entity_multi_insert(&s->elements, key, entity);
|
map_entity_multi_insert(&s->elements, key, entity);
|
||||||
} else {
|
} else {
|
||||||
map_entity_set(&s->elements, key, entity);
|
map_entity_set(&s->elements, key, entity);
|
||||||
@@ -797,10 +789,15 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity)
|
|||||||
bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||||
String name = entity->token.string;
|
String name = entity->token.string;
|
||||||
if (!str_eq(name, str_lit("_"))) {
|
if (!str_eq(name, str_lit("_"))) {
|
||||||
Entity *insert_entity = scope_insert_entity(scope, entity);
|
Entity *ie = scope_insert_entity(scope, entity);
|
||||||
if (insert_entity) {
|
if (ie) {
|
||||||
Entity *up = insert_entity->using_parent;
|
TokenPos pos = ie->token.pos;
|
||||||
|
Entity *up = ie->using_parent;
|
||||||
if (up != NULL) {
|
if (up != NULL) {
|
||||||
|
if (token_pos_eq(pos, up->token.pos)) {
|
||||||
|
// NOTE(bill): Error should have been handled already
|
||||||
|
return false;
|
||||||
|
}
|
||||||
error(entity->token,
|
error(entity->token,
|
||||||
"Redeclararation of `%.*s` in this scope through `using`\n"
|
"Redeclararation of `%.*s` in this scope through `using`\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
@@ -808,7 +805,6 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
|||||||
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;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
TokenPos pos = insert_entity->token.pos;
|
|
||||||
if (token_pos_eq(pos, entity->token.pos)) {
|
if (token_pos_eq(pos, entity->token.pos)) {
|
||||||
// NOTE(bill): Error should have been handled already
|
// NOTE(bill): Error should have been handled already
|
||||||
return false;
|
return false;
|
||||||
@@ -1374,14 +1370,13 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// NOTE(bill): You need to store the entity information here unline a constant declaration
|
// NOTE(bill): You need to store the entity information here unline a constant declaration
|
||||||
isize entity_count = vd->names.count;
|
isize entity_cap = vd->names.count;
|
||||||
isize entity_index = 0;
|
isize entity_count = 0;
|
||||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap);
|
||||||
DeclInfo *di = NULL;
|
DeclInfo *di = NULL;
|
||||||
if (vd->values.count > 0) {
|
if (vd->values.count > 0) {
|
||||||
di = make_declaration_info(heap_allocator(), c->context.scope);
|
di = make_declaration_info(heap_allocator(), c->context.scope);
|
||||||
di->entities = entities;
|
di->entities = entities;
|
||||||
di->entity_count = entity_count;
|
|
||||||
di->type_expr = vd->type;
|
di->type_expr = vd->type;
|
||||||
di->init_expr = vd->values.e[0];
|
di->init_expr = vd->values.e[0];
|
||||||
}
|
}
|
||||||
@@ -1396,13 +1391,14 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
|||||||
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
|
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, vd->flags&VarDeclFlag_immutable);
|
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident, NULL, vd->flags & VarDeclFlag_immutable);
|
||||||
|
e->Variable.is_thread_local = vd->flags & VarDeclFlag_thread_local;
|
||||||
e->identifier = name;
|
e->identifier = name;
|
||||||
if (vd->flags&VarDeclFlag_using) {
|
if (vd->flags & VarDeclFlag_using) {
|
||||||
vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
|
vd->flags &= ~VarDeclFlag_using; // NOTE(bill): This error will be only caught once
|
||||||
error_node(name, "`using` is not allowed at the file scope");
|
error_node(name, "`using` is not allowed at the file scope");
|
||||||
}
|
}
|
||||||
entities[entity_index++] = e;
|
entities[entity_count++] = e;
|
||||||
|
|
||||||
DeclInfo *d = di;
|
DeclInfo *d = di;
|
||||||
if (d == NULL) {
|
if (d == NULL) {
|
||||||
@@ -1410,12 +1406,15 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
|||||||
d = make_declaration_info(heap_allocator(), e->scope);
|
d = make_declaration_info(heap_allocator(), e->scope);
|
||||||
d->type_expr = vd->type;
|
d->type_expr = vd->type;
|
||||||
d->init_expr = init_expr;
|
d->init_expr = init_expr;
|
||||||
d->var_decl_flags = vd->flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_entity_and_decl_info(c, name, e, d);
|
add_entity_and_decl_info(c, name, e, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (di != NULL) {
|
||||||
|
di->entity_count = entity_count;
|
||||||
|
}
|
||||||
|
|
||||||
check_arity_match(c, vd);
|
check_arity_match(c, vd);
|
||||||
} else {
|
} else {
|
||||||
for_array(i, vd->names) {
|
for_array(i, vd->names) {
|
||||||
@@ -1434,14 +1433,14 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
|||||||
Entity *e = NULL;
|
Entity *e = NULL;
|
||||||
|
|
||||||
AstNode *up_init = unparen_expr(init);
|
AstNode *up_init = unparen_expr(init);
|
||||||
if (init != NULL && is_ast_node_type(up_init)) {
|
if (up_init != NULL && is_ast_node_type(up_init)) {
|
||||||
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
|
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
|
||||||
// TODO(bill): What if vd->type != NULL??? How to handle this case?
|
// TODO(bill): What if vd->type != NULL??? How to handle this case?
|
||||||
d->type_expr = init;
|
d->type_expr = init;
|
||||||
d->init_expr = init;
|
d->init_expr = init;
|
||||||
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
|
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
|
||||||
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
|
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
|
||||||
d->proc_lit = init;
|
d->proc_lit = up_init;
|
||||||
d->type_expr = vd->type;
|
d->type_expr = vd->type;
|
||||||
} else {
|
} else {
|
||||||
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0});
|
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0});
|
||||||
@@ -1474,7 +1473,11 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
|
|||||||
case_end;
|
case_end;
|
||||||
case_ast_node(fl, ForeignLibrary, decl);
|
case_ast_node(fl, ForeignLibrary, decl);
|
||||||
if (!c->context.scope->is_file) {
|
if (!c->context.scope->is_file) {
|
||||||
error_node(decl, "#foreign_library declarations are only allowed in the file scope");
|
if (fl->is_system) {
|
||||||
|
error_node(decl, "#foreign_system_library declarations are only allowed in the file scope");
|
||||||
|
} else {
|
||||||
|
error_node(decl, "#foreign_library declarations are only allowed in the file scope");
|
||||||
|
}
|
||||||
// NOTE(bill): _Should_ be caught by the parser
|
// NOTE(bill): _Should_ be caught by the parser
|
||||||
// TODO(bill): Better error handling if it isn't
|
// TODO(bill): Better error handling if it isn't
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -12,6 +12,17 @@ gbAllocator heap_allocator(void) {
|
|||||||
gb_global String global_module_path = {0};
|
gb_global String global_module_path = {0};
|
||||||
gb_global bool global_module_path_set = false;
|
gb_global bool global_module_path_set = false;
|
||||||
|
|
||||||
|
gb_global gbScratchMemory scratch_memory = {0};
|
||||||
|
|
||||||
|
void init_scratch_memory(isize size) {
|
||||||
|
void *memory = gb_alloc(heap_allocator(), size);
|
||||||
|
gb_scratch_memory_init(&scratch_memory, memory, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
gbAllocator scratch_allocator(void) {
|
||||||
|
return gb_scratch_allocator(&scratch_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
i64 next_pow2(i64 n) {
|
i64 next_pow2(i64 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
|
|||||||
+3
-1
@@ -66,6 +66,7 @@ struct Entity {
|
|||||||
i32 field_index;
|
i32 field_index;
|
||||||
i32 field_src_index;
|
i32 field_src_index;
|
||||||
bool is_immutable;
|
bool is_immutable;
|
||||||
|
bool is_thread_local;
|
||||||
} Variable;
|
} Variable;
|
||||||
i32 TypeName;
|
i32 TypeName;
|
||||||
struct {
|
struct {
|
||||||
@@ -111,6 +112,7 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ
|
|||||||
|
|
||||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||||
GB_ASSERT(parent != NULL);
|
GB_ASSERT(parent != NULL);
|
||||||
|
token.pos = parent->token.pos;
|
||||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||||
entity->using_parent = parent;
|
entity->using_parent = parent;
|
||||||
entity->flags |= EntityFlag_Anonymous;
|
entity->flags |= EntityFlag_Anonymous;
|
||||||
@@ -132,7 +134,7 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
|
|||||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, bool is_immutable) {
|
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, bool is_immutable) {
|
||||||
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
|
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
|
||||||
entity->flags |= EntityFlag_Used;
|
entity->flags |= EntityFlag_Used;
|
||||||
entity->flags |= EntityFlag_Anonymous*(anonymous != 0);
|
if (anonymous) entity->flags |= EntityFlag_Anonymous;
|
||||||
entity->flags |= EntityFlag_Param;
|
entity->flags |= EntityFlag_Param;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,11 +156,6 @@ struct irProcedure {
|
|||||||
Type * result_type; \
|
Type * result_type; \
|
||||||
i32 elem_index; \
|
i32 elem_index; \
|
||||||
}) \
|
}) \
|
||||||
IR_INSTR_KIND(ArrayExtractValue, struct { \
|
|
||||||
irValue *address; \
|
|
||||||
Type * result_type; \
|
|
||||||
i32 index; \
|
|
||||||
}) \
|
|
||||||
IR_INSTR_KIND(StructExtractValue, struct { \
|
IR_INSTR_KIND(StructExtractValue, struct { \
|
||||||
irValue *address; \
|
irValue *address; \
|
||||||
Type * result_type; \
|
Type * result_type; \
|
||||||
@@ -550,8 +545,6 @@ Type *ir_instr_type(irInstr *instr) {
|
|||||||
return ir_type(instr->PtrOffset.address);
|
return ir_type(instr->PtrOffset.address);
|
||||||
case irInstr_Phi:
|
case irInstr_Phi:
|
||||||
return instr->Phi.type;
|
return instr->Phi.type;
|
||||||
case irInstr_ArrayExtractValue:
|
|
||||||
return instr->ArrayExtractValue.result_type;
|
|
||||||
case irInstr_StructExtractValue:
|
case irInstr_StructExtractValue:
|
||||||
return instr->StructExtractValue.result_type;
|
return instr->StructExtractValue.result_type;
|
||||||
case irInstr_UnionTagPtr:
|
case irInstr_UnionTagPtr:
|
||||||
@@ -851,17 +844,6 @@ irValue *ir_make_instr_ptr_offset(irProcedure *p, irValue *address, irValue *off
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
irValue *ir_make_instr_array_extract_value(irProcedure *p, irValue *address, i32 index) {
|
|
||||||
irValue *v = ir_alloc_instr(p, irInstr_ArrayExtractValue);
|
|
||||||
irInstr *i = &v->Instr;
|
|
||||||
i->ArrayExtractValue.address = address;
|
|
||||||
i->ArrayExtractValue.index = index;
|
|
||||||
Type *t = base_type(ir_type(address));
|
|
||||||
GB_ASSERT(is_type_array(t));
|
|
||||||
i->ArrayExtractValue.result_type = t->Array.elem;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
irValue *ir_make_instr_struct_extract_value(irProcedure *p, irValue *address, i32 index, Type *result_type) {
|
irValue *ir_make_instr_struct_extract_value(irProcedure *p, irValue *address, i32 index, Type *result_type) {
|
||||||
irValue *v = ir_alloc_instr(p, irInstr_StructExtractValue);
|
irValue *v = ir_alloc_instr(p, irInstr_StructExtractValue);
|
||||||
irInstr *i = &v->Instr;
|
irInstr *i = &v->Instr;
|
||||||
@@ -1646,13 +1628,6 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
irValue *ir_emit_array_ev(irProcedure *proc, irValue *s, i32 index) {
|
|
||||||
Type *st = base_type(ir_type(s));
|
|
||||||
GB_ASSERT(is_type_array(st));
|
|
||||||
return ir_emit(proc, ir_make_instr_array_extract_value(proc, s, index));
|
|
||||||
}
|
|
||||||
|
|
||||||
irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
|
irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
|
||||||
// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
|
// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
|
||||||
|
|
||||||
@@ -1913,6 +1888,12 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
Type *src = base_type(base_enum_type(src_type));
|
Type *src = base_type(base_enum_type(src_type));
|
||||||
Type *dst = base_type(base_enum_type(t));
|
Type *dst = base_type(base_enum_type(t));
|
||||||
|
|
||||||
|
|
||||||
|
// if (is_type_untyped_nil(src) && type_has_nil(dst)) {
|
||||||
|
if (is_type_untyped_nil(src)) {
|
||||||
|
return ir_make_value_nil(proc->module->allocator, t);
|
||||||
|
}
|
||||||
|
|
||||||
if (value->kind == irValue_Constant) {
|
if (value->kind == irValue_Constant) {
|
||||||
if (is_type_any(dst)) {
|
if (is_type_any(dst)) {
|
||||||
irValue *default_value = ir_add_local_generated(proc, default_type(src_type));
|
irValue *default_value = ir_add_local_generated(proc, default_type(src_type));
|
||||||
@@ -2147,10 +2128,6 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
return ir_emit_load(proc, result);
|
return ir_emit_load(proc, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_type_untyped_nil(src) && type_has_nil(dst)) {
|
|
||||||
return ir_make_value_nil(proc->module->allocator, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gb_printf_err("ir_emit_conv: src -> dst\n");
|
gb_printf_err("ir_emit_conv: src -> dst\n");
|
||||||
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
||||||
@@ -2718,13 +2695,38 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
return v;
|
return v;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ce, CastExpr, expr);
|
||||||
|
Type *type = tv->type;
|
||||||
|
irValue *expr = ir_build_expr(proc, ce->expr);
|
||||||
|
switch (ce->token.kind) {
|
||||||
|
case Token_cast:
|
||||||
|
ir_emit_comment(proc, str_lit("cast - cast"));
|
||||||
|
return ir_emit_conv(proc, expr, type);
|
||||||
|
|
||||||
|
case Token_transmute:
|
||||||
|
ir_emit_comment(proc, str_lit("cast - transmute"));
|
||||||
|
return ir_emit_transmute(proc, expr, type);
|
||||||
|
|
||||||
|
case Token_down_cast:
|
||||||
|
ir_emit_comment(proc, str_lit("cast - down_cast"));
|
||||||
|
return ir_emit_down_cast(proc, expr, type);
|
||||||
|
|
||||||
|
case Token_union_cast:
|
||||||
|
ir_emit_comment(proc, str_lit("cast - union_cast"));
|
||||||
|
return ir_emit_union_cast(proc, expr, type);
|
||||||
|
|
||||||
|
default:
|
||||||
|
GB_PANIC("Unknown cast expression");
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ue, UnaryExpr, expr);
|
case_ast_node(ue, UnaryExpr, expr);
|
||||||
switch (ue->op.kind) {
|
switch (ue->op.kind) {
|
||||||
case Token_Pointer:
|
case Token_Pointer:
|
||||||
return ir_emit_ptr_offset(proc, ir_build_addr(proc, ue->expr).addr, v_zero); // Make a copy of the pointer
|
return ir_emit_ptr_offset(proc, ir_build_addr(proc, ue->expr).addr, v_zero); // Make a copy of the pointer
|
||||||
|
|
||||||
case Token_Maybe:
|
// case Token_Maybe:
|
||||||
return ir_emit_conv(proc, ir_build_expr(proc, ue->expr), type_of_expr(proc->module->info, expr));
|
// return ir_emit_conv(proc, ir_build_expr(proc, ue->expr), type_of_expr(proc->module->info, expr));
|
||||||
|
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
return ir_build_expr(proc, ue->expr);
|
return ir_build_expr(proc, ue->expr);
|
||||||
@@ -2844,24 +2846,6 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
return ir_type_info(proc, t);
|
return ir_type_info(proc, t);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BuiltinProc_transmute: {
|
|
||||||
irValue *val = ir_build_expr(proc, ce->args.e[1]);
|
|
||||||
ir_emit_comment(proc, str_lit("cast - transmute"));
|
|
||||||
return ir_emit_transmute(proc, val, type_of_expr(proc->module->info, ce->args.e[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
case BuiltinProc_down_cast: {
|
|
||||||
irValue *val = ir_build_expr(proc, ce->args.e[1]);
|
|
||||||
ir_emit_comment(proc, str_lit("cast - down_cast"));
|
|
||||||
return ir_emit_down_cast(proc, val, type_of_expr(proc->module->info, ce->args.e[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
case BuiltinProc_union_cast: {
|
|
||||||
irValue *val = ir_build_expr(proc, ce->args.e[1]);
|
|
||||||
ir_emit_comment(proc, str_lit("cast - union_cast"));
|
|
||||||
return ir_emit_union_cast(proc, val, type_of_expr(proc->module->info, ce->args.e[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
case BuiltinProc_new: {
|
case BuiltinProc_new: {
|
||||||
ir_emit_comment(proc, str_lit("new"));
|
ir_emit_comment(proc, str_lit("new"));
|
||||||
// new :: proc(Type) -> ^Type
|
// new :: proc(Type) -> ^Type
|
||||||
@@ -3405,6 +3389,29 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ce, CastExpr, expr);
|
||||||
|
switch (ce->token.kind) {
|
||||||
|
case Token_cast: {
|
||||||
|
ir_emit_comment(proc, str_lit("Cast - cast"));
|
||||||
|
// NOTE(bill): Needed for dereference of pointer conversion
|
||||||
|
Type *type = type_of_expr(proc->module->info, expr);
|
||||||
|
irValue *v = ir_add_local_generated(proc, type);
|
||||||
|
ir_emit_store(proc, v, ir_emit_conv(proc, ir_build_expr(proc, ce->expr), type));
|
||||||
|
return ir_make_addr(v, expr);
|
||||||
|
}
|
||||||
|
case Token_transmute: {
|
||||||
|
ir_emit_comment(proc, str_lit("Cast - transmute"));
|
||||||
|
// NOTE(bill): Needed for dereference of pointer conversion
|
||||||
|
Type *type = type_of_expr(proc->module->info, expr);
|
||||||
|
irValue *v = ir_add_local_generated(proc, type);
|
||||||
|
ir_emit_store(proc, v, ir_emit_transmute(proc, ir_build_expr(proc, ce->expr), type));
|
||||||
|
return ir_make_addr(v, expr);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GB_PANIC("Unknown cast expression");
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ue, UnaryExpr, expr);
|
case_ast_node(ue, UnaryExpr, expr);
|
||||||
switch (ue->op.kind) {
|
switch (ue->op.kind) {
|
||||||
case Token_Pointer: {
|
case Token_Pointer: {
|
||||||
@@ -5304,9 +5311,8 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
case Entity_Variable: {
|
case Entity_Variable: {
|
||||||
irValue *g = ir_make_value_global(a, e, NULL);
|
irValue *g = ir_make_value_global(a, e, NULL);
|
||||||
if (decl->var_decl_flags & VarDeclFlag_thread_local) {
|
g->Global.is_thread_local = e->Variable.is_thread_local;
|
||||||
g->Global.is_thread_local = true;
|
|
||||||
}
|
|
||||||
irGlobalVariable var = {0};
|
irGlobalVariable var = {0};
|
||||||
var.var = g;
|
var.var = g;
|
||||||
var.decl = decl;
|
var.decl = decl;
|
||||||
@@ -5509,6 +5515,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
map_ir_value_set(&m->values, hash_pointer(e), p);
|
map_ir_value_set(&m->values, hash_pointer(e), p);
|
||||||
map_ir_value_set(&m->members, hash_string(name), p);
|
map_ir_value_set(&m->members, hash_string(name), p);
|
||||||
|
|
||||||
|
|
||||||
irProcedure *proc = &p->Proc;
|
irProcedure *proc = &p->Proc;
|
||||||
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea?
|
||||||
|
|
||||||
@@ -5557,6 +5564,18 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
CheckerInfo *info = proc->module->info;
|
CheckerInfo *info = proc->module->info;
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
irValue *global_type_infos = ir_find_global_variable(proc, str_lit("__type_infos"));
|
||||||
|
Type *type = base_type(type_deref(ir_type(type_info_data)));
|
||||||
|
GB_ASSERT(is_type_array(type));
|
||||||
|
irValue *array_data = ir_emit_array_epi(proc, type_info_data, 0);
|
||||||
|
irValue *array_count = ir_make_const_int(proc->module->allocator, type->Array.count);
|
||||||
|
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, global_type_infos, 0), array_data);
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, global_type_infos, 1), array_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Useful types
|
// Useful types
|
||||||
Type *t_i64_slice_ptr = make_type_pointer(a, make_type_slice(a, t_i64));
|
Type *t_i64_slice_ptr = make_type_pointer(a, make_type_slice(a, t_i64));
|
||||||
Type *t_string_slice_ptr = make_type_pointer(a, make_type_slice(a, t_string));
|
Type *t_string_slice_ptr = make_type_pointer(a, make_type_slice(a, t_string));
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ void ir_opt_add_operands(irValueArray *ops, irInstr *i) {
|
|||||||
array_add(ops, i->PtrOffset.address);
|
array_add(ops, i->PtrOffset.address);
|
||||||
array_add(ops, i->PtrOffset.offset);
|
array_add(ops, i->PtrOffset.offset);
|
||||||
break;
|
break;
|
||||||
case irInstr_ArrayExtractValue:
|
|
||||||
array_add(ops, i->ArrayExtractValue.address);
|
|
||||||
break;
|
|
||||||
case irInstr_StructExtractValue:
|
case irInstr_StructExtractValue:
|
||||||
array_add(ops, i->StructExtractValue.address);
|
array_add(ops, i->StructExtractValue.address);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -790,16 +790,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, "\n");
|
ir_fprintf(f, "\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case irInstr_ArrayExtractValue: {
|
|
||||||
Type *et = ir_type(instr->ArrayExtractValue.address);
|
|
||||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
|
||||||
|
|
||||||
ir_print_type(f, m, et);
|
|
||||||
ir_fprintf(f, " ");
|
|
||||||
ir_print_value(f, m, instr->ArrayExtractValue.address, et);
|
|
||||||
ir_fprintf(f, ", %d\n", instr->ArrayExtractValue.index);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case irInstr_StructExtractValue: {
|
case irInstr_StructExtractValue: {
|
||||||
Type *et = ir_type(instr->StructExtractValue.address);
|
Type *et = ir_type(instr->StructExtractValue.address);
|
||||||
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
ir_fprintf(f, "%%%d = extractvalue ", value->index);
|
||||||
|
|||||||
+2
-1
@@ -92,6 +92,7 @@ int main(int argc, char **argv) {
|
|||||||
timings_init(&timings, str_lit("Total Time"), 128);
|
timings_init(&timings, str_lit("Total Time"), 128);
|
||||||
// defer (timings_destroy(&timings));
|
// defer (timings_destroy(&timings));
|
||||||
init_string_buffer_memory();
|
init_string_buffer_memory();
|
||||||
|
init_scratch_memory(gb_megabytes(10));
|
||||||
init_global_error_collector();
|
init_global_error_collector();
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
@@ -234,7 +235,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
timings_start_section(&timings, str_lit("msvc-link"));
|
timings_start_section(&timings, str_lit("msvc-link"));
|
||||||
|
|
||||||
gbString lib_str = gb_string_make(heap_allocator(), "Kernel32.lib");
|
gbString lib_str = gb_string_make(heap_allocator(), "\"Kernel32.lib\"");
|
||||||
// defer (gb_string_free(lib_str));
|
// defer (gb_string_free(lib_str));
|
||||||
char lib_str_buf[1024] = {0};
|
char lib_str_buf[1024] = {0};
|
||||||
for_array(i, checker.info.foreign_libraries) {
|
for_array(i, checker.info.foreign_libraries) {
|
||||||
|
|||||||
+102
-17
@@ -142,17 +142,26 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
|
|||||||
AST_NODE_KIND(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \
|
AST_NODE_KIND(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \
|
||||||
AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \
|
AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \
|
||||||
AST_NODE_KIND(DemaybeExpr, "demaybe expression", struct { Token op; AstNode *expr; }) \
|
AST_NODE_KIND(DemaybeExpr, "demaybe expression", struct { Token op; AstNode *expr; }) \
|
||||||
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
|
||||||
AstNode *proc; \
|
|
||||||
AstNodeArray args; \
|
|
||||||
Token open, close; \
|
|
||||||
Token ellipsis; \
|
|
||||||
}) \
|
|
||||||
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
|
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
|
||||||
AstNode *expr; \
|
AstNode *expr; \
|
||||||
Token open, close; \
|
Token open, close; \
|
||||||
AstNode *low, *high; \
|
AstNode *low, *high; \
|
||||||
}) \
|
}) \
|
||||||
|
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
||||||
|
AstNode * proc; \
|
||||||
|
AstNodeArray args; \
|
||||||
|
Token open; \
|
||||||
|
Token close; \
|
||||||
|
Token ellipsis; \
|
||||||
|
}) \
|
||||||
|
AST_NODE_KIND(MacroCallExpr, "macro call expression", struct { \
|
||||||
|
AstNode * macro; \
|
||||||
|
Token bang; \
|
||||||
|
AstNodeArray args; \
|
||||||
|
Token open; \
|
||||||
|
Token close; \
|
||||||
|
}) \
|
||||||
|
AST_NODE_KIND(CastExpr, "cast expression", struct { Token token; AstNode *type, *expr; Token open, close; }) \
|
||||||
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
|
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
|
||||||
AST_NODE_KIND(BlockExpr, "block expr", struct { \
|
AST_NODE_KIND(BlockExpr, "block expr", struct { \
|
||||||
AstNodeArray stmts; \
|
AstNodeArray stmts; \
|
||||||
@@ -436,6 +445,8 @@ Token ast_node_token(AstNode *node) {
|
|||||||
return node->ParenExpr.open;
|
return node->ParenExpr.open;
|
||||||
case AstNode_CallExpr:
|
case AstNode_CallExpr:
|
||||||
return ast_node_token(node->CallExpr.proc);
|
return ast_node_token(node->CallExpr.proc);
|
||||||
|
case AstNode_MacroCallExpr:
|
||||||
|
return ast_node_token(node->MacroCallExpr.macro);
|
||||||
case AstNode_SelectorExpr:
|
case AstNode_SelectorExpr:
|
||||||
if (node->SelectorExpr.selector != NULL) {
|
if (node->SelectorExpr.selector != NULL) {
|
||||||
return ast_node_token(node->SelectorExpr.selector);
|
return ast_node_token(node->SelectorExpr.selector);
|
||||||
@@ -447,6 +458,8 @@ Token ast_node_token(AstNode *node) {
|
|||||||
return node->SliceExpr.open;
|
return node->SliceExpr.open;
|
||||||
case AstNode_Ellipsis:
|
case AstNode_Ellipsis:
|
||||||
return node->Ellipsis.token;
|
return node->Ellipsis.token;
|
||||||
|
case AstNode_CastExpr:
|
||||||
|
return node->CastExpr.token;
|
||||||
case AstNode_FieldValue:
|
case AstNode_FieldValue:
|
||||||
return node->FieldValue.eq;
|
return node->FieldValue.eq;
|
||||||
case AstNode_DerefExpr:
|
case AstNode_DerefExpr:
|
||||||
@@ -655,14 +668,25 @@ AstNode *make_paren_expr(AstFile *f, AstNode *expr, Token open, Token close) {
|
|||||||
|
|
||||||
AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, Token close, Token ellipsis) {
|
AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, Token close, Token ellipsis) {
|
||||||
AstNode *result = make_node(f, AstNode_CallExpr);
|
AstNode *result = make_node(f, AstNode_CallExpr);
|
||||||
result->CallExpr.proc = proc;
|
result->CallExpr.proc = proc;
|
||||||
result->CallExpr.args = args;
|
result->CallExpr.args = args;
|
||||||
result->CallExpr.open = open;
|
result->CallExpr.open = open;
|
||||||
result->CallExpr.close = close;
|
result->CallExpr.close = close;
|
||||||
result->CallExpr.ellipsis = ellipsis;
|
result->CallExpr.ellipsis = ellipsis;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode *make_macro_call_expr(AstFile *f, AstNode *macro, Token bang, AstNodeArray args, Token open, Token close) {
|
||||||
|
AstNode *result = make_node(f, AstNode_MacroCallExpr);
|
||||||
|
result->MacroCallExpr.macro = macro;
|
||||||
|
result->MacroCallExpr.bang = bang;
|
||||||
|
result->MacroCallExpr.args = args;
|
||||||
|
result->MacroCallExpr.open = open;
|
||||||
|
result->MacroCallExpr.close = close;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AstNode *make_selector_expr(AstFile *f, Token token, AstNode *expr, AstNode *selector) {
|
AstNode *make_selector_expr(AstFile *f, Token token, AstNode *expr, AstNode *selector) {
|
||||||
AstNode *result = make_node(f, AstNode_SelectorExpr);
|
AstNode *result = make_node(f, AstNode_SelectorExpr);
|
||||||
result->SelectorExpr.expr = expr;
|
result->SelectorExpr.expr = expr;
|
||||||
@@ -755,6 +779,16 @@ AstNode *make_field_value(AstFile *f, AstNode *field, AstNode *value, Token eq)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode *make_cast_expr(AstFile *f, Token token, AstNode *type, AstNode *expr, Token open, Token close) {
|
||||||
|
AstNode *result = make_node(f, AstNode_CastExpr);
|
||||||
|
result->CastExpr.token = token;
|
||||||
|
result->CastExpr.type = type;
|
||||||
|
result->CastExpr.expr = expr;
|
||||||
|
result->CastExpr.open = open;
|
||||||
|
result->CastExpr.close = close;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token open, Token close) {
|
AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token open, Token close) {
|
||||||
AstNode *result = make_node(f, AstNode_CompoundLit);
|
AstNode *result = make_node(f, AstNode_CompoundLit);
|
||||||
result->CompoundLit.type = type;
|
result->CompoundLit.type = type;
|
||||||
@@ -1774,8 +1808,12 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Token_OpenBrace: return parse_block_expr(f);
|
case Token_if:
|
||||||
case Token_if: return parse_if_expr(f);
|
if (lhs) goto error;
|
||||||
|
return parse_if_expr(f);
|
||||||
|
case Token_OpenBrace:
|
||||||
|
if (lhs) goto error;
|
||||||
|
return parse_block_expr(f);
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
AstNode *type = parse_identifier_or_type(f);
|
AstNode *type = parse_identifier_or_type(f);
|
||||||
@@ -1790,6 +1828,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
Token begin = f->curr_token;
|
Token begin = f->curr_token;
|
||||||
syntax_error(begin, "Expected an operand");
|
syntax_error(begin, "Expected an operand");
|
||||||
fix_advance_to_next_stmt(f);
|
fix_advance_to_next_stmt(f);
|
||||||
@@ -1844,6 +1883,36 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
|
|||||||
return make_call_expr(f, operand, args, open_paren, close_paren, ellipsis);
|
return make_call_expr(f, operand, args, open_paren, close_paren, ellipsis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AstNode *parse_macro_call_expr(AstFile *f, AstNode *operand) {
|
||||||
|
AstNodeArray args = make_ast_node_array(f);
|
||||||
|
Token bang, open_paren, close_paren;
|
||||||
|
|
||||||
|
bang = expect_token(f, Token_Not);
|
||||||
|
|
||||||
|
f->expr_level++;
|
||||||
|
open_paren = expect_token(f, Token_OpenParen);
|
||||||
|
|
||||||
|
while (f->curr_token.kind != Token_CloseParen &&
|
||||||
|
f->curr_token.kind != Token_EOF) {
|
||||||
|
if (f->curr_token.kind == Token_Comma) {
|
||||||
|
syntax_error(f->curr_token, "Expected an expression not a ,");
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode *arg = parse_expr(f, false);
|
||||||
|
array_add(&args, arg);
|
||||||
|
|
||||||
|
if (!allow_token(f, Token_Comma)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f->expr_level--;
|
||||||
|
close_paren = expect_closing(f, Token_CloseParen, str_lit("argument list"));
|
||||||
|
|
||||||
|
return make_macro_call_expr(f, operand, bang, args, open_paren, close_paren);
|
||||||
|
}
|
||||||
|
|
||||||
AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
||||||
AstNode *operand = parse_operand(f, lhs);
|
AstNode *operand = parse_operand(f, lhs);
|
||||||
|
|
||||||
@@ -1853,6 +1922,9 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
|||||||
case Token_OpenParen:
|
case Token_OpenParen:
|
||||||
operand = parse_call_expr(f, operand);
|
operand = parse_call_expr(f, operand);
|
||||||
break;
|
break;
|
||||||
|
case Token_Not:
|
||||||
|
operand = parse_macro_call_expr(f, operand);
|
||||||
|
break;
|
||||||
|
|
||||||
case Token_Period: {
|
case Token_Period: {
|
||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
@@ -1936,6 +2008,20 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
||||||
switch (f->curr_token.kind) {
|
switch (f->curr_token.kind) {
|
||||||
|
|
||||||
|
case Token_cast:
|
||||||
|
case Token_transmute:
|
||||||
|
case Token_down_cast:
|
||||||
|
case Token_union_cast:
|
||||||
|
{
|
||||||
|
Token token = f->curr_token; next_token(f);
|
||||||
|
Token open = expect_token(f, Token_OpenParen);
|
||||||
|
AstNode *type = parse_type(f);
|
||||||
|
Token close = expect_token(f, Token_CloseParen);
|
||||||
|
AstNode *expr = parse_unary_expr(f, lhs);
|
||||||
|
return make_cast_expr(f, token, type, expr, open, close);
|
||||||
|
} break;
|
||||||
|
|
||||||
case Token_Pointer: {
|
case Token_Pointer: {
|
||||||
Token op = f->curr_token;
|
Token op = f->curr_token;
|
||||||
next_token(f);
|
next_token(f);
|
||||||
@@ -1945,7 +2031,7 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) {
|
|||||||
}
|
}
|
||||||
return make_unary_expr(f, op, expr);
|
return make_unary_expr(f, op, expr);
|
||||||
} break;
|
} break;
|
||||||
case Token_Maybe:
|
// case Token_Maybe:
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
case Token_Sub:
|
case Token_Sub:
|
||||||
case Token_Not:
|
case Token_Not:
|
||||||
@@ -2432,10 +2518,10 @@ AstNode *parse_identifier_or_type(AstFile *f) {
|
|||||||
AstNode *sel = parse_identifier(f);
|
AstNode *sel = parse_identifier(f);
|
||||||
e = make_selector_expr(f, token, e, sel);
|
e = make_selector_expr(f, token, e, sel);
|
||||||
}
|
}
|
||||||
// if (f->curr_token.kind == Token_OpenParen) {
|
if (f->curr_token.kind == Token_OpenParen) {
|
||||||
// // HACK NOTE(bill): For type_of_val(expr)
|
// HACK NOTE(bill): For type_of_val(expr) et al.
|
||||||
// e = parse_call_expr(f, e);
|
e = parse_call_expr(f, e);
|
||||||
// }
|
}
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2464,8 +2550,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
|
|||||||
bool is_vector = false;
|
bool is_vector = false;
|
||||||
|
|
||||||
if (f->curr_token.kind == Token_Ellipsis) {
|
if (f->curr_token.kind == Token_Ellipsis) {
|
||||||
count_expr = make_ellipsis(f, f->curr_token, NULL);
|
count_expr = make_ellipsis(f, expect_token(f, Token_Ellipsis), NULL);
|
||||||
next_token(f);
|
|
||||||
} else if (f->curr_token.kind == Token_vector) {
|
} else if (f->curr_token.kind == Token_vector) {
|
||||||
next_token(f);
|
next_token(f);
|
||||||
if (f->curr_token.kind != Token_CloseBracket) {
|
if (f->curr_token.kind != Token_CloseBracket) {
|
||||||
|
|||||||
+4
-1
@@ -111,6 +111,10 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_asm, "asm"), \
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
TOKEN_KIND(Token_push_context, "push_context"), \
|
||||||
|
TOKEN_KIND(Token_cast, "cast"), \
|
||||||
|
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||||
|
TOKEN_KIND(Token_down_cast, "down_cast"), \
|
||||||
|
TOKEN_KIND(Token_union_cast, "union_cast"), \
|
||||||
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
||||||
TOKEN_KIND(Token_Count, "")
|
TOKEN_KIND(Token_Count, "")
|
||||||
|
|
||||||
@@ -149,7 +153,6 @@ bool token_pos_eq(TokenPos a, TokenPos b) {
|
|||||||
return token_pos_cmp(a, b) == 0;
|
return token_pos_cmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Text is UTF-8, thus why u8 and not char
|
|
||||||
typedef struct Token {
|
typedef struct Token {
|
||||||
TokenKind kind;
|
TokenKind kind;
|
||||||
String string;
|
String string;
|
||||||
|
|||||||
+2
-2
@@ -509,6 +509,7 @@ bool is_type_numeric(Type *t) {
|
|||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
||||||
}
|
}
|
||||||
|
// TODO(bill): Should this be here?
|
||||||
if (t->kind == Type_Vector) {
|
if (t->kind == Type_Vector) {
|
||||||
return is_type_numeric(t->Vector.elem);
|
return is_type_numeric(t->Vector.elem);
|
||||||
}
|
}
|
||||||
@@ -1851,8 +1852,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
|
|
||||||
|
|
||||||
gbString type_to_string(Type *type) {
|
gbString type_to_string(Type *type) {
|
||||||
gbString str = gb_string_make(gb_heap_allocator(), "");
|
return write_type_to_string(gb_string_make(heap_allocator(), ""), type);
|
||||||
return write_type_to_string(str, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user