mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 14:48:47 +00:00
This commit is contained in:
+12
-5
@@ -5,14 +5,21 @@
|
|||||||
#import "mem.odin";
|
#import "mem.odin";
|
||||||
#import "opengl.odin";
|
#import "opengl.odin";
|
||||||
#import "os.odin";
|
#import "os.odin";
|
||||||
|
#import "strconv.odin";
|
||||||
foo :: proc(x: int) -> f32 {
|
|
||||||
return 123;
|
|
||||||
}
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
// buf: [64]byte;
|
||||||
|
// // len := strconv.generic_ftoa(buf[..], 123.5431, 'f', 4, 64);
|
||||||
|
// x := 624.123;
|
||||||
|
// s := strconv.format_float(buf[..], x, 'f', 6, 64);
|
||||||
|
// fmt.println(s);
|
||||||
|
// fmt.printf("%3d\n", 102);
|
||||||
|
|
||||||
|
a: [10]int;
|
||||||
|
s := a[..0];
|
||||||
|
append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
|
||||||
|
fmt.println(s);
|
||||||
|
|
||||||
fmt.printf("%T\n", foo);
|
|
||||||
|
|
||||||
when false {
|
when false {
|
||||||
/*
|
/*
|
||||||
|
|||||||
+30
-11
@@ -316,24 +316,24 @@ __bounds_check_error :: proc(file: string, line, column: int, index, count: int)
|
|||||||
if 0 <= index && index < count {
|
if 0 <= index && index < count {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..<%d\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Index %d is out of bounds range 0..%d\n",
|
||||||
file, line, column, index, count);
|
file, line, column, index, count);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
__slice_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
__slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) {
|
||||||
if 0 <= low && low <= high {
|
if 0 <= low && low <= high && high <= max {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d:%d]\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n",
|
||||||
file, line, column, low, high);
|
file, line, column, low, high, max);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
__substring_expr_error :: proc(file: string, line, column: int, low, high: int) {
|
||||||
if 0 <= low && low <= high {
|
if 0 <= low && low <= high {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d:%d]\n",
|
fmt.fprintf(os.stderr, "%s(%d:%d) Invalid substring indices: [%d..%d]\n",
|
||||||
file, line, column, low, high);
|
file, line, column, low, high);
|
||||||
__debug_trap();
|
__debug_trap();
|
||||||
}
|
}
|
||||||
@@ -361,8 +361,9 @@ Raw_String :: struct #ordered {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Raw_Slice :: struct #ordered {
|
Raw_Slice :: struct #ordered {
|
||||||
data: rawptr,
|
data: rawptr,
|
||||||
count: int,
|
count: int,
|
||||||
|
capacity: int,
|
||||||
};
|
};
|
||||||
|
|
||||||
Raw_Dynamic_Array :: struct #ordered {
|
Raw_Dynamic_Array :: struct #ordered {
|
||||||
@@ -447,10 +448,28 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
|||||||
data := cast(^byte)array.data;
|
data := cast(^byte)array.data;
|
||||||
assert(data != nil);
|
assert(data != nil);
|
||||||
mem.zero(data + (elem_size*array.count), elem_size);
|
mem.zero(data + (elem_size*array.count), elem_size);
|
||||||
array.count += 1;
|
array.count++;
|
||||||
return array.count;
|
return array.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
|
||||||
|
items: rawptr, item_count: int) -> int {
|
||||||
|
slice := cast(^Raw_Slice)slice_;
|
||||||
|
|
||||||
|
if item_count <= 0 || items == nil {
|
||||||
|
return slice.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
item_count = min(slice.capacity-slice.count, item_count);
|
||||||
|
if item_count > 0 {
|
||||||
|
data := cast(^byte)slice.data;
|
||||||
|
assert(data != nil);
|
||||||
|
mem.copy(data + (elem_size*slice.count), items, elem_size * item_count);
|
||||||
|
slice.count += item_count;
|
||||||
|
}
|
||||||
|
return slice.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Map stuff
|
// Map stuff
|
||||||
|
|
||||||
@@ -506,7 +525,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
|
|||||||
nm.hashes[i] = -1;
|
nm.hashes[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < nm.entries.count; i += 1 {
|
for i := 0; i < nm.entries.count; i++ {
|
||||||
entry_header := __dynamic_map_get_entry(new_header, i);
|
entry_header := __dynamic_map_get_entry(new_header, i);
|
||||||
data := cast(^byte)entry_header;
|
data := cast(^byte)entry_header;
|
||||||
|
|
||||||
@@ -645,7 +664,7 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fr.entry_index == m.entries.count-1 {
|
if fr.entry_index == m.entries.count-1 {
|
||||||
m.entries.count -= 1;
|
m.entries.count--;
|
||||||
}
|
}
|
||||||
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
||||||
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
||||||
|
|||||||
+2
-2
@@ -37,7 +37,7 @@ spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1
|
|||||||
old_value := compare_exchange(a, 1, 0);
|
old_value := compare_exchange(a, 1, 0);
|
||||||
counter := 0;
|
counter := 0;
|
||||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||||
counter += 1;
|
counter++;
|
||||||
yield_thread();
|
yield_thread();
|
||||||
old_value = compare_exchange(a, 1, 0);
|
old_value = compare_exchange(a, 1, 0);
|
||||||
mfence();
|
mfence();
|
||||||
@@ -81,7 +81,7 @@ spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1
|
|||||||
old_value := compare_exchange(a, 1, 0);
|
old_value := compare_exchange(a, 1, 0);
|
||||||
counter := 0;
|
counter := 0;
|
||||||
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
for old_value != 0 && (time_out < 0 || counter < time_out) {
|
||||||
counter += 1;
|
counter++;
|
||||||
yield_thread();
|
yield_thread();
|
||||||
old_value = compare_exchange(a, 1, 0);
|
old_value = compare_exchange(a, 1, 0);
|
||||||
mfence();
|
mfence();
|
||||||
|
|||||||
@@ -0,0 +1,257 @@
|
|||||||
|
// #import "fmt.odin";
|
||||||
|
// Multiple precision decimal numbers
|
||||||
|
// NOTE: This is only for floating point printing and nothing else
|
||||||
|
|
||||||
|
Decimal :: struct {
|
||||||
|
digits: [384]byte, // big-endian digits
|
||||||
|
count: int,
|
||||||
|
decimal_point: int,
|
||||||
|
neg, trunc: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||||
|
digit_zero :: proc(buf: []byte) -> int {
|
||||||
|
for _, i in buf {
|
||||||
|
buf[i] = '0';
|
||||||
|
}
|
||||||
|
return buf.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
n := 10 + a.count + abs(a.decimal_point);
|
||||||
|
|
||||||
|
// TODO(bill): make this work with a buffer that's not big enough
|
||||||
|
assert(buf.count >= n);
|
||||||
|
buf = buf[..n];
|
||||||
|
|
||||||
|
if a.count == 0 {
|
||||||
|
buf[0] = '0';
|
||||||
|
return cast(string)buf[0..1];
|
||||||
|
}
|
||||||
|
|
||||||
|
w := 0;
|
||||||
|
if a.decimal_point <= 0 {
|
||||||
|
buf[w] = '0'; w++;
|
||||||
|
buf[w] = '.'; w++;
|
||||||
|
w += digit_zero(buf[w .. w-a.decimal_point]);
|
||||||
|
w += copy(buf[w..], a.digits[0..a.count]);
|
||||||
|
} else if a.decimal_point < a.count {
|
||||||
|
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
||||||
|
buf[w] = '.'; w++;
|
||||||
|
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
||||||
|
} else {
|
||||||
|
w += copy(buf[w..], a.digits[0..a.count]);
|
||||||
|
w += digit_zero(buf[w .. w+a.decimal_point-a.count]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cast(string)buf[0..w];
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim trailing zeros
|
||||||
|
trim :: proc(a: ^Decimal) {
|
||||||
|
for a.count > 0 && a.digits[a.count-1] == '0' {
|
||||||
|
a.count--;
|
||||||
|
}
|
||||||
|
if a.count == 0 {
|
||||||
|
a.decimal_point = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assign :: proc(a: ^Decimal, i: u64) {
|
||||||
|
buf: [32]byte;
|
||||||
|
n := 0;
|
||||||
|
for i > 0 {
|
||||||
|
j := i/10;
|
||||||
|
i -= 10*j;
|
||||||
|
buf[n] = cast(byte)('0'+i);
|
||||||
|
n++;
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.count = 0;
|
||||||
|
for n--; n >= 0; n-- {
|
||||||
|
a.digits[a.count] = buf[n];
|
||||||
|
a.count++;
|
||||||
|
}
|
||||||
|
a.decimal_point = a.count;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_size :: 8*size_of(uint);
|
||||||
|
max_shift :: uint_size-4;
|
||||||
|
|
||||||
|
shift_right :: proc(a: ^Decimal, k: uint) {
|
||||||
|
r := 0; // read index
|
||||||
|
w := 0; // write index
|
||||||
|
|
||||||
|
n: uint;
|
||||||
|
for ; n>>k == 0; r++ {
|
||||||
|
if r >= a.count {
|
||||||
|
if n == 0 {
|
||||||
|
// Just in case
|
||||||
|
a.count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for n>>k == 0 {
|
||||||
|
n = n * 10;
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c := cast(uint)a.digits[r];
|
||||||
|
n = n*10 + c - '0';
|
||||||
|
}
|
||||||
|
a.decimal_point -= r-1;
|
||||||
|
|
||||||
|
mask: uint = (1<<k) - 1;
|
||||||
|
|
||||||
|
for ; r < a.count; r++ {
|
||||||
|
c := cast(uint)a.digits[r];
|
||||||
|
dig := n>>k;
|
||||||
|
n &= mask;
|
||||||
|
a.digits[w] = cast(byte)('0' + dig);
|
||||||
|
w++;
|
||||||
|
n = n*10 + c - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for n > 0 {
|
||||||
|
dig := n>>k;
|
||||||
|
n &= mask;
|
||||||
|
if w < a.digits.count {
|
||||||
|
a.digits[w] = cast(byte)('0' + dig);
|
||||||
|
w++;
|
||||||
|
} else if dig > 0 {
|
||||||
|
a.trunc = true;
|
||||||
|
}
|
||||||
|
n *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.count = w;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||||
|
delta := cast(int)(k/4);
|
||||||
|
|
||||||
|
r := a.count; // read index
|
||||||
|
w := a.count+delta; // write index
|
||||||
|
|
||||||
|
n: uint;
|
||||||
|
for r--; r >= 0; r-- {
|
||||||
|
n += (cast(uint)a.digits[r] - '0') << k;
|
||||||
|
quo := n/10;
|
||||||
|
rem := n - 10*quo;
|
||||||
|
w--;
|
||||||
|
if w < a.digits.count {
|
||||||
|
a.digits[w] = cast(byte)('0' + rem);
|
||||||
|
} else if rem != 0 {
|
||||||
|
a.trunc = true;
|
||||||
|
}
|
||||||
|
n = quo;
|
||||||
|
}
|
||||||
|
|
||||||
|
for n > 0 {
|
||||||
|
quo := n/10;
|
||||||
|
rem := n - 10*quo;
|
||||||
|
w--;
|
||||||
|
if w < a.digits.count {
|
||||||
|
a.digits[w] = cast(byte)('0' + rem);
|
||||||
|
} else if rem != 0 {
|
||||||
|
a.trunc = true;
|
||||||
|
}
|
||||||
|
n = quo;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.count += delta;
|
||||||
|
a.count = min(a.count, a.digits.count);
|
||||||
|
a.decimal_point += delta;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift :: proc(a: ^Decimal, k: int) {
|
||||||
|
match {
|
||||||
|
case a.count == 0:
|
||||||
|
// no need to update
|
||||||
|
case k > 0:
|
||||||
|
for k > max_shift {
|
||||||
|
shift_left(a, max_shift);
|
||||||
|
k -= max_shift;
|
||||||
|
}
|
||||||
|
shift_left(a, cast(uint)k);
|
||||||
|
|
||||||
|
|
||||||
|
case k < 0:
|
||||||
|
for k < -max_shift {
|
||||||
|
shift_right(a, max_shift);
|
||||||
|
k += max_shift;
|
||||||
|
}
|
||||||
|
shift_right(a, cast(uint)-k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
|
||||||
|
if nd < 0 || nd >= a.count { return false ; }
|
||||||
|
if a.digits[nd] == '5' && nd+1 == a.count {
|
||||||
|
if a.trunc {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return nd > 0 && (a.digits[nd-1]-'0')%2 != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.digits[nd] >= '5';
|
||||||
|
}
|
||||||
|
|
||||||
|
round :: proc(a: ^Decimal, nd: int) {
|
||||||
|
if nd < 0 || nd >= a.count { return; }
|
||||||
|
if can_round_up(a, nd) {
|
||||||
|
round_up(a, nd);
|
||||||
|
} else {
|
||||||
|
round_down(a, nd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round_up :: proc(a: ^Decimal, nd: int) {
|
||||||
|
if nd < 0 || nd >= a.count { return; }
|
||||||
|
|
||||||
|
for i := nd-1; i >= 0; i-- {
|
||||||
|
if c := a.digits[i]; c < '9' {
|
||||||
|
a.digits[i]++;
|
||||||
|
a.count = i+1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number is just 9s
|
||||||
|
a.digits[0] = '1';
|
||||||
|
a.count = 1;
|
||||||
|
a.decimal_point++;
|
||||||
|
}
|
||||||
|
|
||||||
|
round_down :: proc(a: ^Decimal, nd: int) {
|
||||||
|
if nd < 0 || nd >= a.count { return; }
|
||||||
|
a.count = nd;
|
||||||
|
trim(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Extract integer part, rounded appropriately. There are no guarantees about overflow.
|
||||||
|
rounded_integer :: proc(a: ^Decimal) -> u64 {
|
||||||
|
if a.decimal_point > 20 {
|
||||||
|
return 0xffff_ffff_ffff_ffff;
|
||||||
|
}
|
||||||
|
i: int;
|
||||||
|
n: u64 = 0;
|
||||||
|
m := min(a.decimal_point, a.count);
|
||||||
|
for i = 0; i < m; i++ {
|
||||||
|
n = n*10 + cast(u64)(a.digits[i]-'0');
|
||||||
|
}
|
||||||
|
for ; i < a.decimal_point; i++ {
|
||||||
|
n *= 10;
|
||||||
|
}
|
||||||
|
if can_round_up(a, a.decimal_point) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
+300
-379
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -66,7 +66,7 @@ murmur32 :: proc(data: []byte) -> u32 {
|
|||||||
h1 = h1*5 + 0xe6546b64;
|
h1 = h1*5 + 0xe6546b64;
|
||||||
}
|
}
|
||||||
|
|
||||||
tail := data[nblocks*4:];
|
tail := data[nblocks*4 ..];
|
||||||
|
|
||||||
k1: u32;
|
k1: u32;
|
||||||
match tail.count&3 {
|
match tail.count&3 {
|
||||||
@@ -146,7 +146,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
|||||||
i := 0;
|
i := 0;
|
||||||
for len >= 8 {
|
for len >= 8 {
|
||||||
k1, k2: u32;
|
k1, k2: u32;
|
||||||
k1 = data32[i]; i += 1;
|
k1 = data32[i]; i++;
|
||||||
k1 *= m;
|
k1 *= m;
|
||||||
k1 ~= k1>>r;
|
k1 ~= k1>>r;
|
||||||
k1 *= m;
|
k1 *= m;
|
||||||
@@ -154,7 +154,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
|||||||
h1 ~= k1;
|
h1 ~= k1;
|
||||||
len -= 4;
|
len -= 4;
|
||||||
|
|
||||||
k2 = data32[i]; i += 1;
|
k2 = data32[i]; i++;
|
||||||
k2 *= m;
|
k2 *= m;
|
||||||
k2 ~= k2>>r;
|
k2 ~= k2>>r;
|
||||||
k2 *= m;
|
k2 *= m;
|
||||||
@@ -165,7 +165,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
|||||||
|
|
||||||
if len >= 4 {
|
if len >= 4 {
|
||||||
k1: u32;
|
k1: u32;
|
||||||
k1 = data32[i]; i += 1;
|
k1 = data32[i]; i++;
|
||||||
k1 *= m;
|
k1 *= m;
|
||||||
k1 ~= k1>>r;
|
k1 ~= k1>>r;
|
||||||
k1 *= m;
|
k1 *= m;
|
||||||
@@ -174,7 +174,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
|||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
data8 := slice_to_bytes(data32[i:])[:3];
|
data8 := slice_to_bytes(data32[i..])[..3];
|
||||||
match len {
|
match len {
|
||||||
case 3:
|
case 3:
|
||||||
h2 ~= cast(u32)data8[2] << 16;
|
h2 ~= cast(u32)data8[2] << 16;
|
||||||
|
|||||||
+4
-4
@@ -151,8 +151,8 @@ mat4_identity :: proc() -> Mat4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
||||||
for j in 0..<4 {
|
for j in 0..4 {
|
||||||
for i in 0..<4 {
|
for i in 0..4 {
|
||||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,8 +161,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
|
|||||||
|
|
||||||
mul :: proc(a, b: Mat4) -> Mat4 {
|
mul :: proc(a, b: Mat4) -> Mat4 {
|
||||||
c: Mat4;
|
c: Mat4;
|
||||||
for j in 0..<4 {
|
for j in 0..4 {
|
||||||
for i in 0..<4 {
|
for i in 0..4 {
|
||||||
c[j][i] = a[0][i]*b[j][0] +
|
c[j][i] = a[0][i]*b[j][0] +
|
||||||
a[1][i]*b[j][1] +
|
a[1][i]*b[j][1] +
|
||||||
a[2][i]*b[j][2] +
|
a[2][i]*b[j][2] +
|
||||||
|
|||||||
+5
-5
@@ -32,7 +32,7 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "_
|
|||||||
|
|
||||||
compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
|
compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
|
||||||
n := min(a.count, b.count);
|
n := min(a.count, b.count);
|
||||||
for i in 0..<n {
|
for i in 0..n {
|
||||||
match {
|
match {
|
||||||
case a[i] < b[i]:
|
case a[i] < b[i]:
|
||||||
return -1;
|
return -1;
|
||||||
@@ -79,7 +79,7 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
|
|||||||
header.size = size;
|
header.size = size;
|
||||||
ptr := cast(^int)(header+1);
|
ptr := cast(^int)(header+1);
|
||||||
|
|
||||||
for i := 0; cast(rawptr)ptr < data; i += 1 {
|
for i := 0; cast(rawptr)ptr < data; i++ {
|
||||||
(ptr+i)^ = -1;
|
(ptr+i)^ = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ Arena_Temp_Memory :: struct {
|
|||||||
|
|
||||||
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||||
backing = Allocator{};
|
backing = Allocator{};
|
||||||
memory = data[:0];
|
memory = data[..0];
|
||||||
temp_count = 0;
|
temp_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
|
|||||||
tmp: Arena_Temp_Memory;
|
tmp: Arena_Temp_Memory;
|
||||||
tmp.arena = a;
|
tmp.arena = a;
|
||||||
tmp.original_count = a.memory.count;
|
tmp.original_count = a.memory.count;
|
||||||
a.temp_count += 1;
|
a.temp_count++;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) {
|
|||||||
assert(arena.memory.count >= original_count);
|
assert(arena.memory.count >= original_count);
|
||||||
assert(arena.temp_count > 0);
|
assert(arena.temp_count > 0);
|
||||||
arena.memory.count = original_count;
|
arena.memory.count = original_count;
|
||||||
arena.temp_count -= 1;
|
arena.temp_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf: [300]byte;
|
buf: [300]byte;
|
||||||
copy(buf[:], cast([]byte)path);
|
copy(buf[..], cast([]byte)path);
|
||||||
|
|
||||||
handle := cast(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 {
|
||||||
@@ -184,7 +184,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
|||||||
|
|
||||||
assert(buf.count > name.count);
|
assert(buf.count > name.count);
|
||||||
|
|
||||||
copy(buf[:], cast([]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;
|
||||||
@@ -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[:], cast([]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 {
|
||||||
|
|||||||
@@ -0,0 +1,336 @@
|
|||||||
|
#import . "decimal.odin";
|
||||||
|
#import "math.odin";
|
||||||
|
|
||||||
|
Int_Flag :: enum {
|
||||||
|
PREFIX = 1<<0,
|
||||||
|
PLUS = 1<<1,
|
||||||
|
SPACE = 1<<2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
||||||
|
match s {
|
||||||
|
case "1", "t", "T", "true", "TRUE", "True":
|
||||||
|
return true, true;
|
||||||
|
case "0", "f", "F", "false", "FALSE", "False":
|
||||||
|
return false, true;
|
||||||
|
}
|
||||||
|
return false, false;
|
||||||
|
}
|
||||||
|
|
||||||
|
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||||
|
s := b ? "true" : "false";
|
||||||
|
append(buf, ..cast([]byte)s);
|
||||||
|
return cast(string)buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||||
|
using Int_Flag;
|
||||||
|
return append_bits(buf, u, base, false, digits, 0);
|
||||||
|
}
|
||||||
|
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||||
|
return append_bits(buf, cast(u64)i, base, i < 0, digits, 0);
|
||||||
|
}
|
||||||
|
itoa :: proc(buf: []byte, i: int) -> string {
|
||||||
|
return append_int(buf, cast(i64)i, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||||
|
return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Decimal_Slice :: struct {
|
||||||
|
digits: []byte,
|
||||||
|
count: int,
|
||||||
|
decimal_point: int,
|
||||||
|
neg: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
Float_Info :: struct {
|
||||||
|
mantbits: uint,
|
||||||
|
expbits: uint,
|
||||||
|
bias: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
f32_info := Float_Info{23, 8, -127};
|
||||||
|
f64_info := Float_Info{52, 11, -1023};
|
||||||
|
|
||||||
|
|
||||||
|
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> []byte {
|
||||||
|
bits: u64;
|
||||||
|
flt: ^Float_Info;
|
||||||
|
match bit_size {
|
||||||
|
case 32:
|
||||||
|
bits = cast(u64)transmute(u32)cast(f32)val;
|
||||||
|
flt = ^f32_info;
|
||||||
|
case 64:
|
||||||
|
bits = transmute(u64)val;
|
||||||
|
flt = ^f64_info;
|
||||||
|
default:
|
||||||
|
panic("strconv: invalid bit_size");
|
||||||
|
}
|
||||||
|
|
||||||
|
neg := bits>>(flt.expbits+flt.mantbits) != 0;
|
||||||
|
exp := cast(int)(bits>>flt.mantbits) & (1<<flt.expbits - 1);
|
||||||
|
mant := bits & (cast(u64)1 << flt.mantbits - 1);
|
||||||
|
|
||||||
|
match exp {
|
||||||
|
case 1<<flt.expbits - 1:
|
||||||
|
s: string;
|
||||||
|
if mant != 0 {
|
||||||
|
s = "NaN";
|
||||||
|
} else if neg {
|
||||||
|
s = "-Inf";
|
||||||
|
} else {
|
||||||
|
s = "+Inf";
|
||||||
|
}
|
||||||
|
append(buf, ..cast([]byte)s);
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
case 0: // denormalized
|
||||||
|
exp++;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mant |= cast(u64)1 << flt.mantbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
exp += flt.bias;
|
||||||
|
|
||||||
|
d_: Decimal;
|
||||||
|
d := ^d_;
|
||||||
|
assign(d, mant);
|
||||||
|
shift(d, exp - cast(int)flt.mantbits);
|
||||||
|
digs: Decimal_Slice;
|
||||||
|
shortest := prec < 0;
|
||||||
|
if shortest {
|
||||||
|
round_shortest(d, mant, exp, flt);
|
||||||
|
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||||
|
match fmt {
|
||||||
|
case 'e', 'E':
|
||||||
|
prec = digs.count-1;
|
||||||
|
case 'f', 'F':
|
||||||
|
prec = max(digs.count-digs.decimal_point, 0);
|
||||||
|
case 'g', 'G':
|
||||||
|
prec = digs.count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match fmt {
|
||||||
|
case 'e', 'E': round(d, prec+1);
|
||||||
|
case 'f', 'F': round(d, d.decimal_point+prec);
|
||||||
|
case 'g', 'G':
|
||||||
|
if prec == 0 {
|
||||||
|
prec = 1;
|
||||||
|
}
|
||||||
|
round(d, prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||||
|
}
|
||||||
|
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, prec: int, fmt: byte) -> []byte {
|
||||||
|
match fmt {
|
||||||
|
case 'f', 'F':
|
||||||
|
add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) {
|
||||||
|
for b in bytes {
|
||||||
|
if dst.count <= w^ {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dst[w^] = b;
|
||||||
|
w^++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := buf[..];
|
||||||
|
w := 0;
|
||||||
|
if neg {
|
||||||
|
add_bytes(^dst, ^w, '-');
|
||||||
|
} else {
|
||||||
|
add_bytes(^dst, ^w, '+');
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer, padded with zeros when needed
|
||||||
|
if digs.decimal_point > 0 {
|
||||||
|
m := min(digs.count, digs.decimal_point);
|
||||||
|
add_bytes(^dst, ^w, ..digs.digits[..m]);
|
||||||
|
for ; m < digs.decimal_point; m++ {
|
||||||
|
add_bytes(^dst, ^w, '0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add_bytes(^dst, ^w, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// fractional part
|
||||||
|
if prec > 0 {
|
||||||
|
add_bytes(^dst, ^w, '.');
|
||||||
|
for i in 0..prec {
|
||||||
|
c: byte = '0';
|
||||||
|
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||||
|
c = digs.digits[j];
|
||||||
|
}
|
||||||
|
add_bytes(^dst, ^w, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf[..w];
|
||||||
|
|
||||||
|
case 'e', 'E':
|
||||||
|
return nil; // TODO
|
||||||
|
|
||||||
|
case 'g', 'G':
|
||||||
|
return nil; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
c: [2]byte;
|
||||||
|
c[0] = '%';
|
||||||
|
c[1] = fmt;
|
||||||
|
append(buf, ..c[..]);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^Float_Info) {
|
||||||
|
if mant == 0 { // If mantissa is zero, the number is zero
|
||||||
|
d.count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
10^(dp-nd) > 2^(exp-mantbits)
|
||||||
|
log2(10) * (dp-nd) > exp-mantbits
|
||||||
|
log(2) >~ 0.332
|
||||||
|
332*(dp-nd) >= 100*(exp-mantbits)
|
||||||
|
*/
|
||||||
|
minexp := flt.bias+1;
|
||||||
|
if exp > minexp && 332*(d.decimal_point-d.count) >= 100*(exp - cast(int)flt.mantbits) {
|
||||||
|
// Number is already its shortest
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
upper_: Decimal; upper: = ^upper_;
|
||||||
|
assign(upper, 2*mant - 1);
|
||||||
|
shift(upper, exp - cast(int)flt.mantbits - 1);
|
||||||
|
|
||||||
|
mantlo: u64;
|
||||||
|
explo: int;
|
||||||
|
if mant > 1<<flt.mantbits || exp == minexp {
|
||||||
|
mantlo = mant-1;
|
||||||
|
explo = exp;
|
||||||
|
} else {
|
||||||
|
mantlo = 2*mant - 1;
|
||||||
|
explo = exp-1;
|
||||||
|
}
|
||||||
|
lower_: Decimal; lower: = ^lower_;
|
||||||
|
assign(lower, 2*mantlo + 1);
|
||||||
|
shift(lower, explo - cast(int)flt.mantbits - 1);
|
||||||
|
|
||||||
|
inclusive := mant%2 == 0;
|
||||||
|
|
||||||
|
for i in 0..d.count {
|
||||||
|
l: byte = '0'; // lower digit
|
||||||
|
if i < lower.count {
|
||||||
|
l = lower.digits[i];
|
||||||
|
}
|
||||||
|
m := d.digits[i]; // middle digit
|
||||||
|
u: byte = '0'; // upper digit
|
||||||
|
if i < upper.count {
|
||||||
|
u = upper.digits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ok_round_down := l != m || inclusive && i+1 == lower.count;
|
||||||
|
ok_round_up := m != u && (inclusive || m+1 < u || i+1 < upper.count);
|
||||||
|
|
||||||
|
if (ok_round_down && ok_round_up) {
|
||||||
|
round(d, i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ok_round_down) {
|
||||||
|
round_down(d, i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ok_round_up) {
|
||||||
|
round_up(d, i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MAX_BASE :: 32;
|
||||||
|
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
|
||||||
|
|
||||||
|
append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string {
|
||||||
|
is_pow2 :: proc(x: i64) -> bool {
|
||||||
|
if (x <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return x&(x-1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if base < 2 || base > MAX_BASE {
|
||||||
|
panic("strconv: illegal base passed to append_bits");
|
||||||
|
}
|
||||||
|
|
||||||
|
a: [65]byte;
|
||||||
|
i := a.count;
|
||||||
|
if neg {
|
||||||
|
u = -u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_pow2(cast(i64)base) {
|
||||||
|
b := cast(u64)base;
|
||||||
|
m := cast(uint)b - 1;
|
||||||
|
for u >= b {
|
||||||
|
i--;
|
||||||
|
a[i] = digits[cast(uint)u & m];
|
||||||
|
u >>= b;
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
a[i] = digits[cast(uint)u];
|
||||||
|
} else {
|
||||||
|
b := cast(u64)base;
|
||||||
|
for u >= b {
|
||||||
|
i--;
|
||||||
|
q := u / b;
|
||||||
|
a[i] = digits[cast(uint)(u-q*b)];
|
||||||
|
u = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
i--;
|
||||||
|
a[i] = digits[cast(uint)u];
|
||||||
|
}
|
||||||
|
|
||||||
|
if flags&Int_Flag.PREFIX != 0 {
|
||||||
|
ok := true;
|
||||||
|
match base {
|
||||||
|
case 2: i--; a[i] = 'b';
|
||||||
|
case 8: i--; a[i] = 'o';
|
||||||
|
case 10: i--; a[i] = 'd';
|
||||||
|
case 16: i--; a[i] = 'x';
|
||||||
|
default: ok = false;
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
i--;
|
||||||
|
a[i] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if neg {
|
||||||
|
i--; a[i] = '-';
|
||||||
|
} else if flags&Int_Flag.PLUS != 0 {
|
||||||
|
i--; a[i] = '+';
|
||||||
|
} else if flags&Int_Flag.SPACE != 0 {
|
||||||
|
i--; a[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
append(buf, ..a[i..]);
|
||||||
|
return cast(string)buf;
|
||||||
|
}
|
||||||
|
|
||||||
+1
-1
@@ -9,7 +9,7 @@ to_odin_string :: proc(c: ^byte) -> string {
|
|||||||
s: string;
|
s: string;
|
||||||
s.data = c;
|
s.data = c;
|
||||||
for (c+s.count)^ != 0 {
|
for (c+s.count)^ != 0 {
|
||||||
s.count += 1;
|
s.count++;
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -52,7 +52,7 @@ mutex_lock :: proc(m: ^Mutex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomic.store(^m.owner, thread_id);
|
atomic.store(^m.owner, thread_id);
|
||||||
m.recursion += 1;
|
m.recursion++;
|
||||||
}
|
}
|
||||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||||
thread_id := current_thread_id();
|
thread_id := current_thread_id();
|
||||||
@@ -68,7 +68,7 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
|||||||
}
|
}
|
||||||
atomic.store(^m.owner, thread_id);
|
atomic.store(^m.owner, thread_id);
|
||||||
}
|
}
|
||||||
m.recursion += 1;
|
m.recursion++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
mutex_unlock :: proc(m: ^Mutex) {
|
mutex_unlock :: proc(m: ^Mutex) {
|
||||||
@@ -76,7 +76,7 @@ mutex_unlock :: proc(m: ^Mutex) {
|
|||||||
thread_id := current_thread_id();
|
thread_id := current_thread_id();
|
||||||
assert(thread_id == atomic.load(^m.owner));
|
assert(thread_id == atomic.load(^m.owner));
|
||||||
|
|
||||||
m.recursion -= 1;
|
m.recursion--;
|
||||||
recursion = m.recursion;
|
recursion = m.recursion;
|
||||||
if recursion == 0 {
|
if recursion == 0 {
|
||||||
atomic.store(^m.owner, thread_id);
|
atomic.store(^m.owner, thread_id);
|
||||||
|
|||||||
+51
-7
@@ -92,7 +92,8 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
|||||||
return buf, 4;
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
decode_rune :: proc(s: string) -> (rune, int) {
|
decode_rune :: proc(s: string) -> (rune, int) #inline { return decode_rune(cast([]byte)s); }
|
||||||
|
decode_rune :: proc(s: []byte) -> (rune, int) {
|
||||||
n := s.count;
|
n := s.count;
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return RUNE_ERROR, 0;
|
return RUNE_ERROR, 0;
|
||||||
@@ -130,6 +131,46 @@ decode_rune :: proc(s: string) -> (rune, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
decode_last_rune :: proc(s: string) -> (rune, int) #inline { return decode_last_rune(cast([]byte)s); }
|
||||||
|
decode_last_rune :: proc(s: []byte) -> (rune, int) {
|
||||||
|
r: rune;
|
||||||
|
size: int;
|
||||||
|
start, end, limit: int;
|
||||||
|
|
||||||
|
end = s.count;
|
||||||
|
if end == 0 {
|
||||||
|
return RUNE_ERROR, 0;
|
||||||
|
}
|
||||||
|
start = end-1;
|
||||||
|
r = cast(rune)s[start];
|
||||||
|
if r < RUNE_SELF {
|
||||||
|
return r, 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
limit = max(end - UTF_MAX, 0);
|
||||||
|
|
||||||
|
start--;
|
||||||
|
for start >= limit {
|
||||||
|
if rune_start(s[start]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = max(start, 0);
|
||||||
|
r, size = decode_rune(s[start..end]);
|
||||||
|
if start+size != end {
|
||||||
|
return RUNE_ERROR, 1;
|
||||||
|
}
|
||||||
|
return r, size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
valid_rune :: proc(r: rune) -> bool {
|
valid_rune :: proc(r: rune) -> bool {
|
||||||
if r < 0 {
|
if r < 0 {
|
||||||
return false;
|
return false;
|
||||||
@@ -146,7 +187,7 @@ valid_string :: proc(s: string) -> bool {
|
|||||||
for i := 0; i < n; {
|
for i := 0; i < n; {
|
||||||
si := s[i];
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i += 1;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
x := accept_sizes[si];
|
x := accept_sizes[si];
|
||||||
@@ -174,25 +215,28 @@ valid_string :: proc(s: string) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rune_count :: proc(s: string) -> int {
|
rune_start :: proc(b: byte) -> bool #inline { return b&0xc0 != 0x80; }
|
||||||
|
|
||||||
|
rune_count :: proc(s: string) -> int #inline { return rune_count(cast([]byte)s); }
|
||||||
|
rune_count :: proc(s: []byte) -> int {
|
||||||
count := 0;
|
count := 0;
|
||||||
n := s.count;
|
n := s.count;
|
||||||
|
|
||||||
for i := 0; i < n; {
|
for i := 0; i < n; {
|
||||||
defer count += 1;
|
defer count++;
|
||||||
si := s[i];
|
si := s[i];
|
||||||
if si < RUNE_SELF { // ascii
|
if si < RUNE_SELF { // ascii
|
||||||
i += 1;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
x := accept_sizes[si];
|
x := accept_sizes[si];
|
||||||
if x == 0xf1 {
|
if x == 0xf1 {
|
||||||
i += 1;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
size := cast(int)(x & 7);
|
size := cast(int)(x & 7);
|
||||||
if i+size > n {
|
if i+size > n {
|
||||||
i += 1;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ar := accept_ranges[x>>4];
|
ar := accept_ranges[x>>4];
|
||||||
|
|||||||
+53
-21
@@ -197,11 +197,11 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (is_type_proc(dst)) {
|
if (is_type_proc(dst)) {
|
||||||
// if (are_types_identical(src, dst)) {
|
if (are_types_identical(src, dst)) {
|
||||||
// return 1;
|
return 3;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
if (is_type_any(dst)) {
|
if (is_type_any(dst)) {
|
||||||
// NOTE(bill): Anything can cast to `Any`
|
// NOTE(bill): Anything can cast to `Any`
|
||||||
@@ -2827,6 +2827,16 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entity == NULL &&
|
||||||
|
operand->type != NULL && is_type_untyped(operand->type) && is_type_string(operand->type)) {
|
||||||
|
String s = operand->value.value_string;
|
||||||
|
operand->mode = Addressing_Constant;
|
||||||
|
operand->value = make_exact_value_integer(s.len);
|
||||||
|
operand->type = t_untyped_integer;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (entity == NULL) {
|
if (entity == NULL) {
|
||||||
gbString op_str = expr_to_string(op_expr);
|
gbString op_str = expr_to_string(op_expr);
|
||||||
gbString type_str = type_to_string(operand->type);
|
gbString type_str = type_to_string(operand->type);
|
||||||
@@ -3047,19 +3057,26 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BuiltinProc_append: {
|
case BuiltinProc_append: {
|
||||||
// append :: proc([dynamic]Type, item: ...Type)
|
// append :: proc([dynamic]Type, item: ..Type)
|
||||||
|
// append :: proc([]Type, item: ..Type)
|
||||||
Type *type = operand->type;
|
Type *type = operand->type;
|
||||||
type = base_type(type);
|
type = base_type(type);
|
||||||
if (!is_type_dynamic_array(type)) {
|
if (!is_type_dynamic_array(type) && !is_type_slice(type)) {
|
||||||
gbString str = type_to_string(type);
|
gbString str = type_to_string(type);
|
||||||
error_node(operand->expr, "Expected a dynamic array, got `%s`", str);
|
error_node(operand->expr, "Expected a slice or dynamic array, got `%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bill): Semi-memory leaks
|
Type *elem = NULL;
|
||||||
Type *elem = type->DynamicArray.elem;
|
Type *slice_elem = NULL;
|
||||||
Type *slice_elem = make_type_slice(c->allocator, elem);
|
if (is_type_dynamic_array(type)) {
|
||||||
|
// TODO(bill): Semi-memory leaks
|
||||||
|
elem = type->DynamicArray.elem;
|
||||||
|
} else {
|
||||||
|
elem = type->Slice.elem;
|
||||||
|
}
|
||||||
|
slice_elem = make_type_slice(c->allocator, elem);
|
||||||
|
|
||||||
Type *proc_type_params = make_type_tuple(c->allocator);
|
Type *proc_type_params = make_type_tuple(c->allocator);
|
||||||
proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2);
|
proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2);
|
||||||
@@ -3394,7 +3411,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case BuiltinProc_swizzle: {
|
case BuiltinProc_swizzle: {
|
||||||
// swizzle :: proc(v: {N}T, T...) -> {M}T
|
// swizzle :: proc(v: {N}T, T..) -> {M}T
|
||||||
Type *vector_type = base_type(operand->type);
|
Type *vector_type = base_type(operand->type);
|
||||||
if (!is_type_vector(vector_type)) {
|
if (!is_type_vector(vector_type)) {
|
||||||
gbString type_str = type_to_string(operand->type);
|
gbString type_str = type_to_string(operand->type);
|
||||||
@@ -5110,6 +5127,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
if (is_type_string(t)) {
|
if (is_type_string(t)) {
|
||||||
|
if (se->index3) {
|
||||||
|
error_node(node, "3-index slice on a string in not needed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
valid = true;
|
valid = true;
|
||||||
if (o->mode == Addressing_Constant) {
|
if (o->mode == Addressing_Constant) {
|
||||||
max_count = o->value.value_string.len;
|
max_count = o->value.value_string.len;
|
||||||
@@ -5150,14 +5171,20 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
o->mode = Addressing_Value;
|
o->mode = Addressing_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (se->index3 && (se->high == NULL || se->max == NULL)) {
|
||||||
|
error(se->close, "2nd and 3rd indices are required in a 3-index slice");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
i64 indices[2] = {0};
|
i64 indices[2] = {0};
|
||||||
AstNode *nodes[2] = {se->low, se->high};
|
AstNode *nodes[3] = {se->low, se->high, se->max};
|
||||||
for (isize i = 0; i < gb_count_of(nodes); i++) {
|
for (isize i = 0; i < gb_count_of(nodes); i++) {
|
||||||
i64 index = max_count;
|
i64 index = max_count;
|
||||||
if (nodes[i] != NULL) {
|
if (nodes[i] != NULL) {
|
||||||
i64 capacity = -1;
|
i64 capacity = -1;
|
||||||
if (max_count >= 0)
|
if (max_count >= 0) {
|
||||||
capacity = max_count;
|
capacity = max_count;
|
||||||
|
}
|
||||||
i64 j = 0;
|
i64 j = 0;
|
||||||
if (check_index_value(c, nodes[i], capacity, &j)) {
|
if (check_index_value(c, nodes[i], capacity, &j)) {
|
||||||
index = j;
|
index = j;
|
||||||
@@ -5423,13 +5450,17 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
str = write_expr_to_string(str, se->expr);
|
str = write_expr_to_string(str, se->expr);
|
||||||
str = gb_string_appendc(str, "[");
|
str = gb_string_appendc(str, "[");
|
||||||
str = write_expr_to_string(str, se->low);
|
str = write_expr_to_string(str, se->low);
|
||||||
str = gb_string_appendc(str, ":");
|
str = gb_string_appendc(str, "..");
|
||||||
str = write_expr_to_string(str, se->high);
|
str = write_expr_to_string(str, se->high);
|
||||||
|
if (se->index3) {
|
||||||
|
str = gb_string_appendc(str, "..");
|
||||||
|
str = write_expr_to_string(str, se->max);
|
||||||
|
}
|
||||||
str = gb_string_appendc(str, "]");
|
str = gb_string_appendc(str, "]");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(e, Ellipsis, node);
|
case_ast_node(e, Ellipsis, node);
|
||||||
str = gb_string_appendc(str, "...");
|
str = gb_string_appendc(str, "..");
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fv, FieldValue, node);
|
case_ast_node(fv, FieldValue, node);
|
||||||
@@ -5445,9 +5476,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
|
|
||||||
case_ast_node(at, ArrayType, node);
|
case_ast_node(at, ArrayType, node);
|
||||||
str = gb_string_appendc(str, "[");
|
str = gb_string_appendc(str, "[");
|
||||||
if (at->count->kind == AstNode_UnaryExpr &&
|
if (at->count != NULL &&
|
||||||
at->count->UnaryExpr.op.kind == Token_Hash) {
|
at->count->kind == AstNode_UnaryExpr &&
|
||||||
str = gb_string_appendc(str, "#");
|
at->count->UnaryExpr.op.kind == Token_Ellipsis) {
|
||||||
|
str = gb_string_appendc(str, "..");
|
||||||
} else {
|
} else {
|
||||||
str = write_expr_to_string(str, at->count);
|
str = write_expr_to_string(str, at->count);
|
||||||
}
|
}
|
||||||
@@ -5456,7 +5488,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(at, DynamicArrayType, node);
|
case_ast_node(at, DynamicArrayType, node);
|
||||||
str = gb_string_appendc(str, "[...]");
|
str = gb_string_appendc(str, "[..]");
|
||||||
str = write_expr_to_string(str, at->elem);
|
str = write_expr_to_string(str, at->elem);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -5489,7 +5521,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
str = gb_string_appendc(str, ": ");
|
str = gb_string_appendc(str, ": ");
|
||||||
}
|
}
|
||||||
if (f->flags&FieldFlag_ellipsis) {
|
if (f->flags&FieldFlag_ellipsis) {
|
||||||
str = gb_string_appendc(str, "...");
|
str = gb_string_appendc(str, "..");
|
||||||
}
|
}
|
||||||
str = write_expr_to_string(str, f->type);
|
str = write_expr_to_string(str, f->type);
|
||||||
case_end;
|
case_end;
|
||||||
|
|||||||
+48
-4
@@ -421,6 +421,49 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
check_stmt(c, ts->stmt, flags);
|
check_stmt(c, ts->stmt, flags);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(s, IncDecStmt, node);
|
||||||
|
TokenKind op = s->op.kind;
|
||||||
|
switch (op) {
|
||||||
|
case Token_Inc: op = Token_Add; break;
|
||||||
|
case Token_Dec: op = Token_Sub; break;
|
||||||
|
default:
|
||||||
|
error_node(node, "Invalid inc/dec operation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand x = {0};
|
||||||
|
check_expr(c, &x, s->expr);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!is_type_integer(x.type) && !is_type_float(x.type)) {
|
||||||
|
gbString e = expr_to_string(s->expr);
|
||||||
|
gbString t = type_to_string(x.type);
|
||||||
|
error_node(node, "%s%.*s used on non-numeric type %s", e, LIT(s->op.string), t);
|
||||||
|
gb_string_free(t);
|
||||||
|
gb_string_free(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AstNode *left = s->expr;
|
||||||
|
AstNode *right = gb_alloc_item(c->allocator, AstNode);
|
||||||
|
right->kind = AstNode_BasicLit;
|
||||||
|
right->BasicLit.pos = s->op.pos;
|
||||||
|
right->BasicLit.kind = Token_Integer;
|
||||||
|
right->BasicLit.string = str_lit("1");
|
||||||
|
|
||||||
|
AstNode *be = gb_alloc_item(c->allocator, AstNode);
|
||||||
|
be->kind = AstNode_BinaryExpr;
|
||||||
|
be->BinaryExpr.op = s->op;
|
||||||
|
be->BinaryExpr.op.kind = op;
|
||||||
|
be->BinaryExpr.left = left;
|
||||||
|
be->BinaryExpr.right = right;
|
||||||
|
check_binary_expr(c, &x, be);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
check_assignment_variable(c, &x, left);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(as, AssignStmt, node);
|
case_ast_node(as, AssignStmt, node);
|
||||||
switch (as->op.kind) {
|
switch (as->op.kind) {
|
||||||
case Token_Eq: {
|
case Token_Eq: {
|
||||||
@@ -591,8 +634,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
if (fs->post != NULL) {
|
if (fs->post != NULL) {
|
||||||
check_stmt(c, fs->post, 0);
|
check_stmt(c, fs->post, 0);
|
||||||
|
|
||||||
if (fs->post->kind != AstNode_AssignStmt) {
|
if (fs->post->kind != AstNode_AssignStmt &&
|
||||||
error_node(fs->post, "`for` statement post statement must be an assignment");
|
fs->post->kind != AstNode_IncDecStmt) {
|
||||||
|
error_node(fs->post, "`for` statement post statement must be a simple statement");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check_stmt(c, fs->body, new_flags);
|
check_stmt(c, fs->body, new_flags);
|
||||||
@@ -671,8 +715,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
TokenKind op = Token_Lt;
|
TokenKind op = Token_Lt;
|
||||||
switch (ie->op.kind) {
|
switch (ie->op.kind) {
|
||||||
case Token_HalfOpenRange: op = Token_Lt; break;
|
case Token_Ellipsis: op = Token_Lt; break;
|
||||||
case Token_Ellipsis: op = Token_LtEq; break;
|
|
||||||
default: error(ie->op, "Invalid range operator"); break;
|
default: error(ie->op, "Invalid range operator"); break;
|
||||||
}
|
}
|
||||||
bool ok = compare_exact_values(Token_Lt, a, b);
|
bool ok = compare_exact_values(Token_Lt, a, b);
|
||||||
@@ -1215,6 +1258,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
case Entity_Variable: {
|
case Entity_Variable: {
|
||||||
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)) {
|
||||||
|
// TODO(bill): Make it work for unions too
|
||||||
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);
|
||||||
for_array(i, (*found)->elements.entries) {
|
for_array(i, (*found)->elements.entries) {
|
||||||
|
|||||||
+4
-3
@@ -274,8 +274,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
case ExactValue_Invalid:
|
case ExactValue_Invalid:
|
||||||
return v;
|
return v;
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
i = v.value_integer;
|
i = ~v.value_integer;
|
||||||
i = ~i;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto failure;
|
goto failure;
|
||||||
@@ -283,8 +282,10 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
|
|||||||
|
|
||||||
// NOTE(bill): unsigned integers will be negative and will need to be
|
// NOTE(bill): unsigned integers will be negative and will need to be
|
||||||
// limited to the types precision
|
// limited to the types precision
|
||||||
if (precision > 0)
|
// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
|
||||||
|
if (0 < precision && precision < 64) {
|
||||||
i &= ~((~0ll)<<precision);
|
i &= ~((~0ll)<<precision);
|
||||||
|
}
|
||||||
|
|
||||||
return make_exact_value_integer(i);
|
return make_exact_value_integer(i);
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ struct irProcedure {
|
|||||||
TokenPos pos; \
|
TokenPos pos; \
|
||||||
irValue *low; \
|
irValue *low; \
|
||||||
irValue *high; \
|
irValue *high; \
|
||||||
|
irValue *max; \
|
||||||
bool is_substring; \
|
bool is_substring; \
|
||||||
}) \
|
}) \
|
||||||
IR_INSTR_KIND(DebugDeclare, struct { \
|
IR_INSTR_KIND(DebugDeclare, struct { \
|
||||||
@@ -233,6 +234,7 @@ struct irProcedure {
|
|||||||
#define IR_CONV_KINDS \
|
#define IR_CONV_KINDS \
|
||||||
IR_CONV_KIND(trunc) \
|
IR_CONV_KIND(trunc) \
|
||||||
IR_CONV_KIND(zext) \
|
IR_CONV_KIND(zext) \
|
||||||
|
IR_CONV_KIND(sext) \
|
||||||
IR_CONV_KIND(fptrunc) \
|
IR_CONV_KIND(fptrunc) \
|
||||||
IR_CONV_KIND(fpext) \
|
IR_CONV_KIND(fpext) \
|
||||||
IR_CONV_KIND(fptoui) \
|
IR_CONV_KIND(fptoui) \
|
||||||
@@ -955,11 +957,12 @@ irValue *ir_make_instr_bounds_check(irProcedure *p, TokenPos pos, irValue *index
|
|||||||
v->Instr.BoundsCheck.len = len;
|
v->Instr.BoundsCheck.len = len;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue *low, irValue *high, bool is_substring) {
|
irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue *low, irValue *high, irValue *max, bool is_substring) {
|
||||||
irValue *v = ir_alloc_instr(p, irInstr_SliceBoundsCheck);
|
irValue *v = ir_alloc_instr(p, irInstr_SliceBoundsCheck);
|
||||||
v->Instr.SliceBoundsCheck.pos = pos;
|
v->Instr.SliceBoundsCheck.pos = pos;
|
||||||
v->Instr.SliceBoundsCheck.low = low;
|
v->Instr.SliceBoundsCheck.low = low;
|
||||||
v->Instr.SliceBoundsCheck.high = high;
|
v->Instr.SliceBoundsCheck.high = high;
|
||||||
|
v->Instr.SliceBoundsCheck.max = max;
|
||||||
v->Instr.SliceBoundsCheck.is_substring = is_substring;
|
v->Instr.SliceBoundsCheck.is_substring = is_substring;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -1844,6 +1847,7 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
|
|||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->Slice.elem)); break;
|
case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->Slice.elem)); break;
|
||||||
case 1: result_type = make_type_pointer(a, t_int); break;
|
case 1: result_type = make_type_pointer(a, t_int); break;
|
||||||
|
case 2: result_type = make_type_pointer(a, t_int); break;
|
||||||
}
|
}
|
||||||
} else if (is_type_string(t)) {
|
} else if (is_type_string(t)) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
@@ -2069,6 +2073,11 @@ irValue *ir_slice_count(irProcedure *proc, irValue *slice) {
|
|||||||
GB_ASSERT(t->kind == Type_Slice);
|
GB_ASSERT(t->kind == Type_Slice);
|
||||||
return ir_emit_struct_ev(proc, slice, 1);
|
return ir_emit_struct_ev(proc, slice, 1);
|
||||||
}
|
}
|
||||||
|
irValue *ir_slice_capacity(irProcedure *proc, irValue *slice) {
|
||||||
|
Type *t = base_type(ir_type(slice));
|
||||||
|
GB_ASSERT(t->kind == Type_Slice);
|
||||||
|
return ir_emit_struct_ev(proc, slice, 2);
|
||||||
|
}
|
||||||
|
|
||||||
irValue *ir_dynamic_array_elem(irProcedure *proc, irValue *da) {
|
irValue *ir_dynamic_array_elem(irProcedure *proc, irValue *da) {
|
||||||
Type *t = ir_type(da);
|
Type *t = ir_type(da);
|
||||||
@@ -2105,8 +2114,19 @@ irValue *ir_string_len(irProcedure *proc, irValue *string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ir_fill_slice(irProcedure *proc, irValue *slice_ptr, irValue *data, irValue *count, irValue *capacity) {
|
||||||
|
Type *t = ir_type(slice_ptr);
|
||||||
|
GB_ASSERT(is_type_pointer(t));
|
||||||
|
t = type_deref(t);
|
||||||
|
GB_ASSERT(is_type_slice(t));
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, slice_ptr, 0), data);
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, slice_ptr, 1), count);
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, slice_ptr, 2), capacity);
|
||||||
|
}
|
||||||
|
|
||||||
irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base, irValue *low, irValue *high) {
|
|
||||||
|
|
||||||
|
irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base, irValue *low, irValue *high, irValue *max) {
|
||||||
// TODO(bill): array bounds checking for slice creation
|
// TODO(bill): array bounds checking for slice creation
|
||||||
// TODO(bill): check that low < high <= max
|
// TODO(bill): check that low < high <= max
|
||||||
gbAllocator a = proc->module->allocator;
|
gbAllocator a = proc->module->allocator;
|
||||||
@@ -2122,8 +2142,16 @@ irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base,
|
|||||||
case Type_Pointer: high = v_one; break;
|
case Type_Pointer: high = v_one; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (max == NULL) {
|
||||||
|
switch (bt->kind) {
|
||||||
|
case Type_Array: high = ir_array_len(proc, base); break;
|
||||||
|
case Type_Slice: high = ir_slice_capacity(proc, base); break;
|
||||||
|
case Type_Pointer: high = v_one; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||||
|
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||||
|
|
||||||
irValue *elem = NULL;
|
irValue *elem = NULL;
|
||||||
switch (bt->kind) {
|
switch (bt->kind) {
|
||||||
@@ -2135,14 +2163,7 @@ irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base,
|
|||||||
elem = ir_emit_ptr_offset(proc, elem, low);
|
elem = ir_emit_ptr_offset(proc, elem, low);
|
||||||
|
|
||||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||||
|
ir_fill_slice(proc, slice, elem, len, cap);
|
||||||
irValue *gep = NULL;
|
|
||||||
gep = ir_emit_struct_ep(proc, slice, 0);
|
|
||||||
ir_emit_store(proc, gep, elem);
|
|
||||||
|
|
||||||
gep = ir_emit_struct_ep(proc, slice, 1);
|
|
||||||
ir_emit_store(proc, gep, len);
|
|
||||||
|
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2240,12 +2261,23 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
i64 sz = type_size_of(proc->module->allocator, src);
|
i64 sz = type_size_of(proc->module->allocator, src);
|
||||||
i64 dz = type_size_of(proc->module->allocator, dst);
|
i64 dz = type_size_of(proc->module->allocator, dst);
|
||||||
irConvKind kind = irConv_trunc;
|
irConvKind kind = irConv_trunc;
|
||||||
if (sz == dz) {
|
if (dz == sz) {
|
||||||
// NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment
|
// NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment
|
||||||
// NOTE(bill): Copy the value just for type correctness
|
// NOTE(bill): Copy the value just for type correctness
|
||||||
kind = irConv_bitcast;
|
kind = irConv_bitcast;
|
||||||
} else if (dz > sz) {
|
} else if (dz > sz) {
|
||||||
kind = irConv_zext;
|
kind = irConv_zext;
|
||||||
|
|
||||||
|
// TODO(bill): figure out the rules completely
|
||||||
|
bool ss = !is_type_unsigned(src);
|
||||||
|
bool ds = !is_type_unsigned(dst);
|
||||||
|
if (ss && ds) {
|
||||||
|
kind = irConv_sext;
|
||||||
|
} else if (ss) {
|
||||||
|
kind = irConv_sext;
|
||||||
|
} else {
|
||||||
|
kind = irConv_zext;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
|
return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
|
||||||
@@ -2374,7 +2406,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
ir_emit_store(proc, elem_ptr, elem);
|
ir_emit_store(proc, elem_ptr, elem);
|
||||||
|
|
||||||
irValue *len = ir_string_len(proc, value);
|
irValue *len = ir_string_len(proc, value);
|
||||||
irValue *slice = ir_add_local_slice(proc, dst, elem_ptr, v_zero, len);
|
irValue *cap = len;
|
||||||
|
irValue *slice = ir_add_local_slice(proc, dst, elem_ptr, v_zero, len, cap);
|
||||||
return ir_emit_load(proc, slice);
|
return ir_emit_load(proc, slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2745,7 +2778,7 @@ void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValu
|
|||||||
ir_emit(proc, ir_make_instr_bounds_check(proc, token.pos, index, len));
|
ir_emit(proc, ir_make_instr_bounds_check(proc, token.pos, index, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, bool is_substring) {
|
void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, irValue *max, bool is_substring) {
|
||||||
if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2753,10 +2786,11 @@ void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, ir
|
|||||||
low = ir_emit_conv(proc, low, t_int);
|
low = ir_emit_conv(proc, low, t_int);
|
||||||
high = ir_emit_conv(proc, high, t_int);
|
high = ir_emit_conv(proc, high, t_int);
|
||||||
|
|
||||||
ir_emit(proc, ir_make_instr_slice_bounds_check(proc, token.pos, low, high, is_substring));
|
ir_emit(proc, ir_make_instr_slice_bounds_check(proc, token.pos, low, high, max, is_substring));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// @Build
|
// @Build
|
||||||
@@ -3149,7 +3183,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
|
|
||||||
irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
|
irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
|
||||||
|
|
||||||
ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, false);
|
ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, count, false);
|
||||||
|
|
||||||
irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, count, t_int);
|
irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, count, t_int);
|
||||||
|
|
||||||
@@ -3161,10 +3195,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
irValue *ptr = ir_emit_conv(proc, call, ptr_type);
|
irValue *ptr = ir_emit_conv(proc, call, ptr_type);
|
||||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||||
|
|
||||||
irValue *gep0 = ir_emit_struct_ep(proc, slice, 0);
|
ir_fill_slice(proc, slice, ptr, count, count);
|
||||||
irValue *gep1 = ir_emit_struct_ep(proc, slice, 1);
|
|
||||||
ir_emit_store(proc, gep0, ptr);
|
|
||||||
ir_emit_store(proc, gep1, count);
|
|
||||||
return ir_emit_load(proc, slice);
|
return ir_emit_load(proc, slice);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -3303,8 +3334,16 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
Type *type = ir_type(array_ptr);
|
Type *type = ir_type(array_ptr);
|
||||||
GB_ASSERT(is_type_pointer(type));
|
GB_ASSERT(is_type_pointer(type));
|
||||||
type = base_type(type_deref(type));
|
type = base_type(type_deref(type));
|
||||||
GB_ASSERT(is_type_dynamic_array(type));
|
Type *elem_type = NULL;
|
||||||
Type *elem_type = type->DynamicArray.elem;
|
bool is_slice = false;
|
||||||
|
if (is_type_dynamic_array(type)) {
|
||||||
|
elem_type = type->DynamicArray.elem;
|
||||||
|
} else if (is_type_slice(type)) {
|
||||||
|
is_slice = true;
|
||||||
|
elem_type = type->Slice.elem;
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Invalid type to append");
|
||||||
|
}
|
||||||
|
|
||||||
irValue *elem_size = ir_make_const_int(a, type_size_of(a, elem_type));
|
irValue *elem_size = ir_make_const_int(a, type_size_of(a, elem_type));
|
||||||
irValue *elem_align = ir_make_const_int(a, type_align_of(a, elem_type));
|
irValue *elem_align = ir_make_const_int(a, type_align_of(a, elem_type));
|
||||||
@@ -3361,10 +3400,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
}
|
}
|
||||||
|
|
||||||
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
|
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
|
||||||
irValue *slice_elem = ir_emit_struct_ep(proc, slice, 0);
|
|
||||||
ir_emit_store(proc, slice_elem, base_elem);
|
|
||||||
irValue *len = ir_make_const_int(a, slice_len);
|
irValue *len = ir_make_const_int(a, slice_len);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
|
ir_fill_slice(proc, slice, base_elem, len, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_count = 2;
|
arg_count = 2;
|
||||||
@@ -3381,6 +3418,10 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
daa_args[2] = elem_align;
|
daa_args[2] = elem_align;
|
||||||
daa_args[3] = ir_emit_conv(proc, items, t_rawptr);
|
daa_args[3] = ir_emit_conv(proc, items, t_rawptr);
|
||||||
daa_args[4] = ir_emit_conv(proc, item_count, t_int);
|
daa_args[4] = ir_emit_conv(proc, item_count, t_int);
|
||||||
|
|
||||||
|
if (is_slice) {
|
||||||
|
return ir_emit_global_call(proc, "__slice_append", daa_args, 5);
|
||||||
|
}
|
||||||
return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
|
return ir_emit_global_call(proc, "__dynamic_array_append", daa_args, 5);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -3526,8 +3567,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
|
|
||||||
Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ir_type(ptr)));
|
Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ir_type(ptr)));
|
||||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), ptr);
|
ir_fill_slice(proc, slice, ptr, count, count);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), count);
|
|
||||||
return ir_emit_load(proc, slice);
|
return ir_emit_load(proc, slice);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -3544,9 +3584,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr);
|
irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr);
|
||||||
irValue *count = ir_slice_count(proc, s);
|
irValue *count = ir_slice_count(proc, s);
|
||||||
count = ir_emit_arith(proc, Token_Mul, count, ir_make_const_int(proc->module->allocator, elem_size), t_int);
|
count = ir_emit_arith(proc, Token_Mul, count, ir_make_const_int(proc->module->allocator, elem_size), t_int);
|
||||||
|
ir_fill_slice(proc, slice, ptr, count, count);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), ptr);
|
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), count);
|
|
||||||
return ir_emit_load(proc, slice);
|
return ir_emit_load(proc, slice);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -3669,11 +3707,9 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
|||||||
ir_emit_store(proc, addr, args[i]);
|
ir_emit_store(proc, addr, args[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
|
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
|
||||||
irValue *slice_elem = ir_emit_struct_ep(proc, slice, 0);
|
|
||||||
ir_emit_store(proc, slice_elem, base_elem);
|
|
||||||
irValue *len = ir_make_const_int(allocator, slice_len);
|
irValue *len = ir_make_const_int(allocator, slice_len);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
|
ir_fill_slice(proc, slice, base_elem, len, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_count = type->param_count;
|
arg_count = type->param_count;
|
||||||
@@ -4064,9 +4100,11 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
gbAllocator a = proc->module->allocator;
|
gbAllocator a = proc->module->allocator;
|
||||||
irValue *low = v_zero;
|
irValue *low = v_zero;
|
||||||
irValue *high = NULL;
|
irValue *high = NULL;
|
||||||
|
irValue *max = NULL;
|
||||||
|
|
||||||
if (se->low != NULL) low = ir_build_expr(proc, se->low);
|
if (se->low != NULL) low = ir_build_expr(proc, se->low);
|
||||||
if (se->high != NULL) high = ir_build_expr(proc, se->high);
|
if (se->high != NULL) high = ir_build_expr(proc, se->high);
|
||||||
|
if (se->max != NULL) max = ir_build_expr(proc, se->max);
|
||||||
irValue *addr = ir_build_addr(proc, se->expr).addr;
|
irValue *addr = ir_build_addr(proc, se->expr).addr;
|
||||||
irValue *base = ir_emit_load(proc, addr);
|
irValue *base = ir_emit_load(proc, addr);
|
||||||
Type *type = base_type(ir_type(base));
|
Type *type = base_type(ir_type(base));
|
||||||
@@ -4084,16 +4122,15 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
Type *slice_type = type;
|
Type *slice_type = type;
|
||||||
|
|
||||||
if (high == NULL) high = ir_slice_count(proc, base);
|
if (high == NULL) high = ir_slice_count(proc, base);
|
||||||
|
if (max == NULL) max = ir_slice_capacity(proc, base);
|
||||||
|
|
||||||
ir_emit_slice_bounds_check(proc, se->open, low, high, false);
|
ir_emit_slice_bounds_check(proc, se->open, low, high, max, false);
|
||||||
|
|
||||||
irValue *elem = ir_emit_ptr_offset(proc, ir_slice_elem(proc, base), low);
|
irValue *elem = ir_emit_ptr_offset(proc, ir_slice_elem(proc, base), low);
|
||||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||||
|
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||||
|
ir_fill_slice(proc, slice, elem, len, cap);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem);
|
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
|
|
||||||
|
|
||||||
return ir_make_addr(slice);
|
return ir_make_addr(slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4101,16 +4138,15 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
Type *dynamic_array = type;
|
Type *dynamic_array = type;
|
||||||
|
|
||||||
if (high == NULL) high = ir_dynamic_array_count(proc, base);
|
if (high == NULL) high = ir_dynamic_array_count(proc, base);
|
||||||
|
if (max == NULL) max = ir_dynamic_array_capacity(proc, base);
|
||||||
|
|
||||||
ir_emit_slice_bounds_check(proc, se->open, low, high, false);
|
ir_emit_slice_bounds_check(proc, se->open, low, high, max, false);
|
||||||
|
|
||||||
irValue *elem = ir_emit_ptr_offset(proc, ir_dynamic_array_elem(proc, base), low);
|
irValue *elem = ir_emit_ptr_offset(proc, ir_dynamic_array_elem(proc, base), low);
|
||||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||||
|
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||||
irValue *slice = ir_add_local_generated(proc, dynamic_array);
|
irValue *slice = ir_add_local_generated(proc, dynamic_array);
|
||||||
|
ir_fill_slice(proc, slice, elem, len, cap);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem);
|
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
|
|
||||||
|
|
||||||
return ir_make_addr(slice);
|
return ir_make_addr(slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4119,38 +4155,31 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
Type *slice_type = make_type_slice(a, type->Array.elem);
|
Type *slice_type = make_type_slice(a, type->Array.elem);
|
||||||
|
|
||||||
if (high == NULL) high = ir_array_len(proc, base);
|
if (high == NULL) high = ir_array_len(proc, base);
|
||||||
|
if (max == NULL) max = ir_array_len(proc, base);
|
||||||
|
|
||||||
ir_emit_slice_bounds_check(proc, se->open, low, high, false);
|
ir_emit_slice_bounds_check(proc, se->open, low, high, max, false);
|
||||||
|
|
||||||
irValue *elem = ir_emit_ptr_offset(proc, ir_array_elem(proc, addr), low);
|
irValue *elem = ir_emit_ptr_offset(proc, ir_array_elem(proc, addr), low);
|
||||||
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||||
|
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
|
||||||
irValue *slice = ir_add_local_generated(proc, slice_type);
|
irValue *slice = ir_add_local_generated(proc, slice_type);
|
||||||
|
ir_fill_slice(proc, slice, elem, len, cap);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem);
|
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
|
|
||||||
|
|
||||||
return ir_make_addr(slice);
|
return ir_make_addr(slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type_Basic: {
|
case Type_Basic: {
|
||||||
GB_ASSERT(type == t_string);
|
GB_ASSERT(type == t_string);
|
||||||
if (high == NULL) {
|
if (high == NULL) high = ir_string_len(proc, base);
|
||||||
high = ir_string_len(proc, base);
|
if (max == NULL) max = ir_string_len(proc, base);
|
||||||
}
|
|
||||||
|
|
||||||
ir_emit_slice_bounds_check(proc, se->open, low, high, true);
|
ir_emit_slice_bounds_check(proc, se->open, low, high, max, true);
|
||||||
|
|
||||||
irValue *elem, *len;
|
irValue *elem = ir_emit_ptr_offset(proc, ir_string_elem(proc, base), low);
|
||||||
len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
|
||||||
|
|
||||||
elem = ir_string_elem(proc, base);
|
|
||||||
elem = ir_emit_ptr_offset(proc, elem, low);
|
|
||||||
|
|
||||||
irValue *str = ir_add_local_generated(proc, t_string);
|
irValue *str = ir_add_local_generated(proc, t_string);
|
||||||
irValue *gep0 = ir_emit_struct_ep(proc, str, 0);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, str, 0), elem);
|
||||||
irValue *gep1 = ir_emit_struct_ep(proc, str, 1);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, str, 1), len);
|
||||||
ir_emit_store(proc, gep0, elem);
|
|
||||||
ir_emit_store(proc, gep1, len);
|
|
||||||
|
|
||||||
return ir_make_addr(str);
|
return ir_make_addr(str);
|
||||||
} break;
|
} break;
|
||||||
@@ -4357,13 +4386,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
ir_emit_store(proc, offset, ev);
|
ir_emit_store(proc, offset, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
|
irValue *count = ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count);
|
||||||
irValue *gep1 = ir_emit_struct_ep(proc, v, 1);
|
ir_fill_slice(proc, v, data, count, count);
|
||||||
irValue *gep2 = ir_emit_struct_ep(proc, v, 1);
|
|
||||||
|
|
||||||
ir_emit_store(proc, gep0, data);
|
|
||||||
ir_emit_store(proc, gep1, ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
|
|
||||||
ir_emit_store(proc, gep2, ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -4730,8 +4754,7 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type
|
|||||||
|
|
||||||
TokenKind op = Token_Lt;
|
TokenKind op = Token_Lt;
|
||||||
switch (node->op.kind) {
|
switch (node->op.kind) {
|
||||||
case Token_HalfOpenRange: op = Token_Lt; break;
|
case Token_Ellipsis: op = Token_Lt; break;
|
||||||
case Token_Ellipsis: op = Token_LtEq; break;
|
|
||||||
default: GB_PANIC("Invalid interval operator"); break;
|
default: GB_PANIC("Invalid interval operator"); break;
|
||||||
}
|
}
|
||||||
irValue *cond = ir_emit_comp(proc, op, ir_emit_load(proc, value), upper);
|
irValue *cond = ir_emit_comp(proc, op, ir_emit_load(proc, value), upper);
|
||||||
@@ -4769,6 +4792,15 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
|||||||
ir_build_when_stmt(proc, ws);
|
ir_build_when_stmt(proc, ws);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(s, IncDecStmt, node);
|
||||||
|
TokenKind op = Token_Add;
|
||||||
|
if (s->op.kind == Token_Dec) {
|
||||||
|
op = Token_Sub;
|
||||||
|
}
|
||||||
|
irAddr addr = ir_build_addr(proc, s->expr);
|
||||||
|
ir_build_assign_op(proc, addr, v_one, op);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(vd, ValueDecl, node);
|
case_ast_node(vd, ValueDecl, node);
|
||||||
if (vd->is_var) {
|
if (vd->is_var) {
|
||||||
irModule *m = proc->module;
|
irModule *m = proc->module;
|
||||||
@@ -6010,16 +6042,6 @@ void ir_add_foreign_library_path(irModule *m, Entity *e) {
|
|||||||
array_add(&m->foreign_library_paths, library_path);
|
array_add(&m->foreign_library_paths, library_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ir_fill_slice(irProcedure *proc, irValue *slice_ptr, irValue *data, irValue *count) {
|
|
||||||
Type *t = ir_type(slice_ptr);
|
|
||||||
GB_ASSERT(is_type_pointer(t));
|
|
||||||
t = type_deref(t);
|
|
||||||
GB_ASSERT(is_type_slice(t));
|
|
||||||
irValue *elem = ir_emit_struct_ep(proc, slice_ptr, 0);
|
|
||||||
irValue *len = ir_emit_struct_ep(proc, slice_ptr, 1);
|
|
||||||
ir_emit_store(proc, elem, data);
|
|
||||||
ir_emit_store(proc, len, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ir_gen_tree(irGen *s) {
|
void ir_gen_tree(irGen *s) {
|
||||||
irModule *m = &s->module;
|
irModule *m = &s->module;
|
||||||
@@ -6356,9 +6378,10 @@ void ir_gen_tree(irGen *s) {
|
|||||||
irValue *global_type_table = ir_find_global_variable(proc, str_lit("__type_table"));
|
irValue *global_type_table = ir_find_global_variable(proc, str_lit("__type_table"));
|
||||||
Type *type = base_type(type_deref(ir_type(ir_global_type_info_data)));
|
Type *type = base_type(type_deref(ir_type(ir_global_type_info_data)));
|
||||||
GB_ASSERT(is_type_array(type));
|
GB_ASSERT(is_type_array(type));
|
||||||
|
irValue *len = ir_make_const_int(proc->module->allocator, type->Array.count);
|
||||||
ir_fill_slice(proc, global_type_table,
|
ir_fill_slice(proc, global_type_table,
|
||||||
ir_emit_array_epi(proc, ir_global_type_info_data, 0),
|
ir_emit_array_epi(proc, ir_global_type_info_data, 0),
|
||||||
ir_make_const_int(proc->module->allocator, type->Array.count));
|
len, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -6542,8 +6565,9 @@ void ir_gen_tree(irGen *s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Tuple.variable_count));
|
irValue *count = ir_make_const_int(a, t->Tuple.variable_count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Tuple.variable_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count);
|
||||||
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count);
|
||||||
} break;
|
} break;
|
||||||
case Type_Record: {
|
case Type_Record: {
|
||||||
switch (t->Record.kind) {
|
switch (t->Record.kind) {
|
||||||
@@ -6589,9 +6613,10 @@ void ir_gen_tree(irGen *s) {
|
|||||||
ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
|
ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
irValue *count = ir_make_const_int(a, t->Record.field_count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count);
|
||||||
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count);
|
||||||
} break;
|
} break;
|
||||||
case TypeRecord_Union: {
|
case TypeRecord_Union: {
|
||||||
ir_emit_comment(proc, str_lit("Type_Info_Union"));
|
ir_emit_comment(proc, str_lit("Type_Info_Union"));
|
||||||
@@ -6632,9 +6657,10 @@ void ir_gen_tree(irGen *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types, ir_make_const_int(a, field_count));
|
irValue *count = ir_make_const_int(a, field_count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names, ir_make_const_int(a, field_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types, count, count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, ir_make_const_int(a, field_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names, count, count);
|
||||||
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, count, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -6661,9 +6687,8 @@ void ir_gen_tree(irGen *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
irValue *count = ir_make_const_int(a, variant_count);
|
irValue *count = ir_make_const_int(a, variant_count);
|
||||||
|
ir_fill_slice(proc, variant_names, memory_names, count, count);
|
||||||
ir_fill_slice(proc, variant_names, memory_names, count);
|
ir_fill_slice(proc, variant_types, memory_types, count, count);
|
||||||
ir_fill_slice(proc, variant_types, memory_types, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
@@ -6696,9 +6721,10 @@ void ir_gen_tree(irGen *s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, ir_make_const_int(a, t->Record.field_count));
|
irValue *count = ir_make_const_int(a, t->Record.field_count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, ir_make_const_int(a, t->Record.field_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, ir_make_const_int(a, t->Record.field_count));
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count);
|
||||||
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count);
|
||||||
} break;
|
} break;
|
||||||
case TypeRecord_Enum:
|
case TypeRecord_Enum:
|
||||||
ir_emit_comment(proc, str_lit("Type_Info_Enum"));
|
ir_emit_comment(proc, str_lit("Type_Info_Enum"));
|
||||||
|
|||||||
+8
-1
@@ -191,7 +191,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
ir_fprintf(f, "{");
|
ir_fprintf(f, "{");
|
||||||
ir_print_type(f, m, t->Slice.elem);
|
ir_print_type(f, m, t->Slice.elem);
|
||||||
ir_fprintf(f, "*, i%lld}", word_bits);
|
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
|
||||||
return;
|
return;
|
||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
ir_fprintf(f, "{");
|
ir_fprintf(f, "{");
|
||||||
@@ -1249,6 +1249,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
ir_fprintf(f, " ");
|
ir_fprintf(f, " ");
|
||||||
ir_print_value(f, m, bc->high, t_int);
|
ir_print_value(f, m, bc->high, t_int);
|
||||||
|
|
||||||
|
if (!bc->is_substring) {
|
||||||
|
ir_fprintf(f, ", ");
|
||||||
|
ir_print_type(f, m, t_int);
|
||||||
|
ir_fprintf(f, " ");
|
||||||
|
ir_print_value(f, m, bc->max, t_int);
|
||||||
|
}
|
||||||
|
|
||||||
ir_fprintf(f, ")\n");
|
ir_fprintf(f, ")\n");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|||||||
+54
-19
@@ -151,8 +151,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
|
|||||||
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(SliceExpr, "slice expression", struct { \
|
AST_NODE_KIND(SliceExpr, "slice expression", struct { \
|
||||||
AstNode *expr; \
|
AstNode *expr; \
|
||||||
Token open, close, interval; \
|
Token open, close; \
|
||||||
AstNode *low, *high; \
|
bool index3; \
|
||||||
|
AstNode *low, *high, *max; \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
||||||
AstNode * proc; \
|
AstNode * proc; \
|
||||||
@@ -186,6 +187,10 @@ AST_NODE_KIND(_StmtBegin, "", i32) \
|
|||||||
Token op; \
|
Token op; \
|
||||||
AstNodeArray lhs, rhs; \
|
AstNodeArray lhs, rhs; \
|
||||||
}) \
|
}) \
|
||||||
|
AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \
|
||||||
|
Token op; \
|
||||||
|
AstNode *expr; \
|
||||||
|
}) \
|
||||||
AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
|
AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
|
||||||
AST_NODE_KIND(BlockStmt, "block statement", struct { \
|
AST_NODE_KIND(BlockStmt, "block statement", struct { \
|
||||||
AstNodeArray stmts; \
|
AstNodeArray stmts; \
|
||||||
@@ -467,6 +472,7 @@ Token ast_node_token(AstNode *node) {
|
|||||||
case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr);
|
case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr);
|
||||||
case AstNode_TagStmt: return node->TagStmt.token;
|
case AstNode_TagStmt: return node->TagStmt.token;
|
||||||
case AstNode_AssignStmt: return node->AssignStmt.op;
|
case AstNode_AssignStmt: return node->AssignStmt.op;
|
||||||
|
case AstNode_IncDecStmt: return ast_node_token(node->IncDecStmt.expr);
|
||||||
case AstNode_BlockStmt: return node->BlockStmt.open;
|
case AstNode_BlockStmt: return node->BlockStmt.open;
|
||||||
case AstNode_IfStmt: return node->IfStmt.token;
|
case AstNode_IfStmt: return node->IfStmt.token;
|
||||||
case AstNode_WhenStmt: return node->WhenStmt.token;
|
case AstNode_WhenStmt: return node->WhenStmt.token;
|
||||||
@@ -662,14 +668,15 @@ AstNode *ast_index_expr(AstFile *f, AstNode *expr, AstNode *index, Token open, T
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, Token interval, AstNode *low, AstNode *high) {
|
AstNode *ast_slice_expr(AstFile *f, AstNode *expr, Token open, Token close, bool index3, AstNode *low, AstNode *high, AstNode *max) {
|
||||||
AstNode *result = make_ast_node(f, AstNode_SliceExpr);
|
AstNode *result = make_ast_node(f, AstNode_SliceExpr);
|
||||||
result->SliceExpr.expr = expr;
|
result->SliceExpr.expr = expr;
|
||||||
result->SliceExpr.open = open;
|
result->SliceExpr.open = open;
|
||||||
result->SliceExpr.close = close;
|
result->SliceExpr.close = close;
|
||||||
result->SliceExpr.interval = interval;
|
result->SliceExpr.index3 = index3;
|
||||||
result->SliceExpr.low = low;
|
result->SliceExpr.low = low;
|
||||||
result->SliceExpr.high = high;
|
result->SliceExpr.high = high;
|
||||||
|
result->SliceExpr.max = max;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,6 +809,16 @@ AstNode *ast_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rh
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AstNode *ast_inc_dec_stmt(AstFile *f, Token op, AstNode *expr) {
|
||||||
|
AstNode *result = make_ast_node(f, AstNode_IncDecStmt);
|
||||||
|
result->IncDecStmt.op = op;
|
||||||
|
result->IncDecStmt.expr = expr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AstNode *ast_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) {
|
AstNode *ast_block_stmt(AstFile *f, AstNodeArray stmts, Token open, Token close) {
|
||||||
AstNode *result = make_ast_node(f, AstNode_BlockStmt);
|
AstNode *result = make_ast_node(f, AstNode_BlockStmt);
|
||||||
result->BlockStmt.stmts = stmts;
|
result->BlockStmt.stmts = stmts;
|
||||||
@@ -1930,37 +1947,49 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
|||||||
// TODO(bill): Handle this
|
// TODO(bill): Handle this
|
||||||
}
|
}
|
||||||
Token open = {0}, close = {0}, interval = {0};
|
Token open = {0}, close = {0}, interval = {0};
|
||||||
AstNode *indices[2] = {0};
|
AstNode *indices[3] = {0};
|
||||||
|
isize ellipsis_count = 0;
|
||||||
|
Token ellipses[2] = {0};
|
||||||
|
|
||||||
f->expr_level++;
|
f->expr_level++;
|
||||||
open = expect_token(f, Token_OpenBracket);
|
open = expect_token(f, Token_OpenBracket);
|
||||||
|
|
||||||
// if (f->curr_token.kind != Token_Ellipsis &&
|
if (f->curr_token.kind != Token_Ellipsis) {
|
||||||
// f->curr_token.kind != Token_HalfOpenRange) {
|
|
||||||
if (f->curr_token.kind != Token_Colon) {
|
|
||||||
indices[0] = parse_expr(f, false);
|
indices[0] = parse_expr(f, false);
|
||||||
}
|
}
|
||||||
bool is_index = true;
|
bool is_index = true;
|
||||||
|
|
||||||
// if (f->curr_token.kind == Token_Ellipsis ||
|
while (f->curr_token.kind == Token_Ellipsis && ellipsis_count < gb_count_of(ellipses)) {
|
||||||
// f->curr_token.kind == Token_HalfOpenRange) {
|
ellipses[ellipsis_count++] = f->curr_token;
|
||||||
if (f->curr_token.kind == Token_Colon) {
|
|
||||||
is_index = false;
|
|
||||||
interval = f->curr_token;
|
|
||||||
next_token(f);
|
next_token(f);
|
||||||
if (f->curr_token.kind != Token_CloseBracket &&
|
if (f->curr_token.kind != Token_Ellipsis &&
|
||||||
|
f->curr_token.kind != Token_CloseBracket &&
|
||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
indices[1] = parse_expr(f, false);
|
indices[ellipsis_count] = parse_expr(f, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
f->expr_level--;
|
f->expr_level--;
|
||||||
close = expect_token(f, Token_CloseBracket);
|
close = expect_token(f, Token_CloseBracket);
|
||||||
|
|
||||||
if (is_index) {
|
if (ellipsis_count > 0) {
|
||||||
operand = ast_index_expr(f, operand, indices[0], open, close);
|
bool index3 = false;
|
||||||
|
if (ellipsis_count == 2) {
|
||||||
|
index3 = true;
|
||||||
|
// 2nd and 3rd index must be present
|
||||||
|
if (indices[1] == NULL) {
|
||||||
|
error(ellipses[0], "2nd index required in 3-index slice expression");
|
||||||
|
indices[1] = ast_bad_expr(f, ellipses[0], ellipses[1]);
|
||||||
|
}
|
||||||
|
if (indices[2] == NULL) {
|
||||||
|
error(ellipses[1], "3rd index required in 3-index slice expression");
|
||||||
|
indices[2] = ast_bad_expr(f, ellipses[1], close);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
operand = ast_slice_expr(f, operand, open, close, index3, indices[0], indices[1], indices[2]);
|
||||||
} else {
|
} else {
|
||||||
operand = ast_slice_expr(f, operand, open, close, interval, indices[0], indices[1]);
|
operand = ast_index_expr(f, operand, indices[0], open, close);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -2246,7 +2275,6 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
|
|||||||
allow_token(f, Token_in);
|
allow_token(f, Token_in);
|
||||||
AstNode *expr = parse_expr(f, false);
|
AstNode *expr = parse_expr(f, false);
|
||||||
switch (f->curr_token.kind) {
|
switch (f->curr_token.kind) {
|
||||||
case Token_HalfOpenRange:
|
|
||||||
case Token_Ellipsis: {
|
case Token_Ellipsis: {
|
||||||
Token op = f->curr_token;
|
Token op = f->curr_token;
|
||||||
next_token(f);
|
next_token(f);
|
||||||
@@ -2272,6 +2300,13 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
|
|||||||
return ast_bad_stmt(f, token, f->curr_token);
|
return ast_bad_stmt(f, token, f->curr_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (token.kind) {
|
||||||
|
case Token_Inc:
|
||||||
|
case Token_Dec:
|
||||||
|
next_token(f);
|
||||||
|
return ast_inc_dec_stmt(f, token, lhs.e[0]);
|
||||||
|
}
|
||||||
|
|
||||||
return ast_expr_stmt(f, lhs.e[0]);
|
return ast_expr_stmt(f, lhs.e[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+40
-18
@@ -51,8 +51,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \
|
|||||||
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \
|
||||||
TOKEN_KIND(Token_ArrowRight, "->"), \
|
TOKEN_KIND(Token_ArrowRight, "->"), \
|
||||||
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
TOKEN_KIND(Token_ArrowLeft, "<-"), \
|
||||||
TOKEN_KIND(Token_Increment, "++"), \
|
TOKEN_KIND(Token_Inc, "++"), \
|
||||||
TOKEN_KIND(Token_Decrement, "--"), \
|
TOKEN_KIND(Token_Dec, "--"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \
|
||||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||||
@@ -73,8 +73,8 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
|||||||
TOKEN_KIND(Token_Semicolon, ";"), \
|
TOKEN_KIND(Token_Semicolon, ";"), \
|
||||||
TOKEN_KIND(Token_Period, "."), \
|
TOKEN_KIND(Token_Period, "."), \
|
||||||
TOKEN_KIND(Token_Comma, ","), \
|
TOKEN_KIND(Token_Comma, ","), \
|
||||||
TOKEN_KIND(Token_Ellipsis, "..."), \
|
TOKEN_KIND(Token_Ellipsis, ".."), \
|
||||||
TOKEN_KIND(Token_HalfOpenRange, "..<"), \
|
/* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \
|
||||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||||
\
|
\
|
||||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||||
@@ -225,6 +225,23 @@ void syntax_error_va(Token token, char *fmt, va_list va) {
|
|||||||
gb_mutex_unlock(&global_error_collector.mutex);
|
gb_mutex_unlock(&global_error_collector.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syntax_warning_va(Token token, char *fmt, va_list va) {
|
||||||
|
gb_mutex_lock(&global_error_collector.mutex);
|
||||||
|
global_error_collector.warning_count++;
|
||||||
|
// NOTE(bill): Duplicate error, skip it
|
||||||
|
if (!token_pos_eq(global_error_collector.prev, token.pos)) {
|
||||||
|
global_error_collector.prev = token.pos;
|
||||||
|
gb_printf_err("%.*s(%td:%td) Syntax Warning: %s\n",
|
||||||
|
LIT(token.pos.file), token.pos.line, token.pos.column,
|
||||||
|
gb_bprintf_va(fmt, va));
|
||||||
|
} else if (token.pos.line == 0) {
|
||||||
|
gb_printf_err("Warning: %s\n", gb_bprintf_va(fmt, va));
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_mutex_unlock(&global_error_collector.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void warning(Token token, char *fmt, ...) {
|
void warning(Token token, char *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
@@ -247,6 +264,13 @@ void syntax_error(Token token, char *fmt, ...) {
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syntax_warning(Token token, char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
syntax_warning_va(token, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void compiler_error(char *fmt, ...) {
|
void compiler_error(char *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
@@ -834,13 +858,11 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
token.kind = Token_Period; // Default
|
token.kind = Token_Period; // Default
|
||||||
if (t->curr_rune == '.') { // Could be an ellipsis
|
if (t->curr_rune == '.') { // Could be an ellipsis
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
if (t->curr_rune == '<') {
|
token.kind = Token_Ellipsis;
|
||||||
advance_to_next_rune(t);
|
// if (t->curr_rune == '<') {
|
||||||
token.kind = Token_HalfOpenRange;
|
// advance_to_next_rune(t);
|
||||||
} else if (t->curr_rune == '.') {
|
// token.kind = Token_HalfOpenRange;
|
||||||
advance_to_next_rune(t);
|
// }
|
||||||
token.kind = Token_Ellipsis;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -859,13 +881,13 @@ Token tokenizer_get_token(Tokenizer *t) {
|
|||||||
case '{': token.kind = Token_OpenBrace; break;
|
case '{': token.kind = Token_OpenBrace; break;
|
||||||
case '}': token.kind = Token_CloseBrace; break;
|
case '}': token.kind = Token_CloseBrace; break;
|
||||||
|
|
||||||
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break;
|
||||||
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
|
case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break;
|
||||||
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break;
|
||||||
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break;
|
||||||
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break;
|
||||||
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break;
|
case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break;
|
||||||
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break;
|
case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break;
|
||||||
case '/': {
|
case '/': {
|
||||||
if (t->curr_rune == '/') {
|
if (t->curr_rune == '/') {
|
||||||
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
|
while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) {
|
||||||
|
|||||||
+24
-11
@@ -1090,6 +1090,7 @@ gb_global Entity *entity__any_data = NULL;
|
|||||||
gb_global Entity *entity__string_data = NULL;
|
gb_global Entity *entity__string_data = NULL;
|
||||||
gb_global Entity *entity__string_count = NULL;
|
gb_global Entity *entity__string_count = NULL;
|
||||||
gb_global Entity *entity__slice_count = NULL;
|
gb_global Entity *entity__slice_count = NULL;
|
||||||
|
gb_global Entity *entity__slice_capacity = NULL;
|
||||||
|
|
||||||
gb_global Entity *entity__dynamic_array_count = NULL;
|
gb_global Entity *entity__dynamic_array_count = NULL;
|
||||||
gb_global Entity *entity__dynamic_array_capacity = NULL;
|
gb_global Entity *entity__dynamic_array_capacity = NULL;
|
||||||
@@ -1251,6 +1252,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
} else if (type->kind == Type_Slice) {
|
} else if (type->kind == Type_Slice) {
|
||||||
String data_str = str_lit("data");
|
String data_str = str_lit("data");
|
||||||
String count_str = str_lit("count");
|
String count_str = str_lit("count");
|
||||||
|
String capacity_str = str_lit("capacity");
|
||||||
|
|
||||||
if (str_eq(field_name, data_str)) {
|
if (str_eq(field_name, data_str)) {
|
||||||
selection_add_index(&sel, 0);
|
selection_add_index(&sel, 0);
|
||||||
@@ -1265,7 +1267,16 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
|
|
||||||
sel.entity = entity__slice_count;
|
sel.entity = entity__slice_count;
|
||||||
return sel;
|
return sel;
|
||||||
|
} else if (str_eq(field_name, capacity_str)) {
|
||||||
|
selection_add_index(&sel, 2);
|
||||||
|
if (entity__slice_capacity == NULL) {
|
||||||
|
entity__slice_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
sel.entity = entity__slice_capacity;
|
||||||
|
return sel;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (type->kind == Type_DynamicArray) {
|
} else if (type->kind == Type_DynamicArray) {
|
||||||
String data_str = str_lit("data");
|
String data_str = str_lit("data");
|
||||||
String count_str = str_lit("count");
|
String count_str = str_lit("count");
|
||||||
@@ -1779,7 +1790,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
|||||||
|
|
||||||
|
|
||||||
case Type_Slice: // ptr + count
|
case Type_Slice: // ptr + count
|
||||||
return 2 * build_context.word_size;
|
return 3 * build_context.word_size;
|
||||||
|
|
||||||
case Type_Map: {
|
case Type_Map: {
|
||||||
if (t->Map.count == 0) { // Dynamic
|
if (t->Map.count == 0) { // Dynamic
|
||||||
@@ -1875,23 +1886,24 @@ i64 type_offset_of(gbAllocator allocator, Type *t, i32 index) {
|
|||||||
} else if (t->kind == Type_Basic) {
|
} else if (t->kind == Type_Basic) {
|
||||||
if (t->Basic.kind == Basic_string) {
|
if (t->Basic.kind == Basic_string) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return 0; // data
|
case 0: return 0; // data
|
||||||
case 1: return build_context.word_size; // count
|
case 1: return build_context.word_size; // count
|
||||||
}
|
}
|
||||||
} else if (t->Basic.kind == Basic_any) {
|
} else if (t->Basic.kind == Basic_any) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return 0; // type_info
|
case 0: return 0; // type_info
|
||||||
case 1: return build_context.word_size; // data
|
case 1: return build_context.word_size; // data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (t->kind == Type_Slice) {
|
} else if (t->kind == Type_Slice) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return 0; // data
|
case 0: return 0; // data
|
||||||
case 1: return 1*build_context.word_size; // count
|
case 1: return 1*build_context.word_size; // count
|
||||||
|
case 2: return 2*build_context.word_size; // capacity
|
||||||
}
|
}
|
||||||
} else if (t->kind == Type_DynamicArray) {
|
} else if (t->kind == Type_DynamicArray) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return 0; // data
|
case 0: return 0; // data
|
||||||
case 1: return 1*build_context.word_size; // count
|
case 1: return 1*build_context.word_size; // count
|
||||||
case 2: return 2*build_context.word_size; // capacity
|
case 2: return 2*build_context.word_size; // capacity
|
||||||
case 3: return 3*build_context.word_size; // allocator
|
case 3: return 3*build_context.word_size; // allocator
|
||||||
@@ -1928,6 +1940,13 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Type_Slice:
|
||||||
|
switch (index) {
|
||||||
|
case 0: t = t_rawptr; break;
|
||||||
|
case 1: t = t_int; break;
|
||||||
|
case 2: t = t_int; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: t = t_rawptr; break;
|
case 0: t = t_rawptr; break;
|
||||||
@@ -1936,12 +1955,6 @@ i64 type_offset_of_from_selection(gbAllocator allocator, Type *type, Selection s
|
|||||||
case 3: t = t_allocator; break;
|
case 3: t = t_allocator; break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type_Slice:
|
|
||||||
switch (index) {
|
|
||||||
case 0: t = t_rawptr; break;
|
|
||||||
case 1: t = t_int; break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user