diff options
| author | Zachary Pierson <zacpiersonhehe@gmail.com> | 2017-02-27 23:25:47 -0600 |
|---|---|---|
| committer | Zachary Pierson <zacpiersonhehe@gmail.com> | 2017-02-27 23:25:47 -0600 |
| commit | 231ea8b0264e8b6d47278f01fb7c31b8562c2bbb (patch) | |
| tree | e483189c84fcea9763e2fa0386e98ef5ca9a420b | |
| parent | 5bbdb3a3a3ab6c821141190e052db9fdb2961734 (diff) | |
| parent | 9bc37f44002d89ed35643b2bfd8c384cb5ff1f48 (diff) | |
Merge https://github.com/gingerBill/Odin
| -rw-r--r-- | code/demo.odin | 17 | ||||
| -rw-r--r-- | core/_preload.odin | 41 | ||||
| -rw-r--r-- | core/atomic.odin | 4 | ||||
| -rw-r--r-- | core/decimal.odin | 257 | ||||
| -rw-r--r-- | core/fmt.odin | 677 | ||||
| -rw-r--r-- | core/hash.odin | 10 | ||||
| -rw-r--r-- | core/math.odin | 8 | ||||
| -rw-r--r-- | core/mem.odin | 10 | ||||
| -rw-r--r-- | core/os_windows.odin | 6 | ||||
| -rw-r--r-- | core/strconv.odin | 336 | ||||
| -rw-r--r-- | core/strings.odin | 2 | ||||
| -rw-r--r-- | core/sync.odin | 6 | ||||
| -rw-r--r-- | core/utf8.odin | 58 | ||||
| -rw-r--r-- | src/check_expr.c | 74 | ||||
| -rw-r--r-- | src/check_stmt.c | 52 | ||||
| -rw-r--r-- | src/exact_value.c | 7 | ||||
| -rw-r--r-- | src/ir.c | 216 | ||||
| -rw-r--r-- | src/ir_print.c | 9 | ||||
| -rw-r--r-- | src/parser.c | 73 | ||||
| -rw-r--r-- | src/tokenizer.c | 58 | ||||
| -rw-r--r-- | src/types.c | 35 |
21 files changed, 1360 insertions, 596 deletions
diff --git a/code/demo.odin b/code/demo.odin index c548a9430..8162fc0d3 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -5,14 +5,21 @@ #import "mem.odin"; #import "opengl.odin"; #import "os.odin"; - -foo :: proc(x: int) -> f32 { - return 123; -} +#import "strconv.odin"; 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 { /* diff --git a/core/_preload.odin b/core/_preload.odin index de01bb244..953d38c43 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -316,24 +316,24 @@ __bounds_check_error :: proc(file: string, line, column: int, index, count: int) if 0 <= index && index < count { 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); __debug_trap(); } -__slice_expr_error :: proc(file: string, line, column: int, low, high: int) { - if 0 <= low && low <= high { +__slice_expr_error :: proc(file: string, line, column: int, low, high, max: int) { + if 0 <= low && low <= high && high <= max { return; } - fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d:%d]\n", - file, line, column, low, high); + fmt.fprintf(os.stderr, "%s(%d:%d) Invalid slice indices: [%d..%d..%d]\n", + file, line, column, low, high, max); __debug_trap(); } __substring_expr_error :: proc(file: string, line, column: int, low, high: int) { if 0 <= low && low <= high { 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); __debug_trap(); } @@ -361,8 +361,9 @@ Raw_String :: struct #ordered { }; Raw_Slice :: struct #ordered { - data: rawptr, - count: int, + data: rawptr, + count: int, + capacity: int, }; 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; assert(data != nil); mem.zero(data + (elem_size*array.count), elem_size); - array.count += 1; + 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 @@ -506,7 +525,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { 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); 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 { - 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); last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key); diff --git a/core/atomic.odin b/core/atomic.odin index 3db437a4b..ec7900f0d 100644 --- a/core/atomic.odin +++ b/core/atomic.odin @@ -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); counter := 0; for old_value != 0 && (time_out < 0 || counter < time_out) { - counter += 1; + counter++; yield_thread(); old_value = compare_exchange(a, 1, 0); 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); counter := 0; for old_value != 0 && (time_out < 0 || counter < time_out) { - counter += 1; + counter++; yield_thread(); old_value = compare_exchange(a, 1, 0); mfence(); diff --git a/core/decimal.odin b/core/decimal.odin new file mode 100644 index 000000000..07031104b --- /dev/null +++ b/core/decimal.odin @@ -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; +} diff --git a/core/fmt.odin b/core/fmt.odin index 80517ee95..eb2353b72 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -2,41 +2,25 @@ #import "mem.odin"; #import "utf8.odin"; #import "types.odin"; +#import "strconv.odin"; _BUFFER_SIZE :: 1<<12; -Buffer :: struct { - data: []byte, - length: int, +write_string :: proc(buf: ^[]byte, s: string) { + append(buf^, ..cast([]byte)s); } - -buffer_write :: proc(buf: ^Buffer, b: []byte) { - if buf.length < buf.data.count { - n := min(buf.data.count-buf.length, b.count); - if n > 0 { - copy(buf.data[buf.length:], b[:n]); - buf.length += n; - } - } -} -buffer_write_string :: proc(buf: ^Buffer, s: string) { - buffer_write(buf, cast([]byte)s); -} -buffer_write_byte :: proc(buf: ^Buffer, b: byte) { - if buf.length < buf.data.count { - buf.data[buf.length] = b; - buf.length += 1; - } +write_byte :: proc(buf: ^[]byte, b: byte) { + append(buf^, b); } -buffer_write_rune :: proc(buf: ^Buffer, r: rune) { +write_rune :: proc(buf: ^[]byte, r: rune) { if r < utf8.RUNE_SELF { - buffer_write_byte(buf, cast(byte)r); + write_byte(buf, cast(byte)r); return; } b, n := utf8.encode_rune(r); - buffer_write(buf, b[:n]); + append(buf^, ..b[..n]); } Fmt_Info :: struct { @@ -54,55 +38,55 @@ Fmt_Info :: struct { reordered: bool, good_arg_index: bool, - buf: ^Buffer, + buf: ^[]byte, arg: any, // Temporary } -fprint :: proc(fd: os.Handle, args: ...any) -> int { +fprint :: proc(fd: os.Handle, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := Buffer{data[:], 0}; - bprint(^buf, ...args); - os.write(fd, buf.data[:buf.length]); - return buf.length; + buf := data[..0]; + bprint(^buf, ..args); + os.write(fd, buf[..buf.count]); + return buf.count; } -fprintln :: proc(fd: os.Handle, args: ...any) -> int { +fprintln :: proc(fd: os.Handle, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := Buffer{data[:], 0}; - bprintln(^buf, ...args); - os.write(fd, buf.data[:buf.length]); - return buf.length; + buf := data[..0]; + bprintln(^buf, ..args); + os.write(fd, buf[..buf.count]); + return buf.count; } -fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { data: [_BUFFER_SIZE]byte; - buf := Buffer{data[:], 0}; - bprintf(^buf, fmt, ...args); - os.write(fd, buf.data[:buf.length]); - return buf.length; + buf := data[..0]; + bprintf(^buf, fmt, ..args); + os.write(fd, buf[..buf.count]); + return buf.count; } -print :: proc(args: ...any) -> int { - return fprint(os.stdout, ...args); +print :: proc(args: ..any) -> int { + return fprint(os.stdout, ..args); } -println :: proc(args: ...any) -> int { - return fprintln(os.stdout, ...args); +println :: proc(args: ..any) -> int { + return fprintln(os.stdout, ..args); } -printf :: proc(fmt: string, args: ...any) -> int { - return fprintf(os.stdout, fmt, ...args); +printf :: proc(fmt: string, args: ..any) -> int { + return fprintf(os.stdout, fmt, ..args); } fprint_type :: proc(fd: os.Handle, info: ^Type_Info) { data: [_BUFFER_SIZE]byte; - buf := Buffer{data[:], 0}; - buffer_write_type(^buf, info); - os.write(fd, buf.data[:buf.length]); + buf := data[..0]; + write_type(^buf, info); + os.write(fd, buf[..buf.count]); } -buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { +write_type :: proc(buf: ^[]byte, ti: ^Type_Info) { if ti == nil { return; } @@ -110,176 +94,176 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { using Type_Info; match info in ti { case Named: - buffer_write_string(buf, info.name); + write_string(buf, info.name); case Integer: match { - case ti == type_info(int): buffer_write_string(buf, "int"); - case ti == type_info(uint): buffer_write_string(buf, "uint"); + case ti == type_info(int): write_string(buf, "int"); + case ti == type_info(uint): write_string(buf, "uint"); default: - buffer_write_string(buf, info.signed ? "i" : "u"); + write_string(buf, info.signed ? "i" : "u"); fi := Fmt_Info{buf = buf}; fmt_int(^fi, cast(u64)(8*info.size), false, 'd'); } case Float: match info.size { - case 4: buffer_write_string(buf, "f32"); - case 8: buffer_write_string(buf, "f64"); + case 4: write_string(buf, "f32"); + case 8: write_string(buf, "f64"); } - case String: buffer_write_string(buf, "string"); - case Boolean: buffer_write_string(buf, "bool"); + case String: write_string(buf, "string"); + case Boolean: write_string(buf, "bool"); case Pointer: if info.elem == nil { - buffer_write_string(buf, "rawptr"); + write_string(buf, "rawptr"); } else { - buffer_write_string(buf, "^"); - buffer_write_type(buf, info.elem); + write_string(buf, "^"); + write_type(buf, info.elem); } case Procedure: - buffer_write_string(buf, "proc"); + write_string(buf, "proc"); if info.params == nil { - buffer_write_string(buf, "()"); + write_string(buf, "()"); } else { t := union_cast(^Tuple)info.params; - buffer_write_string(buf, "("); + write_string(buf, "("); for type, i in t.types { - if i > 0 { buffer_write_string(buf, ", "); } - buffer_write_type(buf, type); + if i > 0 { write_string(buf, ", "); } + write_type(buf, type); } - buffer_write_string(buf, ")"); + write_string(buf, ")"); } if info.results != nil { - buffer_write_string(buf, " -> "); - buffer_write_type(buf, info.results); + write_string(buf, " -> "); + write_type(buf, info.results); } case Tuple: count := info.names.count; - if count != 1 { buffer_write_string(buf, "("); } + if count != 1 { write_string(buf, "("); } for name, i in info.names { - if i > 0 { buffer_write_string(buf, ", "); } + if i > 0 { write_string(buf, ", "); } type := info.types[i]; if name.count > 0 { - buffer_write_string(buf, name); - buffer_write_string(buf, ": "); + write_string(buf, name); + write_string(buf, ": "); } - buffer_write_type(buf, type); + write_type(buf, type); } - if count != 1 { buffer_write_string(buf, ")"); } + if count != 1 { write_string(buf, ")"); } case Array: - buffer_write_string(buf, "["); + write_string(buf, "["); fi := Fmt_Info{buf = buf}; fmt_int(^fi, cast(u64)info.count, false, 'd'); - buffer_write_string(buf, "]"); - buffer_write_type(buf, info.elem); + write_string(buf, "]"); + write_type(buf, info.elem); case Dynamic_Array: - buffer_write_string(buf, "[...]"); - buffer_write_type(buf, info.elem); + write_string(buf, "[..]"); + write_type(buf, info.elem); case Slice: - buffer_write_string(buf, "["); - buffer_write_string(buf, "]"); - buffer_write_type(buf, info.elem); + write_string(buf, "["); + write_string(buf, "]"); + write_type(buf, info.elem); case Vector: - buffer_write_string(buf, "[vector "); + write_string(buf, "[vector "); fi := Fmt_Info{buf = buf}; fmt_int(^fi, cast(u64)info.count, false, 'd'); - buffer_write_string(buf, "]"); - buffer_write_type(buf, info.elem); + write_string(buf, "]"); + write_type(buf, info.elem); case Map: - buffer_write_string(buf, "map["); - buffer_write_type(buf, info.key); - buffer_write_byte(buf, ']'); - buffer_write_type(buf, info.value); + write_string(buf, "map["); + write_type(buf, info.key); + write_byte(buf, ']'); + write_type(buf, info.value); case Struct: - buffer_write_string(buf, "struct "); - if info.packed { buffer_write_string(buf, "#packed "); } - if info.ordered { buffer_write_string(buf, "#ordered "); } + write_string(buf, "struct "); + if info.packed { write_string(buf, "#packed "); } + if info.ordered { write_string(buf, "#ordered "); } if info.custom_align { - buffer_write_string(buf, "#align "); + write_string(buf, "#align "); fi := Fmt_Info{buf = buf}; fmt_int(^fi, cast(u64)info.align, false, 'd'); - buffer_write_byte(buf, ' '); + write_byte(buf, ' '); } - buffer_write_byte(buf, '{'); + write_byte(buf, '{'); for name, i in info.names { if i > 0 { - buffer_write_string(buf, ", "); + write_string(buf, ", "); } - buffer_write_string(buf, name); - buffer_write_string(buf, ": "); - buffer_write_type(buf, info.types[i]); + write_string(buf, name); + write_string(buf, ": "); + write_type(buf, info.types[i]); } - buffer_write_byte(buf, '}'); + write_byte(buf, '}'); case Union: - buffer_write_string(buf, "union {"); + write_string(buf, "union {"); cf := info.common_fields; total_count := 0; for name, i in cf.names { if i > 0 { - buffer_write_string(buf, ", "); + write_string(buf, ", "); } - buffer_write_string(buf, name); - buffer_write_string(buf, ": "); - buffer_write_type(buf, cf.types[i]); - total_count += 1; + write_string(buf, name); + write_string(buf, ": "); + write_type(buf, cf.types[i]); + total_count++; } for name, i in info.variant_names { if total_count > 0 || i > 0 { - buffer_write_string(buf, ", "); + write_string(buf, ", "); } - buffer_write_string(buf, name); - buffer_write_byte(buf, '{'); - defer buffer_write_byte(buf, '}'); + write_string(buf, name); + write_byte(buf, '{'); + defer write_byte(buf, '}'); variant_type := type_info_base(info.variant_types[i]); variant := union_cast(^Struct)variant_type; vc := variant.names.count-cf.names.count; - for j in 0..<vc { + for j in 0..vc { if j > 0 { - buffer_write_string(buf, ", "); + write_string(buf, ", "); } index := j + cf.names.count; - buffer_write_string(buf, variant.names[index]); - buffer_write_string(buf, ": "); - buffer_write_type(buf, variant.types[index]); + write_string(buf, variant.names[index]); + write_string(buf, ": "); + write_type(buf, variant.types[index]); } } - buffer_write_string(buf, "}"); + write_string(buf, "}"); case Raw_Union: - buffer_write_string(buf, "raw_union {"); + write_string(buf, "raw_union {"); for name, i in info.names { if i > 0 { - buffer_write_string(buf, ", "); + write_string(buf, ", "); } - buffer_write_string(buf, name); - buffer_write_string(buf, ": "); - buffer_write_type(buf, info.types[i]); + write_string(buf, name); + write_string(buf, ": "); + write_type(buf, info.types[i]); } - buffer_write_string(buf, "}"); + write_string(buf, "}"); case Enum: - buffer_write_string(buf, "enum "); - buffer_write_type(buf, info.base); - buffer_write_string(buf, " {"); + write_string(buf, "enum "); + write_type(buf, info.base); + write_string(buf, " {"); for name, i in info.names { if i > 0 { - buffer_write_string(buf, ", "); + write_string(buf, ", "); } - buffer_write_string(buf, name); + write_string(buf, name); } - buffer_write_string(buf, "}"); + write_string(buf, "}"); } } -bprint :: proc(buf: ^Buffer, args: ...any) -> int { +bprint :: proc(buf: ^[]byte, args: ..any) -> int { fi: Fmt_Info; fi.buf = buf; @@ -287,45 +271,39 @@ bprint :: proc(buf: ^Buffer, args: ...any) -> int { for arg, i in args { is_string := arg.data != nil && types.is_string(arg.type_info); if i > 0 && !is_string && !prev_string { - buffer_write_byte(buf, ' '); + write_byte(buf, ' '); } fmt_value(^fi, args[i], 'v'); prev_string = is_string; } - return buf.length; + return buf.count; } -bprintln :: proc(buf: ^Buffer, args: ...any) -> int { +bprintln :: proc(buf: ^[]byte, args: ..any) -> int { fi: Fmt_Info; fi.buf = buf; for arg, i in args { if i > 0 { - buffer_write_byte(buf, ' '); + write_byte(buf, ' '); } fmt_value(^fi, args[i], 'v'); } - buffer_write_byte(buf, '\n'); - return buf.length; + write_byte(buf, '\n'); + return buf.count; } -sprint :: proc(buf: []byte, args: ...any) -> string { - b: Buffer; - b.data = buf; - count := bprint(^b, ...args); - return cast(string)b.data[:b.length]; +sprint :: proc(buf: []byte, args: ..any) -> string { + count := bprint(^buf, ..args); + return cast(string)buf; } -sprintln :: proc(buf: []byte, args: ...any) -> string { - b: Buffer; - b.data = buf; - count := bprintln(^b, ...args); - return cast(string)b.data[:b.length]; +sprintln :: proc(buf: []byte, args: ..any) -> string { + count := bprintln(^buf, ..args); + return cast(string)buf; } -sprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string { - b: Buffer; - b.data = buf; - count := bprintf(^b, fmt, ...args); - return cast(string)b.data[:b.length]; +sprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string { + count := bprintf(^buf, fmt, ..args); + return cast(string)buf; } @@ -340,12 +318,12 @@ parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool ok := true; i := 0; - for o in offset..<s.count { + for o in offset..s.count { c := cast(rune)s[offset+i]; if !is_digit(c) { break; } - i += 1; + i++; result *= 10; result += cast(int)(c - '0'); @@ -365,7 +343,7 @@ _arg_number :: proc(fi: ^Fmt_Info, return 0, 1, false; } - for i in 1..<format.count { + for i in 1..format.count { if format[i] == ']' { width, new_index, ok := parse_int(format, 1); if !ok || new_index != i { @@ -383,7 +361,7 @@ _arg_number :: proc(fi: ^Fmt_Info, return arg_index, offset, false; } fi.reordered = true; - index, width, ok := parse_arg_number(format[offset:]); + index, width, ok := parse_arg_number(format[offset..]); if ok && 0 <= index && index < arg_count { return index, offset+width, true; } @@ -419,23 +397,23 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) { fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) { assert(verb != 'v'); - buffer_write_string(buf, "%!"); - buffer_write_rune(buf, verb); - buffer_write_byte(buf, '('); + write_string(buf, "%!"); + write_rune(buf, verb); + write_byte(buf, '('); if arg.type_info != nil { - buffer_write_type(buf, arg.type_info); - buffer_write_byte(buf, '='); + write_type(buf, arg.type_info); + write_byte(buf, '='); fmt_value(fi, arg, 'v'); } else { - buffer_write_string(buf, "<nil>"); + write_string(buf, "<nil>"); } - buffer_write_byte(buf, ')'); + write_byte(buf, ')'); } fmt_bool :: proc(using fi: ^Fmt_Info, b: bool, verb: rune) { match verb { case 't', 'v': - buffer_write_string(buf, b ? "true" : "false"); + write_string(buf, b ? "true" : "false"); default: fmt_bad_verb(fi, verb); } @@ -451,25 +429,22 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { pad_byte = '0'; } - count := min(width, fi.buf.data.count-fi.buf.length); - start := fi.buf.length; - for i in start..<count { - fi.buf.data[i] = pad_byte; + count := min(width, fi.buf.capacity-fi.buf.count); + for _ in 0..count { + append(fi.buf^, pad_byte); } - fi.buf.length += count; } -fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) { - negative := signed && cast(i64)u < 0; - if signed { - u = cast(u64)abs(cast(i64)u); +_write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string) { + if neg { + u = -u; } - buf: [256]byte; + BUF_SIZE :: 256; if fi.width_set || fi.prec_set { - width := fi.width + fi.prec + 3; - if width > buf.count { + width := fi.width + fi.prec + 3; // 3 extra bytes for sign and prefix + if width > BUF_SIZE { // TODO(bill):???? - panic("fmt_integer buffer overrun. Width and precision too big"); + panic("_write_int buffer overrun. Width and precision too big"); } } @@ -477,103 +452,55 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri if fi.prec_set { prec = fi.prec; if prec == 0 && u == 0 { - old_zero := fi.zero; + prev_zero := fi.zero; fi.zero = false; fmt_write_padding(fi, fi.width); - fi.zero = old_zero; + fi.zero = prev_zero; return; } } else if fi.zero && fi.width_set { prec = fi.width; - if negative || fi.plus || fi.space { + if neg || fi.plus || fi.space { // There needs to be space for the "sign" - prec -= 1; + prec--; } } - i := buf.count; - match base { case 2, 8, 10, 16: break; default: - panic("fmt_integer: unknown base, whoops"); - } - - for b := cast(u64)base; u >= b; { - i -= 1; - next := u / b; - buf[i] = digits[u%b]; - u = next; - } - i -= 1; - buf[i] = digits[u]; - for i > 0 && prec > buf.count-i { - i -= 1; - buf[i] = '0'; - } - - if fi.hash { - i -= 1; - match base { - case 2: buf[i] = 'b'; - case 8: buf[i] = 'o'; - case 10: buf[i] = 'd'; - case 16: buf[i] = digits[16]; - } - i -= 1; - buf[i] = '0'; - } - - if negative { - i -= 1; - buf[i] = '-'; - } else if fi.plus { - i -= 1; - buf[i] = '+'; - } else if fi.space { - i -= 1; - buf[i] = ' '; + panic("_write_int: unknown base, whoops"); } - old_zero := fi.zero; - defer fi.zero = old_zero; + buf: [256]byte; + flags: strconv.Int_Flag; + if fi.hash { flags |= strconv.Int_Flag.PREFIX; } + if fi.plus { flags |= strconv.Int_Flag.PLUS; } + if fi.space { flags |= strconv.Int_Flag.SPACE; } + s := strconv.append_bits(buf[..0], u, base, neg, digits, flags); + + prev_zero := fi.zero; + defer fi.zero = prev_zero; fi.zero = false; - - if !fi.width_set || fi.width == 0 { - buffer_write(fi.buf, buf[i:]); - } else { - width := fi.width - utf8.rune_count(cast(string)buf[i:]); - if width > 0 { - if fi.minus { - // Right pad - buffer_write(fi.buf, buf[i:]); - fmt_write_padding(fi, width); - } else { - // Left pad - fmt_write_padding(fi, width); - buffer_write(fi.buf, buf[i:]); - } - } - } - + _pad(fi, s); } -__DIGITS_LOWER := "0123456789abcdefx"; -__DIGITS_UPPER := "0123456789ABCDEFX"; +immutable __DIGITS_LOWER := "0123456789abcdefx"; +immutable __DIGITS_UPPER := "0123456789ABCDEFX"; fmt_rune :: proc(fi: ^Fmt_Info, r: rune) { - buffer_write_rune(fi.buf, r); + write_rune(fi.buf, r); } -fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) { +fmt_int :: proc(fi: ^Fmt_Info, u: u64, neg: bool, verb: rune) { match verb { - case 'v': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER); - case 'b': fmt_integer(fi, u, 2, signed, __DIGITS_LOWER); - case 'o': fmt_integer(fi, u, 8, signed, __DIGITS_LOWER); - case 'd': fmt_integer(fi, u, 10, signed, __DIGITS_LOWER); - case 'x': fmt_integer(fi, u, 16, signed, __DIGITS_LOWER); - case 'X': fmt_integer(fi, u, 16, signed, __DIGITS_UPPER); + case 'v': _write_int(fi, u, 10, neg, __DIGITS_LOWER); + case 'b': _write_int(fi, u, 2, neg, __DIGITS_LOWER); + case 'o': _write_int(fi, u, 8, neg, __DIGITS_LOWER); + case 'd': _write_int(fi, u, 10, neg, __DIGITS_LOWER); + case 'x': _write_int(fi, u, 16, neg, __DIGITS_LOWER); + case 'X': _write_int(fi, u, 16, neg, __DIGITS_UPPER); case 'c', 'r': fmt_rune(fi, cast(rune)u); case 'U': @@ -581,8 +508,8 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) { if r < 0 || r > utf8.MAX_RUNE { fmt_bad_verb(fi, verb); } else { - buffer_write_string(fi.buf, "U+"); - fmt_integer(fi, u, 16, false, __DIGITS_UPPER); + write_string(fi.buf, "U+"); + _write_int(fi, u, 16, false, __DIGITS_UPPER); } default: @@ -590,69 +517,63 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, signed: bool, verb: rune) { } } +_pad :: proc(fi: ^Fmt_Info, s: string) { + if !fi.width_set || fi.width == 0 { + write_string(fi.buf, s); + return; + } + width := fi.width - utf8.rune_count(s); + if fi.minus { // right pad + write_string(fi.buf, s); + fmt_write_padding(fi, width); + } else { // left pad + fmt_write_padding(fi, width); + write_string(fi.buf, s); + } +} fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) { + + match verb { // case 'e', 'E', 'f', 'F', 'g', 'G', 'v': // case 'f', 'F', 'v': - // TODO(bill): This is a shit copy from gb.h and I really need a decent implementation case 'f', 'F', 'v': - width := 0; - if fi.width_set { - width = max(fi.width, 0); - } - prec := 3; + prec: int = 3; if fi.prec_set { - prec = max(fi.prec, 0); + prec = fi.prec; } - - if v == 0 { - buffer_write_byte(fi.buf, '0'); - if fi.hash && width > 0 { - buffer_write_byte(fi.buf, '.'); - } + buf: [128]byte; + str := strconv.append_float(buf[1..1], v, 'f', prec, bit_size); + str = cast(string)buf[..str.count+1]; + if str[1] == '+' || str[1] == '-' { + str = str[1..]; } else { - signed := v < 0; - v = abs(v); - - if signed { - buffer_write_byte(fi.buf, '-'); - } - - val := cast(u64)v; - fi.minus = false; - fi.width = 0; - fi.prec = 0; - // TODO(bill): Write integer to buffer than use this crap - fmt_integer(fi, val, 10, false, __DIGITS_LOWER); - - if fi.hash || prec > 0 { - arg := v - cast(f64)val; - mult: f64 = 10; - buffer_write_byte(fi.buf, '.'); - for _ in 0..<prec { - val := cast(u64)(arg*mult); - buffer_write_byte(fi.buf, __DIGITS_LOWER[cast(u64)val]); - arg -= cast(f64)val / mult; - mult *= 10; - } - } + str[0] = '+'; } + if fi.space && !fi.plus && str[0] == '+' { + str[0] = ' '; + } - if width > 0 { - fill: byte = ' '; - match { - case fi.zero: fill = '0'; - case fi.space: fill = ' '; - } + if str[1] == 'N' && str[1] == 'I' { + write_string(fi.buf, str); + return; + } - for width > 0 { - width -= 1; - buffer_write_byte(fi.buf, fill); + if fi.plus || str[0] != '+' { + if fi.zero && fi.width_set && fi.width > str.count { + write_byte(fi.buf, str[0]); + fmt_write_padding(fi, fi.width - str.count); + write_string(fi.buf, str[1..]); + } else { + _pad(fi, str); } + } else { + _pad(fi, str[1..]); } + default: fmt_bad_verb(fi, verb); return; @@ -661,7 +582,7 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) { fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) { match verb { case 's', 'v': - buffer_write_string(fi.buf, s); + write_string(fi.buf, s); default: fmt_bad_verb(fi, verb); } @@ -677,14 +598,14 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) { } u := cast(u64)cast(uint)p; if !fi.hash || verb == 'v' { - buffer_write_string(fi.buf, "0x"); + write_string(fi.buf, "0x"); } - fmt_integer(fi, u, 16, false, __DIGITS_UPPER); + _write_int(fi, u, 16, false, __DIGITS_UPPER); } fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if v.type_info == nil || v.data == nil { - buffer_write_string(fi.buf, "<nil>"); + write_string(fi.buf, "<nil>"); return; } @@ -720,18 +641,18 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if types.is_string(e.base) { for val, idx in e.values { if val.i == i { - buffer_write_string(fi.buf, e.names[idx]); + write_string(fi.buf, e.names[idx]); ok = true; break; } } } else if e.values.count == 0 { - buffer_write_string(fi.buf, ""); + write_string(fi.buf, ""); ok = true; } else { for val, idx in e.values { if val.i == i { - buffer_write_string(fi.buf, e.names[idx]); + write_string(fi.buf, e.names[idx]); ok = true; break; } @@ -739,7 +660,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { } if !ok { - buffer_write_string(fi.buf, "!%(BAD ENUM VALUE)"); + write_string(fi.buf, "!%(BAD ENUM VALUE)"); } default: fmt_bad_verb(fi, verb); @@ -751,7 +672,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if v.data == nil || v.type_info == nil { - buffer_write_string(fi.buf, "<nil>"); + write_string(fi.buf, "<nil>"); return; } @@ -764,18 +685,18 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_bad_verb(fi, verb); return; } - buffer_write_string(fi.buf, info.name); - buffer_write_byte(fi.buf, '{'); + write_string(fi.buf, info.name); + write_byte(fi.buf, '{'); for _, i in b.names { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } - buffer_write_string(fi.buf, b.names[i]); - buffer_write_string(fi.buf, " = "); + write_string(fi.buf, b.names[i]); + write_string(fi.buf, " = "); data := cast(^byte)v.data + b.offsets[i]; fmt_arg(fi, any{b.types[i], cast(rawptr)data}, 'v'); } - buffer_write_byte(fi.buf, '}'); + write_byte(fi.buf, '}'); default: fmt_value(fi, any{info.base, v.data}, verb); @@ -788,7 +709,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { case Pointer: if v.type_info == type_info(^Type_Info) { - buffer_write_type(fi.buf, (cast(^^Type_Info)v.data)^); + write_type(fi.buf, (cast(^^Type_Info)v.data)^); } else { fmt_pointer(fi, (cast(^rawptr)v.data)^, verb); } @@ -799,11 +720,11 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { return; } - buffer_write_byte(fi.buf, '['); - defer buffer_write_byte(fi.buf, ']'); - for i in 0..<info.count { + write_byte(fi.buf, '['); + defer write_byte(fi.buf, ']'); + for i in 0..info.count { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } data := cast(^byte)v.data + i*info.elem_size; fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v'); @@ -815,12 +736,12 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { return; } - buffer_write_byte(fi.buf, '['); - defer buffer_write_byte(fi.buf, ']'); + write_byte(fi.buf, '['); + defer write_byte(fi.buf, ']'); array := cast(^Raw_Dynamic_Array)v.data; - for i in 0..<array.count { + for i in 0..array.count { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } data := cast(^byte)array.data + i*info.elem_size; fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v'); @@ -832,29 +753,29 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { return; } - buffer_write_string(fi.buf, "map["); - defer buffer_write_byte(fi.buf, ']'); + write_string(fi.buf, "map["); + defer write_byte(fi.buf, ']'); entries := ^(cast(^Raw_Dynamic_Map)v.data).entries; gs := union_cast(^Struct)type_info_base(info.generated_struct); ed := union_cast(^Dynamic_Array)type_info_base(gs.types[1]); entry_type := union_cast(^Struct)ed.elem; entry_size := ed.elem_size; - for i in 0..<entries.count { + for i in 0..entries.count { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } data := cast(^byte)entries.data + i*entry_size; header := cast(^__Map_Entry_Header)data; if types.is_string(info.key) { - buffer_write_string(fi.buf, header.key.str); + write_string(fi.buf, header.key.str); } else { fi := Fmt_Info{buf = fi.buf}; fmt_arg(^fi, any{info.key, cast(rawptr)^header.key.hash}, 'v'); } - buffer_write_string(fi.buf, "="); + write_string(fi.buf, "="); value := data + entry_type.offsets[2]; fmt_arg(fi, any{info.value, cast(rawptr)value}, 'v'); @@ -866,24 +787,24 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { return; } - buffer_write_byte(fi.buf, '['); - defer buffer_write_byte(fi.buf, ']'); + write_byte(fi.buf, '['); + defer write_byte(fi.buf, ']'); slice := cast(^[]byte)v.data; - for i in 0..<slice.count { + for i in 0..slice.count { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } data := slice.data + i*info.elem_size; fmt_arg(fi, any{info.elem, cast(rawptr)data}, 'v'); } case Vector: - buffer_write_byte(fi.buf, '<'); - defer buffer_write_byte(fi.buf, '>'); + write_byte(fi.buf, '<'); + defer write_byte(fi.buf, '>'); - for i in 0..<info.count { + for i in 0..info.count { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } data := cast(^byte)v.data + i*info.elem_size; @@ -891,51 +812,51 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { } case Struct: - buffer_write_byte(fi.buf, '{'); - defer buffer_write_byte(fi.buf, '}'); + write_byte(fi.buf, '{'); + defer write_byte(fi.buf, '}'); for _, i in info.names { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } - buffer_write_string(fi.buf, info.names[i]); - buffer_write_string(fi.buf, " = "); + write_string(fi.buf, info.names[i]); + write_string(fi.buf, " = "); data := cast(^byte)v.data + info.offsets[i]; fmt_value(fi, any{info.types[i], cast(rawptr)data}, 'v'); } case Union: - buffer_write_byte(fi.buf, '{'); - defer buffer_write_byte(fi.buf, '}'); + write_byte(fi.buf, '{'); + defer write_byte(fi.buf, '}'); cf := info.common_fields; for _, i in cf.names { if i > 0 { - buffer_write_string(fi.buf, ", "); + write_string(fi.buf, ", "); } - buffer_write_string(fi.buf, cf.names[i]); - buffer_write_string(fi.buf, " = "); + write_string(fi.buf, cf.names[i]); + write_string(fi.buf, " = "); data := cast(^byte)v.data + cf.offsets[i]; fmt_value(fi, any{cf.types[i], cast(rawptr)data}, 'v'); } case Raw_Union: - buffer_write_string(fi.buf, "(raw_union)"); + write_string(fi.buf, "(raw_union)"); case Enum: fmt_enum(fi, v, verb); case Procedure: - buffer_write_type(fi.buf, v.type_info); - buffer_write_string(fi.buf, " @ "); + write_type(fi.buf, v.type_info); + write_string(fi.buf, " @ "); fmt_pointer(fi, (cast(^rawptr)v.data)^, 'p'); } } fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { if arg.data == nil || arg.type_info == nil { - buffer_write_string(fi.buf, "<nil>"); + write_string(fi.buf, "<nil>"); return; } fi.arg = arg; @@ -945,7 +866,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { match a in arg { case ^Type_Info: ti = a; } - buffer_write_type(fi.buf, ti); + write_type(fi.buf, ti); return; } @@ -957,11 +878,11 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { case f32: fmt_float(fi, cast(f64)a, 32, verb); case f64: fmt_float(fi, a, 64, verb); - case int: fmt_int(fi, cast(u64)a, true, verb); - case i8: fmt_int(fi, cast(u64)a, true, verb); - case i16: fmt_int(fi, cast(u64)a, true, verb); - case i32: fmt_int(fi, cast(u64)a, true, verb); - case i64: fmt_int(fi, cast(u64)a, true, verb); + case int: fmt_int(fi, cast(u64)a, a < 0, verb); + case i8: fmt_int(fi, cast(u64)a, a < 0, verb); + case i16: fmt_int(fi, cast(u64)a, a < 0, verb); + case i32: fmt_int(fi, cast(u64)a, a < 0, verb); + case i64: fmt_int(fi, cast(u64)a, a < 0, verb); case uint: fmt_int(fi, cast(u64)a, false, verb); case u8: fmt_int(fi, cast(u64)a, false, verb); case u16: fmt_int(fi, cast(u64)a, false, verb); @@ -974,7 +895,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { } -bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { +bprintf :: proc(b: ^[]byte, fmt: string, args: ..any) -> int { fi := Fmt_Info{}; end := fmt.count; arg_index := 0; @@ -984,20 +905,20 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { prev_i := i; for i < end && fmt[i] != '%' { - i += 1; + i++; } if i > prev_i { - buffer_write_string(b, fmt[prev_i:i]); + write_string(b, fmt[prev_i..i]); } if i >= end { break; } // Process a "verb" - i += 1; + i++; - for ; i < end; i += 1 { + for ; i < end; i++ { skip_loop := false; c := fmt[i]; match c { @@ -1025,10 +946,10 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { // Width if i < end && fmt[i] == '*' { - i += 1; + i++; fi.width, arg_index, fi.width_set = int_from_arg(args, arg_index); if !fi.width_set { - buffer_write_string(b, "%!(BAD WIDTH)"); + write_string(b, "%!(BAD WIDTH)"); } if fi.width < 0 { @@ -1046,20 +967,20 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { // Precision if i < end && fmt[i] == '.' { - i += 1; + i++; if was_prev_index { // %[6].2d fi.good_arg_index = false; } if i < end && fmt[i] == '*' { arg_index, i, was_prev_index = _arg_number(^fi, arg_index, fmt, i, args.count); - i += 1; + i++; fi.prec, arg_index, fi.prec_set = int_from_arg(args, arg_index); if fi.prec < 0 { fi.prec = 0; fi.prec_set = false; } if !fi.prec_set { - buffer_write_string(fi.buf, "%!(BAD PRECISION)"); + write_string(fi.buf, "%!(BAD PRECISION)"); } was_prev_index = false; } else { @@ -1076,39 +997,39 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int { } if i >= end { - buffer_write_string(b, "%!(NO VERB)"); + write_string(b, "%!(NO VERB)"); break; } - verb, w := utf8.decode_rune(fmt[i:]); + verb, w := utf8.decode_rune(fmt[i..]); i += w; if verb == '%' { - buffer_write_byte(b, '%'); + write_byte(b, '%'); } else if !fi.good_arg_index { - buffer_write_string(b, "%!(BAD ARGUMENT NUMBER)"); + write_string(b, "%!(BAD ARGUMENT NUMBER)"); } else if arg_index >= args.count { - buffer_write_string(b, "%!(MISSING ARGUMENT)"); + write_string(b, "%!(MISSING ARGUMENT)"); } else { fmt_arg(^fi, args[arg_index], verb); - arg_index += 1; + arg_index++; } } if !fi.reordered && arg_index < args.count { - buffer_write_string(b, "%!(EXTRA "); - for arg, index in args[arg_index:] { + write_string(b, "%!(EXTRA "); + for arg, index in args[arg_index..] { if index > 0 { - buffer_write_string(b, ", "); + write_string(b, ", "); } if arg.data == nil || arg.type_info == nil { - buffer_write_string(b, "<nil>"); + write_string(b, "<nil>"); } else { fmt_arg(^fi, args[index], 'v'); } } - buffer_write_string(b, ")"); + write_string(b, ")"); } - return b.length; + return b.count; } diff --git a/core/hash.odin b/core/hash.odin index de1ffd0b6..6d61594d2 100644 --- a/core/hash.odin +++ b/core/hash.odin @@ -66,7 +66,7 @@ murmur32 :: proc(data: []byte) -> u32 { h1 = h1*5 + 0xe6546b64; } - tail := data[nblocks*4:]; + tail := data[nblocks*4 ..]; k1: u32; match tail.count&3 { @@ -146,7 +146,7 @@ murmur64 :: proc(data: []byte) -> u64 { i := 0; for len >= 8 { k1, k2: u32; - k1 = data32[i]; i += 1; + k1 = data32[i]; i++; k1 *= m; k1 ~= k1>>r; k1 *= m; @@ -154,7 +154,7 @@ murmur64 :: proc(data: []byte) -> u64 { h1 ~= k1; len -= 4; - k2 = data32[i]; i += 1; + k2 = data32[i]; i++; k2 *= m; k2 ~= k2>>r; k2 *= m; @@ -165,7 +165,7 @@ murmur64 :: proc(data: []byte) -> u64 { if len >= 4 { k1: u32; - k1 = data32[i]; i += 1; + k1 = data32[i]; i++; k1 *= m; k1 ~= k1>>r; k1 *= m; @@ -174,7 +174,7 @@ murmur64 :: proc(data: []byte) -> u64 { len -= 4; } - data8 := slice_to_bytes(data32[i:])[:3]; + data8 := slice_to_bytes(data32[i..])[..3]; match len { case 3: h2 ~= cast(u32)data8[2] << 16; diff --git a/core/math.odin b/core/math.odin index 61a33bdeb..ef773faf9 100644 --- a/core/math.odin +++ b/core/math.odin @@ -151,8 +151,8 @@ mat4_identity :: proc() -> Mat4 { } mat4_transpose :: proc(m: Mat4) -> Mat4 { - for j in 0..<4 { - for i in 0..<4 { + for j in 0..4 { + for i in 0..4 { 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 { c: Mat4; - for j in 0..<4 { - for i in 0..<4 { + for j in 0..4 { + for i in 0..4 { c[j][i] = a[0][i]*b[j][0] + a[1][i]*b[j][1] + a[2][i]*b[j][2] + diff --git a/core/mem.odin b/core/mem.odin index ce1c4a21c..b5e119921 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -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" { n := min(a.count, b.count); - for i in 0..<n { + for i in 0..n { match { case a[i] < b[i]: return -1; @@ -79,7 +79,7 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i header.size = size; 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; } } @@ -117,7 +117,7 @@ Arena_Temp_Memory :: struct { init_arena_from_memory :: proc(using a: ^Arena, data: []byte) { backing = Allocator{}; - memory = data[:0]; + memory = data[..0]; temp_count = 0; } @@ -183,7 +183,7 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory { tmp: Arena_Temp_Memory; tmp.arena = a; tmp.original_count = a.memory.count; - a.temp_count += 1; + a.temp_count++; return tmp; } @@ -191,7 +191,7 @@ end_arena_temp_memory :: proc(using tmp: Arena_Temp_Memory) { assert(arena.memory.count >= original_count); assert(arena.temp_count > 0); arena.memory.count = original_count; - arena.temp_count -= 1; + arena.temp_count--; } diff --git a/core/os_windows.odin b/core/os_windows.odin index 9066c6ca0..8e380f0ba 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -95,7 +95,7 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { } 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); if handle != INVALID_HANDLE { @@ -184,7 +184,7 @@ last_write_time_by_name :: proc(name: string) -> File_Time { assert(buf.count > name.count); - copy(buf[:], cast([]byte)name); + copy(buf[..], cast([]byte)name); if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 { 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) { buf: [300]byte; - copy(buf[:], cast([]byte)name); + copy(buf[..], cast([]byte)name); fd, err := open(name, O_RDONLY, 0); if err != ERROR_NONE { diff --git a/core/strconv.odin b/core/strconv.odin new file mode 100644 index 000000000..ff78847df --- /dev/null +++ b/core/strconv.odin @@ -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; +} + diff --git a/core/strings.odin b/core/strings.odin index bfc16a184..7439fff32 100644 --- a/core/strings.odin +++ b/core/strings.odin @@ -9,7 +9,7 @@ to_odin_string :: proc(c: ^byte) -> string { s: string; s.data = c; for (c+s.count)^ != 0 { - s.count += 1; + s.count++; } return s; } diff --git a/core/sync.odin b/core/sync.odin index e346c60d4..3126d6882 100644 --- a/core/sync.odin +++ b/core/sync.odin @@ -52,7 +52,7 @@ mutex_lock :: proc(m: ^Mutex) { } } atomic.store(^m.owner, thread_id); - m.recursion += 1; + m.recursion++; } mutex_try_lock :: proc(m: ^Mutex) -> bool { thread_id := current_thread_id(); @@ -68,7 +68,7 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool { } atomic.store(^m.owner, thread_id); } - m.recursion += 1; + m.recursion++; return true; } mutex_unlock :: proc(m: ^Mutex) { @@ -76,7 +76,7 @@ mutex_unlock :: proc(m: ^Mutex) { thread_id := current_thread_id(); assert(thread_id == atomic.load(^m.owner)); - m.recursion -= 1; + m.recursion--; recursion = m.recursion; if recursion == 0 { atomic.store(^m.owner, thread_id); diff --git a/core/utf8.odin b/core/utf8.odin index 8720e1f20..a90e4e45b 100644 --- a/core/utf8.odin +++ b/core/utf8.odin @@ -92,7 +92,8 @@ encode_rune :: proc(r: rune) -> ([4]byte, int) { 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; if n < 1 { 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 { if r < 0 { return false; @@ -146,7 +187,7 @@ valid_string :: proc(s: string) -> bool { for i := 0; i < n; { si := s[i]; if si < RUNE_SELF { // ascii - i += 1; + i++; continue; } x := accept_sizes[si]; @@ -174,25 +215,28 @@ valid_string :: proc(s: string) -> bool { 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; n := s.count; for i := 0; i < n; { - defer count += 1; + defer count++; si := s[i]; if si < RUNE_SELF { // ascii - i += 1; + i++; continue; } x := accept_sizes[si]; if x == 0xf1 { - i += 1; + i++; continue; } size := cast(int)(x & 7); if i+size > n { - i += 1; + i++; continue; } ar := accept_ranges[x>>4]; diff --git a/src/check_expr.c b/src/check_expr.c index f075df688..0e166ef1a 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -197,11 +197,11 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { } } - // if (is_type_proc(dst)) { - // if (are_types_identical(src, dst)) { - // return 1; - // } - // } + if (is_type_proc(dst)) { + if (are_types_identical(src, dst)) { + return 3; + } + } if (is_type_any(dst)) { // 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; } } + + 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) { gbString op_str = expr_to_string(op_expr); 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; 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 = 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); - 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); return false; } - // TODO(bill): Semi-memory leaks - Type *elem = type->DynamicArray.elem; - Type *slice_elem = make_type_slice(c->allocator, elem); + Type *elem = NULL; + Type *slice_elem = NULL; + 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); 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; 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); if (!is_type_vector(vector_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) { case Type_Basic: if (is_type_string(t)) { + if (se->index3) { + error_node(node, "3-index slice on a string in not needed"); + goto error; + } valid = true; if (o->mode == Addressing_Constant) { 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; } + 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}; - 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++) { i64 index = max_count; if (nodes[i] != NULL) { i64 capacity = -1; - if (max_count >= 0) + if (max_count >= 0) { capacity = max_count; + } i64 j = 0; if (check_index_value(c, nodes[i], capacity, &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 = gb_string_appendc(str, "["); 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); + if (se->index3) { + str = gb_string_appendc(str, ".."); + str = write_expr_to_string(str, se->max); + } str = gb_string_appendc(str, "]"); case_end; case_ast_node(e, Ellipsis, node); - str = gb_string_appendc(str, "..."); + str = gb_string_appendc(str, ".."); case_end; 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); str = gb_string_appendc(str, "["); - if (at->count->kind == AstNode_UnaryExpr && - at->count->UnaryExpr.op.kind == Token_Hash) { - str = gb_string_appendc(str, "#"); + if (at->count != NULL && + at->count->kind == AstNode_UnaryExpr && + at->count->UnaryExpr.op.kind == Token_Ellipsis) { + str = gb_string_appendc(str, ".."); } else { str = write_expr_to_string(str, at->count); } @@ -5456,7 +5488,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_end; case_ast_node(at, DynamicArrayType, node); - str = gb_string_appendc(str, "[...]"); + str = gb_string_appendc(str, "[..]"); str = write_expr_to_string(str, at->elem); case_end; @@ -5489,7 +5521,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, ": "); } if (f->flags&FieldFlag_ellipsis) { - str = gb_string_appendc(str, "..."); + str = gb_string_appendc(str, ".."); } str = write_expr_to_string(str, f->type); case_end; diff --git a/src/check_stmt.c b/src/check_stmt.c index 90cb6ff61..768410803 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -421,6 +421,49 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_stmt(c, ts->stmt, flags); 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); switch (as->op.kind) { case Token_Eq: { @@ -591,8 +634,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (fs->post != NULL) { check_stmt(c, fs->post, 0); - if (fs->post->kind != AstNode_AssignStmt) { - error_node(fs->post, "`for` statement post statement must be an assignment"); + if (fs->post->kind != AstNode_AssignStmt && + 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); @@ -671,8 +715,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { TokenKind op = Token_Lt; switch (ie->op.kind) { - case Token_HalfOpenRange: op = Token_Lt; break; - case Token_Ellipsis: op = Token_LtEq; break; + case Token_Ellipsis: op = Token_Lt; break; default: error(ie->op, "Invalid range operator"); break; } 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: { Type *t = base_type(type_deref(e->type)); 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)); GB_ASSERT(found != NULL); for_array(i, (*found)->elements.entries) { diff --git a/src/exact_value.c b/src/exact_value.c index 7c48d126b..57c8ae81d 100644 --- a/src/exact_value.c +++ b/src/exact_value.c @@ -274,8 +274,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) case ExactValue_Invalid: return v; case ExactValue_Integer: - i = v.value_integer; - i = ~i; + i = ~v.value_integer; break; default: 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 // 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); + } return make_exact_value_integer(i); } break; @@ -218,6 +218,7 @@ struct irProcedure { TokenPos pos; \ irValue *low; \ irValue *high; \ + irValue *max; \ bool is_substring; \ }) \ IR_INSTR_KIND(DebugDeclare, struct { \ @@ -233,6 +234,7 @@ struct irProcedure { #define IR_CONV_KINDS \ IR_CONV_KIND(trunc) \ IR_CONV_KIND(zext) \ + IR_CONV_KIND(sext) \ IR_CONV_KIND(fptrunc) \ IR_CONV_KIND(fpext) \ 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; 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); v->Instr.SliceBoundsCheck.pos = pos; v->Instr.SliceBoundsCheck.low = low; v->Instr.SliceBoundsCheck.high = high; + v->Instr.SliceBoundsCheck.max = max; v->Instr.SliceBoundsCheck.is_substring = is_substring; return v; } @@ -1844,6 +1847,7 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { switch (index) { 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 2: result_type = make_type_pointer(a, t_int); break; } } else if (is_type_string(t)) { switch (index) { @@ -2069,6 +2073,11 @@ irValue *ir_slice_count(irProcedure *proc, irValue *slice) { GB_ASSERT(t->kind == Type_Slice); 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) { 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): check that low < high <= max 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; } } + 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 *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int); irValue *elem = NULL; 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); irValue *slice = ir_add_local_generated(proc, slice_type); - - 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); - + ir_fill_slice(proc, slice, elem, len, cap); 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 dz = type_size_of(proc->module->allocator, dst); 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): Copy the value just for type correctness kind = irConv_bitcast; } else if (dz > sz) { 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)); @@ -2374,7 +2406,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { ir_emit_store(proc, elem_ptr, elem); 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); } @@ -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)); } -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) { 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); 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 @@ -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); - 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); @@ -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 *slice = ir_add_local_generated(proc, slice_type); - irValue *gep0 = ir_emit_struct_ep(proc, slice, 0); - irValue *gep1 = ir_emit_struct_ep(proc, slice, 1); - ir_emit_store(proc, gep0, ptr); - ir_emit_store(proc, gep1, count); + ir_fill_slice(proc, slice, ptr, count, count); return ir_emit_load(proc, slice); } break; @@ -3303,8 +3334,16 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv Type *type = ir_type(array_ptr); GB_ASSERT(is_type_pointer(type)); type = base_type(type_deref(type)); - GB_ASSERT(is_type_dynamic_array(type)); - Type *elem_type = type->DynamicArray.elem; + Type *elem_type = NULL; + 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_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 *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); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len); + ir_fill_slice(proc, slice, base_elem, len, len); } 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[3] = ir_emit_conv(proc, items, t_rawptr); 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); } 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))); irValue *slice = ir_add_local_generated(proc, slice_type); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), ptr); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), count); + ir_fill_slice(proc, slice, ptr, count, count); return ir_emit_load(proc, slice); } 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 *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); - - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), ptr); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), count); + ir_fill_slice(proc, slice, ptr, count, count); return ir_emit_load(proc, slice); } break; @@ -3669,11 +3707,9 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv ir_emit_store(proc, addr, args[i]); } - 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 *base_elem = ir_emit_array_epi(proc, base_array, 0); 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; @@ -4064,9 +4100,11 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { gbAllocator a = proc->module->allocator; irValue *low = v_zero; irValue *high = NULL; + irValue *max = NULL; if (se->low != NULL) low = ir_build_expr(proc, se->low); 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 *base = ir_emit_load(proc, addr); Type *type = base_type(ir_type(base)); @@ -4084,16 +4122,15 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Type *slice_type = type; 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 *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); - - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len); - + ir_fill_slice(proc, slice, elem, len, cap); return ir_make_addr(slice); } @@ -4101,16 +4138,15 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Type *dynamic_array = type; 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 *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); - - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len); - + ir_fill_slice(proc, slice, elem, len, cap); 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); 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 *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); - - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len); - + ir_fill_slice(proc, slice, elem, len, cap); return ir_make_addr(slice); } case Type_Basic: { GB_ASSERT(type == t_string); - if (high == NULL) { - high = ir_string_len(proc, base); - } + if (high == NULL) 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; - 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 *elem = ir_emit_ptr_offset(proc, ir_string_elem(proc, base), low); + irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int); irValue *str = ir_add_local_generated(proc, t_string); - irValue *gep0 = ir_emit_struct_ep(proc, str, 0); - irValue *gep1 = ir_emit_struct_ep(proc, str, 1); - ir_emit_store(proc, gep0, elem); - ir_emit_store(proc, gep1, len); + ir_emit_store(proc, ir_emit_struct_ep(proc, str, 0), elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, str, 1), len); return ir_make_addr(str); } break; @@ -4357,13 +4386,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ir_emit_store(proc, offset, ev); } - irValue *gep0 = ir_emit_struct_ep(proc, v, 0); - irValue *gep1 = ir_emit_struct_ep(proc, v, 1); - 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)); + irValue *count = ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count); + ir_fill_slice(proc, v, data, count, count); } } break; @@ -4730,8 +4754,7 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type TokenKind op = Token_Lt; switch (node->op.kind) { - case Token_HalfOpenRange: op = Token_Lt; break; - case Token_Ellipsis: op = Token_LtEq; break; + case Token_Ellipsis: op = Token_Lt; break; default: GB_PANIC("Invalid interval operator"); break; } 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); 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); if (vd->is_var) { 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); } -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) { 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")); Type *type = base_type(type_deref(ir_type(ir_global_type_info_data))); 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_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)); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, 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, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); } break; case Type_Record: { 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_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, 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, 2), memory_offsets, 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, 0), memory_types, count, 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; case TypeRecord_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)); - 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, 2), memory_offsets, 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, 0), memory_types, count, 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); - - ir_fill_slice(proc, variant_names, memory_names, count); - ir_fill_slice(proc, variant_types, memory_types, count); + ir_fill_slice(proc, variant_names, memory_names, count, count); + ir_fill_slice(proc, variant_types, memory_types, count, count); } } 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)); - 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, 2), memory_offsets, 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, 0), memory_types, count, 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; case TypeRecord_Enum: ir_emit_comment(proc, str_lit("Type_Info_Enum")); diff --git a/src/ir_print.c b/src/ir_print.c index 3018e2463..9bc7e5f41 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -191,7 +191,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { case Type_Slice: ir_fprintf(f, "{"); 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; case Type_DynamicArray: ir_fprintf(f, "{"); @@ -1249,6 +1249,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, " "); 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"); } break; diff --git a/src/parser.c b/src/parser.c index f14f37599..160b72ef3 100644 --- a/src/parser.c +++ b/src/parser.c @@ -151,8 +151,9 @@ AST_NODE_KIND(_ExprBegin, "", i32) \ AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \ AST_NODE_KIND(SliceExpr, "slice expression", struct { \ AstNode *expr; \ - Token open, close, interval; \ - AstNode *low, *high; \ + Token open, close; \ + bool index3; \ + AstNode *low, *high, *max; \ }) \ AST_NODE_KIND(CallExpr, "call expression", struct { \ AstNode * proc; \ @@ -186,6 +187,10 @@ AST_NODE_KIND(_StmtBegin, "", i32) \ Token op; \ AstNodeArray lhs, rhs; \ }) \ + AST_NODE_KIND(IncDecStmt, "increment decrement statement", struct { \ + Token op; \ + AstNode *expr; \ + }) \ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AST_NODE_KIND(BlockStmt, "block statement", struct { \ AstNodeArray stmts; \ @@ -467,6 +472,7 @@ Token ast_node_token(AstNode *node) { case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr); case AstNode_TagStmt: return node->TagStmt.token; 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_IfStmt: return node->IfStmt.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); result->SliceExpr.expr = expr; result->SliceExpr.open = open; result->SliceExpr.close = close; - result->SliceExpr.interval = interval; + result->SliceExpr.index3 = index3; result->SliceExpr.low = low; result->SliceExpr.high = high; + result->SliceExpr.max = max; return result; } @@ -802,6 +809,16 @@ AstNode *ast_assign_stmt(AstFile *f, Token op, AstNodeArray lhs, AstNodeArray rh 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 *result = make_ast_node(f, AstNode_BlockStmt); result->BlockStmt.stmts = stmts; @@ -1930,37 +1947,49 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { // TODO(bill): Handle this } 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++; open = expect_token(f, Token_OpenBracket); - // if (f->curr_token.kind != Token_Ellipsis && - // f->curr_token.kind != Token_HalfOpenRange) { - if (f->curr_token.kind != Token_Colon) { + if (f->curr_token.kind != Token_Ellipsis) { indices[0] = parse_expr(f, false); } bool is_index = true; - // if (f->curr_token.kind == Token_Ellipsis || - // f->curr_token.kind == Token_HalfOpenRange) { - if (f->curr_token.kind == Token_Colon) { - is_index = false; - interval = f->curr_token; + while (f->curr_token.kind == Token_Ellipsis && ellipsis_count < gb_count_of(ellipses)) { + ellipses[ellipsis_count++] = f->curr_token; 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) { - indices[1] = parse_expr(f, false); + indices[ellipsis_count] = parse_expr(f, false); } } + f->expr_level--; close = expect_token(f, Token_CloseBracket); - if (is_index) { - operand = ast_index_expr(f, operand, indices[0], open, close); + if (ellipsis_count > 0) { + 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 { - operand = ast_slice_expr(f, operand, open, close, interval, indices[0], indices[1]); + operand = ast_index_expr(f, operand, indices[0], open, close); } } break; @@ -2246,7 +2275,6 @@ AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) { allow_token(f, Token_in); AstNode *expr = parse_expr(f, false); switch (f->curr_token.kind) { - case Token_HalfOpenRange: case Token_Ellipsis: { Token op = f->curr_token; 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); } + 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]); } diff --git a/src/tokenizer.c b/src/tokenizer.c index 68ab270be..cfc1423f0 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -51,8 +51,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ TOKEN_KIND(Token_ArrowRight, "->"), \ TOKEN_KIND(Token_ArrowLeft, "<-"), \ - TOKEN_KIND(Token_Increment, "++"), \ - TOKEN_KIND(Token_Decrement, "--"), \ + TOKEN_KIND(Token_Inc, "++"), \ + TOKEN_KIND(Token_Dec, "--"), \ \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token_CmpEq, "=="), \ @@ -73,8 +73,8 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ TOKEN_KIND(Token_Semicolon, ";"), \ TOKEN_KIND(Token_Period, "."), \ TOKEN_KIND(Token_Comma, ","), \ - TOKEN_KIND(Token_Ellipsis, "..."), \ - TOKEN_KIND(Token_HalfOpenRange, "..<"), \ + TOKEN_KIND(Token_Ellipsis, ".."), \ + /* TOKEN_KIND(Token_HalfOpenRange, "..<"), */ \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ 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); } +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, ...) { va_list va; @@ -247,6 +264,13 @@ void syntax_error(Token token, char *fmt, ...) { 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, ...) { va_list va; @@ -834,13 +858,11 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = Token_Period; // Default if (t->curr_rune == '.') { // Could be an ellipsis advance_to_next_rune(t); - if (t->curr_rune == '<') { - advance_to_next_rune(t); - token.kind = Token_HalfOpenRange; - } else if (t->curr_rune == '.') { - advance_to_next_rune(t); - token.kind = Token_Ellipsis; - } + token.kind = Token_Ellipsis; + // if (t->curr_rune == '<') { + // advance_to_next_rune(t); + // token.kind = Token_HalfOpenRange; + // } } break; @@ -859,13 +881,13 @@ Token tokenizer_get_token(Tokenizer *t) { case '{': token.kind = Token_OpenBrace; 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_Mod, Token_ModEq); 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_Not, Token_NotEq); break; - case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break; - case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); 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_Eq, Token_CmpEq); 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_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break; + case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Dec, '>', Token_ArrowRight); break; case '/': { if (t->curr_rune == '/') { while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) { diff --git a/src/types.c b/src/types.c index a734e3c01..0142fa227 100644 --- a/src/types.c +++ b/src/types.c @@ -1090,6 +1090,7 @@ gb_global Entity *entity__any_data = NULL; gb_global Entity *entity__string_data = NULL; gb_global Entity *entity__string_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_capacity = NULL; @@ -1251,6 +1252,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } else if (type->kind == Type_Slice) { String data_str = str_lit("data"); String count_str = str_lit("count"); + String capacity_str = str_lit("capacity"); if (str_eq(field_name, data_str)) { 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; 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) { String data_str = str_lit("data"); 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 - return 2 * build_context.word_size; + return 3 * build_context.word_size; case Type_Map: { 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) { if (t->Basic.kind == Basic_string) { switch (index) { - case 0: return 0; // data + case 0: return 0; // data case 1: return build_context.word_size; // count } } else if (t->Basic.kind == Basic_any) { switch (index) { - case 0: return 0; // type_info + case 0: return 0; // type_info case 1: return build_context.word_size; // data } } } else if (t->kind == Type_Slice) { switch (index) { - case 0: return 0; // data + case 0: return 0; // data case 1: return 1*build_context.word_size; // count + case 2: return 2*build_context.word_size; // capacity } } else if (t->kind == Type_DynamicArray) { switch (index) { - case 0: return 0; // data + case 0: return 0; // data case 1: return 1*build_context.word_size; // count case 2: return 2*build_context.word_size; // capacity 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; + 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: switch (index) { 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; } break; - case Type_Slice: - switch (index) { - case 0: t = t_rawptr; break; - case 1: t = t_int; break; - } - break; } } } |