From 67694c0df07c758effbc7dcb10c76a2b2bffe5d0 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sat, 17 Sep 2016 11:39:08 +0100 Subject: [PATCH] VarDecl and ConstDecl split; error, warning, et al. now global --- code/demo.odin | 3 +- code/fmt.odin | 583 ++++++++++++++++++++++++++++++++++++++++ code/os.odin | 107 ++++++++ code/punity.odin | 484 +++++++++++++++++++++++++++++++++ src/checker/checker.cpp | 135 +++++----- src/checker/entity.cpp | 3 + src/checker/expr.cpp | 412 ++++++++++++++-------------- src/checker/stmt.cpp | 312 ++++++++++----------- src/codegen/codegen.cpp | 10 +- src/codegen/ssa.cpp | 138 +++++----- src/parser.cpp | 255 ++++++++---------- src/printer.cpp | 15 +- src/tokenizer.cpp | 53 +++- 13 files changed, 1840 insertions(+), 670 deletions(-) create mode 100644 code/fmt.odin create mode 100644 code/os.odin create mode 100644 code/punity.odin diff --git a/code/demo.odin b/code/demo.odin index f1667bd66..9fea042ff 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -2,7 +2,6 @@ main :: proc() { init :: proc(c: ^pn.Core) { - } step :: proc(c: ^pn.Core) { @@ -11,5 +10,5 @@ main :: proc() { } } - // pn.run(init, step) + pn.run(init, step) } diff --git a/code/fmt.odin b/code/fmt.odin new file mode 100644 index 000000000..0c7e3a696 --- /dev/null +++ b/code/fmt.odin @@ -0,0 +1,583 @@ +#import "os.odin" as os + +print_byte_buffer :: proc(buf: ^[]byte, b: []byte) { + if buf.count < buf.capacity { + n := min(buf.capacity-buf.count, b.count) + if n > 0 { + offset := ptr_offset(buf.data, buf.count) + memory_copy(offset, ^b[0], n) + buf.count += n + } + } +} + +print_string_to_buffer :: proc(buf: ^[]byte, s: string) { + print_byte_buffer(buf, s as []byte) +} + + +byte_reverse :: proc(b: []byte) { + n := b.count + for i := 0; i < n/2; i++ { + b[i], b[n-1-i] = b[n-1-i], b[i] + } +} + +encode_rune :: proc(r: rune) -> ([4]byte, int) { + buf: [4]byte + i := r as u32 + mask: byte : 0x3f + if i <= 1<<7-1 { + buf[0] = r as byte + return buf, 1 + } + if i <= 1<<11-1 { + buf[0] = 0xc0 | (r>>6) as byte + buf[1] = 0x80 | (r) as byte & mask + return buf, 2 + } + + // Invalid or Surrogate range + if i > 0x0010ffff || + (i >= 0xd800 && i <= 0xdfff) { + r = 0xfffd + } + + if i <= 1<<16-1 { + buf[0] = 0xe0 | (r>>12) as byte + buf[1] = 0x80 | (r>>6) as byte & mask + buf[2] = 0x80 | (r) as byte & mask + return buf, 3 + } + + buf[0] = 0xf0 | (r>>18) as byte + buf[1] = 0x80 | (r>>12) as byte & mask + buf[2] = 0x80 | (r>>6) as byte & mask + buf[3] = 0x80 | (r) as byte & mask + return buf, 4 +} + +print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) { + b, n := encode_rune(r) + print_string_to_buffer(buf, b[:n] as string) +} + +print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune " ") } +print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\n") } + +print_int_to_buffer :: proc(buf: ^[]byte, i: int) { + print_int_base_to_buffer(buf, i, 10); +} +PRINT__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" +print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { + + buf: [65]byte + len := 0 + negative := false + if i < 0 { + negative = true + i = -i + } + if i == 0 { + buf[len] = #rune "0" + len++ + } + for i > 0 { + buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base] + len++ + i /= base + } + + if negative { + buf[len] = #rune "-" + len++ + } + + byte_reverse(buf[:len]) + print_string_to_buffer(buffer, buf[:len] as string) +} + +print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) { + print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ") +} +print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) { + buf: [65]byte + len := 0 + if i == 0 { + buf[len] = #rune "0" + len++ + } + for i > 0 { + buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base] + len++ + i /= base + } + for len < min_width { + buf[len] = pad_char + len++ + } + + byte_reverse(buf[:len]) + print_string_to_buffer(buffer, buf[:len] as string) +} + +print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) { + if b { print_string_to_buffer(buffer, "true") } + else { print_string_to_buffer(buffer, "false") } +} + +print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_uint_base_to_buffer(buffer, p as uint, 16, 0, #rune " ") } + +print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) } +print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) } + +print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) { + if f == 0 { + print_rune_to_buffer(buffer, #rune "0") + return + } + if f < 0 { + print_rune_to_buffer(buffer, #rune "-") + f = -f + } + + print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) { + buf: [22]byte + len := 0 + if i == 0 { + buf[len] = #rune "0" + len++ + } + for i > 0 { + buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % 10] + len++ + i /= 10 + } + byte_reverse(buf[:len]) + print_string_to_buffer(buffer, buf[:len] as string) + } + + i := f as u64 + print_u64_to_buffer(buffer, i) + f -= i as f64 + + print_rune_to_buffer(buffer, #rune ".") + + mult := 10.0 + for decimal_places := 6; decimal_places >= 0; decimal_places-- { + i = (f * mult) as u64 + print_u64_to_buffer(buffer, i as u64) + f -= i as f64 / mult + mult *= 10 + } +} + +print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) { + if ti == null { return } + + using Type_Info + match type info : ti { + case Named: + print_string_to_buffer(buf, info.name) + case Integer: + match { + case ti == type_info(int): + print_string_to_buffer(buf, "int") + case ti == type_info(uint): + print_string_to_buffer(buf, "uint") + default: + if info.signed { + print_string_to_buffer(buf, "i") + } else { + print_string_to_buffer(buf, "u") + } + print_int_to_buffer(buf, 8*info.size) + } + + case Float: + match info.size { + case 4: print_string_to_buffer(buf, "f32") + case 8: print_string_to_buffer(buf, "f64") + } + case String: print_string_to_buffer(buf, "string") + case Boolean: print_string_to_buffer(buf, "bool") + case Pointer: + print_string_to_buffer(buf, "^") + print_type_to_buffer(buf, info.elem) + case Procedure: + print_string_to_buffer(buf, "proc") + if info.params == null { + print_string_to_buffer(buf, "()") + } else { + count := (info.params as ^Tuple).fields.count + if count == 1 { print_string_to_buffer(buf, "(") } + print_type_to_buffer(buf, info.params) + if count == 1 { print_string_to_buffer(buf, ")") } + } + if info.results != null { + print_string_to_buffer(buf, " -> ") + print_type_to_buffer(buf, info.results) + } + case Tuple: + count := info.fields.count + if count != 1 { print_string_to_buffer(buf, "(") } + for i := 0; i < count; i++ { + if i > 0 { print_string_to_buffer(buf, ", ") } + + f := info.fields[i] + + if f.name.count > 0 { + print_string_to_buffer(buf, f.name) + print_string_to_buffer(buf, ": ") + } + print_type_to_buffer(buf, f.type_info) + } + if count != 1 { print_string_to_buffer(buf, ")") } + + case Array: + print_string_to_buffer(buf, "[") + print_int_to_buffer(buf, info.count) + print_string_to_buffer(buf, "]") + print_type_to_buffer(buf, info.elem) + case Slice: + print_string_to_buffer(buf, "[") + print_string_to_buffer(buf, "]") + print_type_to_buffer(buf, info.elem) + case Vector: + print_string_to_buffer(buf, "{") + print_int_to_buffer(buf, info.count) + print_string_to_buffer(buf, "}") + print_type_to_buffer(buf, info.elem) + + case Struct: + print_string_to_buffer(buf, "struct ") + if info.packed { print_string_to_buffer(buf, "#packed ") } + if info.ordered { print_string_to_buffer(buf, "#ordered ") } + print_string_to_buffer(buf, "{") + for i := 0; i < info.fields.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + print_any_to_buffer(buf, info.fields[i].name) + print_string_to_buffer(buf, ": ") + print_type_to_buffer(buf, info.fields[i].type_info) + } + print_string_to_buffer(buf, "}") + + case Union: + print_string_to_buffer(buf, "union {") + for i := 0; i < info.fields.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + print_any_to_buffer(buf, info.fields[i].name) + print_string_to_buffer(buf, ": ") + print_type_to_buffer(buf, info.fields[i].type_info) + } + print_string_to_buffer(buf, "}") + + case Raw_Union: + print_string_to_buffer(buf, "raw_union {") + for i := 0; i < info.fields.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + print_any_to_buffer(buf, info.fields[i].name) + print_string_to_buffer(buf, ": ") + print_type_to_buffer(buf, info.fields[i].type_info) + } + print_string_to_buffer(buf, "}") + + case Enum: + print_string_to_buffer(buf, "enum ") + print_type_to_buffer(buf, info.base) + print_string_to_buffer(buf, "{}") + } +} + + +print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { + using Type_Info + match type info : arg.type_info { + case Named: + a: any + a.type_info = info.base + a.data = arg.data + match type b : info.base { + case Struct: + print_string_to_buffer(buf, info.name) + print_string_to_buffer(buf, "{") + for i := 0; i < b.fields.count; i++ { + f := b.fields[i]; + if i > 0 { + print_string_to_buffer(buf, ", ") + } + print_any_to_buffer(buf, f.name) + print_string_to_buffer(buf, " = ") + v: any + v.type_info = f.type_info + v.data = ptr_offset(arg.data as ^byte, f.offset) + print_any_to_buffer(buf, v) + } + print_string_to_buffer(buf, "}") + + default: + print_any_to_buffer(buf, a) + } + + case Integer: + if info.signed { + i: int = 0; + if arg.data != null { + match info.size { + case 1: i = (arg.data as ^i8)^ as int + case 2: i = (arg.data as ^i16)^ as int + case 4: i = (arg.data as ^i32)^ as int + case 8: i = (arg.data as ^i64)^ as int + case 16: i = (arg.data as ^i128)^ as int + } + } + print_int_to_buffer(buf, i) + } else { + i: uint = 0; + if arg.data != null { + match info.size { + case 1: i = (arg.data as ^u8)^ as uint + case 2: i = (arg.data as ^u16)^ as uint + case 4: i = (arg.data as ^u32)^ as uint + case 8: i = (arg.data as ^u64)^ as uint + case 16: i = (arg.data as ^u128)^ as uint + } + } + print_uint_to_buffer(buf, i) + } + + case Float: + f: f64 = 0 + if arg.data != null { + match info.size { + case 4: f = (arg.data as ^f32)^ as f64 + case 8: f = (arg.data as ^f64)^ as f64 + } + } + print_f64_to_buffer(buf, f) + + case String: + s := "" + if arg.data != null { + s = (arg.data as ^string)^ + } + print_string_to_buffer(buf, s) + + case Boolean: + v := false; + if arg.data != null { + v = (arg.data as ^bool)^ + } + print_bool_to_buffer(buf, v) + + case Pointer: + v := null; + if arg.data != null { + v = (arg.data as ^rawptr)^ + } + print_pointer_to_buffer(buf, v) + + case Enum: + v: any + v.data = arg.data + v.type_info = info.base + print_any_to_buffer(buf, v) + + + case Array: + print_string_to_buffer(buf, "[") + defer print_string_to_buffer(buf, "]") + + for i := 0; i < info.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + + elem: any + elem.data = (arg.data as int + i*info.elem_size) as rawptr + elem.type_info = info.elem + print_any_to_buffer(buf, elem) + } + + case Slice: + slice := arg.data as ^[]byte + print_string_to_buffer(buf, "[") + defer print_string_to_buffer(buf, "]") + + for i := 0; i < slice.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + + elem: any + elem.data = ptr_offset(slice.data, i*info.elem_size) + elem.type_info = info.elem + print_any_to_buffer(buf, elem) + } + + case Vector: + print_string_to_buffer(buf, "<") + defer print_string_to_buffer(buf, ">") + + for i := 0; i < info.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + + elem: any + elem.data = ptr_offset(arg.data as ^byte, i*info.elem_size) + elem.type_info = info.elem + print_any_to_buffer(buf, elem) + } + + + case Struct: + print_string_to_buffer(buf, "struct") + print_string_to_buffer(buf, "{") + defer print_string_to_buffer(buf, "}") + + for i := 0; i < info.fields.count; i++ { + if i > 0 { + print_string_to_buffer(buf, ", ") + } + print_any_to_buffer(buf, info.fields[i].name) + print_string_to_buffer(buf, " = ") + a: any + a.data = ptr_offset(arg.data as ^byte, info.fields[i].offset) + a.type_info = info.fields[i].type_info + print_any_to_buffer(buf, a) + } + + case Union: + print_string_to_buffer(buf, "(union)") + case Raw_Union: + print_string_to_buffer(buf, "(raw_union)") + case Procedure: + print_type_to_buffer(buf, arg.type_info) + print_string_to_buffer(buf, " @ 0x") + print_pointer_to_buffer(buf, (arg.data as ^rawptr)^) + + default: + } +} + +type_info_is_string :: proc(info: ^Type_Info) -> bool { + using Type_Info + if info == null { + return false + } + + for { + match type i : info { + case Named: + info = i.base + continue + case String: + return true + default: + return false + } + } + return false +} + + +print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) { + is_digit :: proc(r: rune) -> bool #inline { + return r >= #rune "0" && r <= #rune "9" + } + + parse_int :: proc(s: string, offset: int) -> (int, int) { + result := 0 + + for ; offset < s.count; offset++ { + c := s[offset] as rune + if !is_digit(c) { + break + } + + result *= 10 + result += (c - #rune "0") as int + } + + return result, offset + } + + prev := 0 + implicit_index := 0 + + for i := 0; i < fmt.count; i++ { + r := fmt[i] as rune + index := implicit_index + + if r != #rune "%" { + continue + } + + print_string_to_buffer(buf, fmt[prev:i]) + i++ // Skip % + if i < fmt.count { + next := fmt[i] as rune + + if next == #rune "%" { + print_string_to_buffer(buf, "%") + i++ + prev = i + continue + } + + if is_digit(next) { + index, i = parse_int(fmt, i) + } + } + + if 0 <= index && index < args.count { + print_any_to_buffer(buf, args[index]) + implicit_index = index+1 + } else { + // TODO(bill): Error check index out bounds + print_string_to_buffer(buf, "") + } + + prev = i + } + + print_string_to_buffer(buf, fmt[prev:]) +} + +PRINT_BUF_SIZE :: 1<<12 + +print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + print_to_buffer(^buf, fmt, ..args) + os.write(f, buf) +} + +println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + print_to_buffer(^buf, fmt, ..args) + print_nl_to_buffer(^buf) + os.write(f, buf) +} + + +print :: proc(fmt: string, args: ..any) { + print_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args) +} +print_err :: proc(fmt: string, args: ..any) { + print_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args) +} +println :: proc(fmt: string, args: ..any) { + println_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args) +} +println_err :: proc(fmt: string, args: ..any) { + println_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args) +} diff --git a/code/os.odin b/code/os.odin new file mode 100644 index 000000000..dbfd7f723 --- /dev/null +++ b/code/os.odin @@ -0,0 +1,107 @@ +#import "runtime.odin" as _ // TODO(bill): make the compile import this automatically +#import "win32.odin" as win32 + +File :: type struct { + Handle :: type win32.HANDLE + handle: Handle +} + +open :: proc(name: string) -> (File, bool) { + using win32 + buf: [300]byte + copy(buf[:], name as []byte) + f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)} + success := f.handle != INVALID_HANDLE_VALUE as File.Handle + + return f, success +} + +create :: proc(name: string) -> (File, bool) { + using win32 + buf: [300]byte + copy(buf[:], name as []byte) + f := File{ + handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null), + } + success := f.handle != INVALID_HANDLE_VALUE as File.Handle + return f, success +} + + +close :: proc(using f: ^File) { + win32.CloseHandle(handle) +} + +write :: proc(using f: ^File, buf: []byte) -> bool { + bytes_written: i32 + return win32.WriteFile(handle, buf.data, buf.count as i32, ^bytes_written, null) != 0 +} + + +File_Standard :: type enum { + INPUT, + OUTPUT, + ERROR, + COUNT, +} + +__std_files := __set_file_standards(); + +__set_file_standards :: proc() -> [File_Standard.COUNT as int]File { + return [File_Standard.COUNT as int]File{ + File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)}, + File{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)}, + File{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE)}, + } +} + +get_standard_file :: proc(std: File_Standard) -> ^File { + return ^__std_files[std] +} + + +read_entire_file :: proc(name: string) -> (string, bool) { + buf: [300]byte + copy(buf[:], name as []byte) + + f, file_ok := open(name) + if !file_ok { + return "", false + } + defer close(^f) + + length: i64 + file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0 + if !file_size_ok { + return "", false + } + + data := new_slice(u8, length) + if data.data == null { + return "", false + } + + single_read_length: i32 + total_read: i64 + + for total_read < length { + remaining := length - total_read + to_read: u32 + MAX :: 1<<32-1 + if remaining <= MAX { + to_read = remaining as u32 + } else { + to_read = MAX + } + + win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, null) + if single_read_length <= 0 { + free(data.data) + return "", false + } + + total_read += single_read_length as i64 + } + + return data as string, true +} diff --git a/code/punity.odin b/code/punity.odin new file mode 100644 index 000000000..585d0b4b5 --- /dev/null +++ b/code/punity.odin @@ -0,0 +1,484 @@ +#import "win32.odin" as win32 +#import "fmt.odin" as _ + +CANVAS_WIDTH :: 128 +CANVAS_HEIGHT :: 128 +CANVAS_SCALE :: 3 +FRAME_TIME :: 1.0/30.0 +WINDOW_TITLE : string : "Punity\x00" + +_ := compile_assert(CANVAS_WIDTH % 16 == 0) + +WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE +WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE + + +STACK_CAPACITY :: 1<<20 +STORAGE_CAPACITY :: 1<<20 + +DRAW_LIST_RESERVE :: 128 + +MAX_KEYS :: 256 + +Core :: struct { + stack: ^Bank + storage: ^Bank + + running: bool + key_modifiers: u32 + key_states: [MAX_KEYS]byte + key_deltas: [MAX_KEYS]byte + + perf_frame, + perf_frame_inner, + perf_step, + perf_audio, + perf_blit, + perf_blit_cvt, + perf_blit_gdi: Perf_Span + + frame: i64 + + canvas: Canvas + draw_list: ^Draw_List +} + +Perf_Span :: struct { + stamp: f64 + delta: f32 +} + +Bank :: struct { + memory: []byte + cursor: int +} + +Bank_State :: struct { + state: Bank + bank: ^Bank +} + + +Color :: raw_union { + using channels: struct{ a, b, g, r: byte } + rgba: u32 +} + +Palette :: struct { + colors: [256]Color + colors_count: byte +} + + +Rect :: raw_union { + using minmax: struct { + min_x, min_y, max_x, max_y: int + } + using pos: struct { + left, top, right, bottom: int + } + e: [4]int +} + +Bitmap :: struct { + pixels: []byte + width: int + height: int +} + +Font :: struct { + using bitmap: Bitmap + char_width: int + char_height: int +} + +Canvas :: struct { + using bitmap: ^Bitmap + palette: Palette + translate_x: int + translate_y: int + clip: Rect + font: ^Font +} + +DrawFlag :: enum { + NONE = 0, + FLIP_H = 1<<0, + FLIP_V = 1<<1, + MASK = 1<<2, +} + + +Draw_List :: struct { + Item :: struct { + + } + items: []Item +} + +Key :: enum { + MOD_SHIFT = 0x0001, + MOD_CONTROL = 0x0002, + MOD_ALT = 0x0004, + MOD_SUPER = 0x0008, + + UNKNOWN =-1, + INVALID =-2, + + LBUTTON = 1, + RBUTTON = 2, + CANCEL = 3, + MBUTTON = 4, + + BACK = 8, + TAB = 9, + CLEAR = 12, + RETURN = 13, + SHIFT = 16, + CONTROL = 17, + MENU = 18, + PAUSE = 19, + CAPITAL = 20, + KANA = 0x15, + HANGEUL = 0x15, + HANGUL = 0x15, + JUNJA = 0x17, + FINAL = 0x18, + HANJA = 0x19, + KANJI = 0x19, + ESCAPE = 0x1B, + CONVERT = 0x1C, + NONCONVERT = 0x1D, + ACCEPT = 0x1E, + MODECHANGE = 0x1F, + SPACE = 32, + PRIOR = 33, + NEXT = 34, + END = 35, + HOME = 36, + LEFT = 37, + UP = 38, + RIGHT = 39, + DOWN = 40, + SELECT = 41, + PRINT = 42, + EXEC = 43, + SNAPSHOT = 44, + INSERT = 45, + DELETE = 46, + HELP = 47, + LWIN = 0x5B, + RWIN = 0x5C, + APPS = 0x5D, + SLEEP = 0x5F, + NUMPAD0 = 0x60, + NUMPAD1 = 0x61, + NUMPAD2 = 0x62, + NUMPAD3 = 0x63, + NUMPAD4 = 0x64, + NUMPAD5 = 0x65, + NUMPAD6 = 0x66, + NUMPAD7 = 0x67, + NUMPAD8 = 0x68, + NUMPAD9 = 0x69, + MULTIPLY = 0x6A, + ADD = 0x6B, + SEPARATOR = 0x6C, + SUBTRACT = 0x6D, + DECIMAL = 0x6E, + DIVIDE = 0x6F, + F1 = 0x70, + F2 = 0x71, + F3 = 0x72, + F4 = 0x73, + F5 = 0x74, + F6 = 0x75, + F7 = 0x76, + F8 = 0x77, + F9 = 0x78, + F10 = 0x79, + F11 = 0x7A, + F12 = 0x7B, + F13 = 0x7C, + F14 = 0x7D, + F15 = 0x7E, + F16 = 0x7F, + F17 = 0x80, + F18 = 0x81, + F19 = 0x82, + F20 = 0x83, + F21 = 0x84, + F22 = 0x85, + F23 = 0x86, + F24 = 0x87, + NUMLOCK = 0x90, + SCROLL = 0x91, + LSHIFT = 0xA0, + RSHIFT = 0xA1, + LCONTROL = 0xA2, + RCONTROL = 0xA3, + LMENU = 0xA4, + RMENU = 0xA5, + + APOSTROPHE = 39, /* ' */ + COMMA = 44, /* , */ + MINUS = 45, /* - */ + PERIOD = 46, /* . */ + SLASH = 47, /* / */ + NUM0 = 48, + NUM1 = 49, + NUM2 = 50, + NUM3 = 51, + NUM4 = 52, + NUM5 = 53, + NUM6 = 54, + NUM7 = 55, + NUM8 = 56, + NUM9 = 57, + SEMICOLON = 59, /* ; */ + EQUAL = 61, /* = */ + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + LEFT_BRACKET = 91, /* [ */ + BACKSLASH = 92, /* \ */ + RIGHT_BRACKET = 93, /* ] */ + GRAVE_ACCENT = 96, /* ` */ +} + + +key_down :: proc(k: Key) -> bool { + return _core.key_states[k] != 0 +} + +key_pressed :: proc(k: Key) -> bool { + return (_core.key_deltas[k] != 0) && key_down(k) +} + + + + +win32_perf_count_freq := win32.GetQueryPerformanceFrequency() +time_now :: proc() -> f64 { + assert(win32_perf_count_freq != 0) + + counter: i64 + win32.QueryPerformanceCounter(^counter) + result := counter as f64 / win32_perf_count_freq as f64 + return result +} + +_core: Core + +run :: proc(user_init, user_step: proc(c: ^Core)) { + using win32 + + + _core.running = true + + win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline #stdcall { + win32_app_key_mods :: proc() -> u32 { + mods: u32 = 0 + + if is_key_down(Key_Code.SHIFT) { + mods |= Key.MOD_SHIFT as u32; + } + if is_key_down(Key_Code.CONTROL) { + mods |= Key.MOD_CONTROL as u32; + } + if is_key_down(Key_Code.MENU) { + mods |= Key.MOD_ALT as u32; + } + if is_key_down(Key_Code.LWIN) || is_key_down(Key_Code.RWIN) { + mods |= Key.MOD_SUPER as u32; + } + + return mods + } + + match msg { + case WM_KEYDOWN: + _core.key_modifiers = win32_app_key_mods() + if wparam < MAX_KEYS { + _core.key_states[wparam] = 1 + _core.key_deltas[wparam] = 1 + } + return 0 + + case WM_KEYUP: + _core.key_modifiers = win32_app_key_mods() + if wparam < MAX_KEYS { + _core.key_states[wparam] = 0 + _core.key_deltas[wparam] = 1 + } + return 0 + + case WM_CLOSE: + PostQuitMessage(0) + _core.running = false + return 0 + } + + return DefWindowProcA(hwnd, msg, wparam, lparam) + } + + + window_class := WNDCLASSEXA{ + class_name = ("Punity\x00" as string).data, // C-style string + size = size_of(WNDCLASSEXA) as u32, + style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC, + instance = GetModuleHandleA(null) as HINSTANCE, + wnd_proc = win32_proc, + // wnd_proc = DefWindowProcA, + background = GetStockObject(BLACK_BRUSH) as HBRUSH, + } + + if RegisterClassExA(^window_class) == 0 { + /*fmt.*/println_err("RegisterClassExA failed") + return + } + + screen_width := GetSystemMetrics(SM_CXSCREEN) + screen_height := GetSystemMetrics(SM_CYSCREEN) + + rc: RECT + rc.left = (screen_width - WINDOW_WIDTH) / 2 + rc.top = (screen_height - WINDOW_HEIGHT) / 2 + rc.right = rc.left + WINDOW_WIDTH + rc.bottom = rc.top + WINDOW_HEIGHT + + style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX + assert(AdjustWindowRect(^rc, style, 0) != 0) + + wt := WINDOW_TITLE + + win32_window := CreateWindowExA(0, + window_class.class_name, + WINDOW_TITLE.data, + // wt.data, + style, + rc.left, rc.top, + rc.right-rc.left, rc.bottom-rc.top, + null, null, window_class.instance, + null); + + if win32_window == null { + /*fmt.*/println_err("CreateWindowExA failed") + return + } + + + window_bmi: BITMAPINFO; + window_bmi.size = size_of(BITMAPINFO.HEADER) as u32 + window_bmi.width = CANVAS_WIDTH + window_bmi.height = CANVAS_HEIGHT + window_bmi.planes = 1 + window_bmi.bit_count = 32 + window_bmi.compression = BI_RGB + + + user_init(^_core) + + + ShowWindow(win32_window, SW_SHOW) + + window_buffer := new_slice(u32, CANVAS_WIDTH * CANVAS_HEIGHT); + assert(window_buffer.data != null) + defer free(window_buffer.data) + + for i := 0; i < window_buffer.count; i++ { + window_buffer[i] = 0xff00ff + } + + + prev_time, curr_time,dt: f64 + prev_time = time_now() + curr_time = time_now() + total_time : f64 = 0 + offset_x := 0; + offset_y := 0; + + message: MSG + for _core.running { + curr_time = time_now() + dt = curr_time - prev_time + prev_time = curr_time + total_time += dt + + offset_x += 1 + offset_y += 2 + + { + data: [128]byte + buf := data[:0] + /*fmt.*/print_to_buffer(^buf, "Punity: % ms\x00", dt*1000) + win32.SetWindowTextA(win32_window, buf.data) + } + + + for y := 0; y < CANVAS_HEIGHT; y++ { + for x := 0; x < CANVAS_WIDTH; x++ { + g := (x % 32) * 8 + b := (y % 32) * 8 + window_buffer[x + y*CANVAS_WIDTH] = (g << 8 | b) as u32 + } + } + + memory_zero(^_core.key_deltas[0], size_of(_core.key_deltas[0])) + + + for PeekMessageA(^message, null, 0, 0, PM_REMOVE) != 0 { + if message.message == WM_QUIT { + _core.running = false + } + TranslateMessage(^message) + DispatchMessageA(^message) + } + + user_step(^_core) + + dc := GetDC(win32_window); + StretchDIBits(dc, + 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE, + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + window_buffer.data, + ^window_bmi, + DIB_RGB_COLORS, + SRCCOPY) + ReleaseDC(win32_window, dc) + + + { + delta := time_now() - prev_time + ms := ((FRAME_TIME - delta) * 1000) as i32 + if ms > 0 { + win32.Sleep(ms) + } + } + + _core.frame++ + } +} diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 0f2ccc8b1..99d04799f 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -237,8 +237,6 @@ struct Checker { gbArray(Type *) proc_stack; b32 in_defer; // TODO(bill): Actually handle correctly - - ErrorCollector error_collector; }; gb_global Scope *universal_scope = NULL; @@ -635,18 +633,23 @@ b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { if (insert_entity) { Entity *up = insert_entity->using_parent; if (up != NULL) { - error(&c->error_collector, entity->token, + error(entity->token, "Redeclararation of `%.*s` in this scope through `using`\n" "\tat %.*s(%td:%td)", LIT(entity->token.string), LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); return false; } else { - error(&c->error_collector, entity->token, + TokenPos pos = insert_entity->token.pos; + if (token_pos_are_equal(pos, entity->token.pos)) { + // NOTE(bill): Error should have been handled already + return false; + } + error(entity->token, "Redeclararation of `%.*s` in this scope\n" "\tat %.*s(%td:%td)", LIT(entity->token.string), - LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column); + LIT(pos.file), pos.line, pos.column); return false; } } @@ -797,7 +800,7 @@ Type *const curr_procedure(Checker *c) { void add_curr_ast_file(Checker *c, AstFile *file) { TokenPos zero_pos = {}; - c->error_collector.prev = zero_pos; + global_error_collector.prev = zero_pos; c->curr_ast_file = file; } @@ -924,64 +927,60 @@ void check_parsed_files(Checker *c) { // NOTE(bill): ignore case_end; + case_ast_node(cd, ConstDecl, decl); + gb_for_array(i, cd->values) { + AstNode *name = cd->names[i]; + AstNode *value = cd->values[i]; + ExactValue v = {ExactValue_Invalid}; + Entity *e = make_entity_constant(c->allocator, file_scope, name->Ident, NULL, v); + DeclInfo *di = make_declaration_info(c->allocator, file_scope); + di->type_expr = cd->type; + di->init_expr = value; + add_file_entity(c, file_scope, name, e, di); + } + + isize lhs_count = gb_array_count(cd->names); + isize rhs_count = gb_array_count(cd->values); + + if (rhs_count == 0 && cd->type == NULL) { + error(ast_node_token(decl), "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error(ast_node_token(decl), "Extra initial expression"); + } + case_end; + case_ast_node(vd, VarDecl, decl); - switch (vd->kind) { - case Declaration_Immutable: { - gb_for_array(i, vd->values) { - AstNode *name = vd->names[i]; - AstNode *value = vd->values[i]; - ExactValue v = {ExactValue_Invalid}; - Entity *e = make_entity_constant(c->allocator, file_scope, name->Ident, NULL, v); - DeclInfo *di = make_declaration_info(c->allocator, file_scope); - di->type_expr = vd->type; - di->init_expr = value; - add_file_entity(c, file_scope, name, e, di); + isize entity_count = gb_array_count(vd->names); + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + DeclInfo *di = NULL; + if (gb_array_count(vd->values) > 0) { + di = make_declaration_info(gb_heap_allocator(), file_scope); + di->entities = entities; + di->entity_count = entity_count; + di->type_expr = vd->type; + di->init_expr = vd->values[0]; // TODO(bill): Is this correct? + } + + gb_for_array(i, vd->names) { + AstNode *name = vd->names[i]; + AstNode *value = NULL; + if (i < gb_array_count(vd->values)) { + value = vd->values[i]; + } + Entity *e = make_entity_variable(c->allocator, file_scope, name->Ident, NULL); + entities[entity_index++] = e; + + DeclInfo *d = di; + if (d == NULL) { + AstNode *init_expr = value; + d = make_declaration_info(gb_heap_allocator(), file_scope); + d->type_expr = vd->type; + d->init_expr = init_expr; + d->var_decl_tags = vd->tags; } - isize lhs_count = gb_array_count(vd->names); - isize rhs_count = gb_array_count(vd->values); - - if (rhs_count == 0 && vd->type == NULL) { - error(&c->error_collector, ast_node_token(decl), "Missing type or initial expression"); - } else if (lhs_count < rhs_count) { - error(&c->error_collector, ast_node_token(decl), "Extra initial expression"); - } - } break; - - case Declaration_Mutable: { - isize entity_count = gb_array_count(vd->names); - isize entity_index = 0; - Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); - DeclInfo *di = NULL; - if (gb_array_count(vd->values) > 0) { - di = make_declaration_info(gb_heap_allocator(), file_scope); - di->entities = entities; - di->entity_count = entity_count; - di->type_expr = vd->type; - di->init_expr = vd->values[0]; // TODO(bill): Is this correct? - } - - gb_for_array(i, vd->names) { - AstNode *name = vd->names[i]; - AstNode *value = NULL; - if (i < gb_array_count(vd->values)) { - value = vd->values[i]; - } - Entity *e = make_entity_variable(c->allocator, file_scope, name->Ident, NULL); - entities[entity_index++] = e; - - DeclInfo *d = di; - if (d == NULL) { - AstNode *init_expr = value; - d = make_declaration_info(gb_heap_allocator(), file_scope); - d->type_expr = vd->type; - d->init_expr = init_expr; - d->var_decl_tags = vd->tags; - } - - add_file_entity(c, file_scope, name, e, d); - } - } break; + add_file_entity(c, file_scope, name, e, d); } case_end; @@ -1003,7 +1002,7 @@ void check_parsed_files(Checker *c) { case_end; default: - error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope"); + error(ast_node_token(decl), "Only declarations are allowed at file scope"); break; } } @@ -1046,13 +1045,11 @@ void check_parsed_files(Checker *c) { continue; } // NOTE(bill): Do not add other imported entities - if (e->kind != Entity_ImportName) { - if (is_entity_exported(e)) { - add_entity(c, file_scope, NULL, e); - if (!id->is_load) { - HashKey key = hash_string(e->token.string); - map_set(&file_scope->implicit, key, e); - } + if (is_entity_exported(e)) { + add_entity(c, file_scope, NULL, e); + if (!id->is_load) { // `#import`ed entities don't get exported + HashKey key = hash_string(e->token.string); + map_set(&file_scope->implicit, key, e); } } } diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index 3a4ffb191..fd9c5ce8a 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -67,6 +67,9 @@ struct Entity { }; b32 is_entity_exported(Entity *e) { + if (e->kind == Entity_ImportName) { + return false; + } // TODO(bill): Do I really want non-exported entities? // if (e->token.string.len >= 1 && // e->token.string.text[0] == '_') { diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 83fe981be..a16315d4c 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -166,13 +166,13 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n if (operand->mode == Addressing_Builtin) { // TODO(bill): is this a good enough error message? - error(&c->error_collector, ast_node_token(operand->expr), + error(ast_node_token(operand->expr), "Cannot assign builtin procedure `%s` in %.*s", expr_str, LIT(context_name)); } else { // TODO(bill): is this a good enough error message? - error(&c->error_collector, ast_node_token(operand->expr), + error(ast_node_token(operand->expr), "Cannot assign value `%s` of type `%s` to `%s` in %.*s", expr_str, op_type_string, @@ -201,7 +201,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map if (found != NULL) { Entity *e = *found; // TODO(bill): Better type error - error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str); + error(e->token, "`%.*s` is already declared in `%s`", LIT(name), str); } else { map_set(entity_map, key, f); add_entity(c, c->context.scope, NULL, f); @@ -236,45 +236,43 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, #endif gb_for_array(decl_index, decls) { AstNode *decl = decls[decl_index]; - if (decl->kind == AstNode_VarDecl) { - ast_node(vd, VarDecl, decl); - if (vd->kind != Declaration_Immutable) - continue; + if (decl->kind == AstNode_ConstDecl) { + ast_node(cd, ConstDecl, decl); - isize entity_count = gb_array_count(vd->names); + isize entity_count = gb_array_count(cd->names); isize entity_index = 0; Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); - gb_for_array(i, vd->values) { - AstNode *name = vd->names[i]; - AstNode *value = vd->values[i]; + gb_for_array(i, cd->values) { + AstNode *name = cd->names[i]; + AstNode *value = cd->values[i]; GB_ASSERT(name->kind == AstNode_Ident); ExactValue v = {ExactValue_Invalid}; Token name_token = name->Ident; Entity *e = make_entity_constant(c->allocator, c->context.scope, name_token, NULL, v); entities[entity_index++] = e; - check_const_decl(c, e, vd->type, value); + check_const_decl(c, e, cd->type, value); } - isize lhs_count = gb_array_count(vd->names); - isize rhs_count = gb_array_count(vd->values); + isize lhs_count = gb_array_count(cd->names); + isize rhs_count = gb_array_count(cd->values); // TODO(bill): Better error messages or is this good enough? - if (rhs_count == 0 && vd->type == NULL) { - error(&c->error_collector, ast_node_token(node), "Missing type or initial expression"); + if (rhs_count == 0 && cd->type == NULL) { + error(ast_node_token(node), "Missing type or initial expression"); } else if (lhs_count < rhs_count) { - error(&c->error_collector, ast_node_token(node), "Extra initial expression"); + error(ast_node_token(node), "Extra initial expression"); } - gb_for_array(i, vd->names) { - AstNode *name = vd->names[i]; + gb_for_array(i, cd->names) { + AstNode *name = cd->names[i]; Entity *e = entities[i]; Token name_token = name->Ident; HashKey key = hash_string(name_token.string); if (map_get(&entity_map, key) != NULL) { // TODO(bill): Scope checking already checks the declaration - error(&c->error_collector, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string)); + error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string)); } else { map_set(&entity_map, key, e); other_fields[other_field_index++] = e; @@ -292,7 +290,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, HashKey key = hash_string(name_token.string); if (map_get(&entity_map, key) != NULL) { // TODO(bill): Scope checking already checks the declaration - error(&c->error_collector, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string)); + error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string)); } else { map_set(&entity_map, key, e); other_fields[other_field_index++] = e; @@ -312,9 +310,6 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, } ast_node(vd, VarDecl, decl); - if (vd->kind != Declaration_Mutable) { - continue; - } Type *base_type = check_type(c, vd->type, NULL, cycle_checker); gb_for_array(name_index, vd->names) { @@ -329,7 +324,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, HashKey key = hash_string(name_token.string); if (map_get(&entity_map, key) != NULL) { // TODO(bill): Scope checking already checks the declaration - error(&c->error_collector, name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); + error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); } else { map_set(&entity_map, key, e); fields[field_index++] = e; @@ -345,14 +340,12 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, continue; } ast_node(vd, VarDecl, decl); - if (vd->kind != Declaration_Mutable) { - continue; - } + Type *type = check_type(c, vd->type, NULL, cycle_checker); if (vd->is_using) { if (gb_array_count(vd->names) > 1) { - error(&c->error_collector, ast_node_token(vd->names[0]), + error(ast_node_token(vd->names[0]), "Cannot apply `using` to more than one of the same type"); } } @@ -365,7 +358,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, HashKey key = hash_string(name_token.string); if (map_get(&entity_map, key) != NULL) { // TODO(bill): Scope checking already checks the declaration - error(&c->error_collector, name_token, "`%.*s` is already declared in this type", LIT(name_token.string)); + error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string)); } else { map_set(&entity_map, key, e); fields[field_index] = e; @@ -380,7 +373,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Type *t = get_base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t)) { Token name_token = vd->names[0]->Ident; - error(&c->error_collector, name_token, "`using` on a field `%.*s` must be a type", LIT(name_token.string)); + error(name_token, "`using` on a field `%.*s` must be a type", LIT(name_token.string)); continue; } @@ -423,11 +416,11 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke AstNode *decl = st->decls[decl_index]; switch (decl->kind) { case_ast_node(vd, VarDecl, decl); - if (vd->kind == Declaration_Mutable) { - field_count += gb_array_count(vd->names); - } else { - other_field_count += gb_array_count(vd->names); - } + field_count += gb_array_count(vd->names); + case_end; + + case_ast_node(cd, ConstDecl, decl); + other_field_count += gb_array_count(cd->names); case_end; case_ast_node(td, TypeDecl, decl); @@ -483,11 +476,11 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker AstNode *decl = ut->decls[decl_index]; switch (decl->kind) { case_ast_node(vd, VarDecl, decl); - if (vd->kind == Declaration_Mutable) { - field_count += gb_array_count(vd->names); - } else { - other_field_count += gb_array_count(vd->names); - } + field_count += gb_array_count(vd->names); + case_end; + + case_ast_node(cd, ConstDecl, decl); + other_field_count += gb_array_count(cd->names); case_end; case_ast_node(td, TypeDecl, decl); @@ -518,11 +511,11 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node, CycleChec AstNode *decl = ut->decls[decl_index]; switch (decl->kind) { case_ast_node(vd, VarDecl, decl); - if (vd->kind == Declaration_Mutable) { - field_count += gb_array_count(vd->names); - } else { - other_field_count += gb_array_count(vd->names); - } + field_count += gb_array_count(vd->names); + case_end; + + case_ast_node(cd, ConstDecl, decl); + other_field_count += gb_array_count(cd->names); case_end; case_ast_node(td, TypeDecl, decl); @@ -558,7 +551,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod } if (base_type == NULL || !is_type_integer(base_type)) { - error(&c->error_collector, et->token, "Base type for enumeration must be an integer"); + error(et->token, "Base type for enumeration must be an integer"); return; } else if (base_type == NULL) { @@ -579,7 +572,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod if (f->value != NULL) { check_expr(c, &o, f->value); if (o.mode != Addressing_Constant) { - error(&c->error_collector, ast_node_token(f->value), "Enumeration value must be a constant integer"); + error(ast_node_token(f->value), "Enumeration value must be a constant integer"); o.mode = Addressing_Invalid; } if (o.mode != Addressing_Invalid) { @@ -605,7 +598,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod HashKey key = hash_string(name_token.string); if (map_get(&entity_map, key)) { // TODO(bill): Scope checking already checks the declaration - error(&c->error_collector, name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string)); + error(name_token, "`%.*s` is already declared in this enumeration", LIT(name_token.string)); } else { map_set(&entity_map, key, e); fields[field_index++] = e; @@ -643,7 +636,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_va if (i+1 == gb_array_count(fields)) { is_variadic = true; } else { - error(&c->error_collector, ast_node_token(field), "Invalid AST: Invalid variadic parameter"); + error(ast_node_token(field), "Invalid AST: Invalid variadic parameter"); } } @@ -655,7 +648,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_va add_entity(c, scope, name, param); variables[variable_index++] = param; } else { - error(&c->error_collector, ast_node_token(name), "Invalid AST: Invalid parameter"); + error(ast_node_token(name), "Invalid AST: Invalid parameter"); } } } @@ -731,7 +724,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string); if (e == NULL) { if (are_strings_equal(n->Ident.string, make_string("_"))) { - error(&c->error_collector, n->Ident, "`_` cannot be used as a value type"); + error(n->Ident, "`_` cannot be used as a value type"); } else { auto *entries = c->context.scope->elements.entries; // gb_for_array(i, entries) { @@ -750,7 +743,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl // Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string); - error(&c->error_collector, n->Ident, + error(n->Ident, "Undeclared name: %.*s", LIT(n->Ident.string)); } return; @@ -799,12 +792,12 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl gb_for_array(i, cycle_checker->path) { Entity *prev = cycle_checker->path[i]; if (prev == e) { - error(&c->error_collector, e->token, "Illegal declaration cycle for %.*s", LIT(e->token.string)); + error(e->token, "Illegal declaration cycle for %.*s", LIT(e->token.string)); for (isize j = i; j < gb_array_count(cycle_checker->path); j++) { Entity *ref = cycle_checker->path[j]; - error(&c->error_collector, ref->token, "\t%.*s refers to", LIT(ref->token.string)); + error(ref->token, "\t%.*s refers to", LIT(ref->token.string)); } - error(&c->error_collector, e->token, "\t%.*s", LIT(e->token.string)); + error(e->token, "\t%.*s", LIT(e->token.string)); type = t_invalid; break; } @@ -823,7 +816,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl break; case Entity_ImportName: - error(&c->error_collector, ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name)); + error(ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name)); return; default: @@ -842,7 +835,7 @@ i64 check_array_count(Checker *c, AstNode *e) { check_expr(c, &o, e); if (o.mode != Addressing_Constant) { if (o.mode != Addressing_Invalid) { - error(&c->error_collector, ast_node_token(e), "Array count must be a constant"); + error(ast_node_token(e), "Array count must be a constant"); } return 0; } @@ -851,12 +844,12 @@ i64 check_array_count(Checker *c, AstNode *e) { i64 count = o.value.value_integer; if (count >= 0) return count; - error(&c->error_collector, ast_node_token(e), "Invalid array count"); + error(ast_node_token(e), "Invalid array count"); return 0; } } - error(&c->error_collector, ast_node_token(e), "Array count must be an integer"); + error(ast_node_token(e), "Array count must be an integer"); return 0; } @@ -868,26 +861,25 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c switch (e->kind) { case_ast_node(i, Ident, e); - Operand operand = {}; - check_identifier(c, &operand, e, named_type, cycle_checker); - switch (operand.mode) { + Operand o = {}; + check_identifier(c, &o, e, named_type, cycle_checker); + + switch (o.mode) { + case Addressing_Invalid: + break; case Addressing_Type: { - type = operand.type; + type = o.type; type->flags |= e->type_flags; set_base_type(named_type, type); goto end; } break; - - case Addressing_Invalid: - break; - case Addressing_NoValue: err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` used as a type", err_str); + error(ast_node_token(e), "`%s` used as a type", err_str); break; default: err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` used as a type when not a type", err_str); + error(ast_node_token(e), "`%s` used as a type when not a type", err_str); break; } case_end; @@ -897,27 +889,22 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c check_selector(c, &o, e); switch (o.mode) { - case Addressing_Type: - GB_ASSERT(o.type != NULL); - set_base_type(type, o.type); - o.type->flags |= e->type_flags; - return o.type; - case Addressing_Invalid: break; - case Addressing_NoValue: { - gbString err = expr_to_string(e); - defer (gb_string_free(err)); - error(&c->error_collector, ast_node_token(e), "`%s` used as a type", err); - } break; - default: { - gbString err = expr_to_string(e); - defer (gb_string_free(err)); - error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err); - } break; - } - - if (o.mode == Addressing_Type) { + case Addressing_Type: + GB_ASSERT(o.type != NULL); + type = o.type; + type->flags |= e->type_flags; + set_base_type(named_type, type); + return type; + case Addressing_NoValue: + err_str = expr_to_string(e); + error(ast_node_token(e), "`%s` used as a type", err_str); + break; + default: + err_str = expr_to_string(e); + error(ast_node_token(e), "`%s` is not a type", err_str); + break; } case_end; @@ -947,7 +934,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c i64 count = check_array_count(c, vt->count); if (!is_type_boolean(be) && !is_type_numeric(be)) { err_str = type_to_string(elem); - error(&c->error_collector, ast_node_token(vt->elem), "Vector element type must be numerical or a boolean. Got `%s`", err_str); + error(ast_node_token(vt->elem), "Vector element type must be numerical or a boolean. Got `%s`", err_str); } type = make_type_vector(c->allocator, elem, count); set_base_type(named_type, type); @@ -1018,7 +1005,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c } err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err_str); + error(ast_node_token(e), "`%s` is not a type", err_str); } break; } @@ -1043,25 +1030,25 @@ b32 check_unary_op(Checker *c, Operand *o, Token op) { case Token_Sub: if (!is_type_numeric(type)) { str = expr_to_string(o->expr); - error(&c->error_collector, op, "Operator `%.*s` is not allowed with `%s`", LIT(op.string), str); + error(op, "Operator `%.*s` is not allowed with `%s`", LIT(op.string), str); } break; case Token_Xor: if (!is_type_integer(type)) { - error(&c->error_collector, op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); + error(op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); } break; case Token_Not: if (!is_type_boolean(type)) { str = expr_to_string(o->expr); - error(&c->error_collector, op, "Operator `%.*s` is only allowed on boolean expression", LIT(op.string)); + error(op, "Operator `%.*s` is only allowed on boolean expression", LIT(op.string)); } break; default: - error(&c->error_collector, op, "Unknown operator `%.*s`", LIT(op.string)); + error(op, "Unknown operator `%.*s`", LIT(op.string)); return false; } @@ -1082,7 +1069,7 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { case Token_MulEq: case Token_QuoEq: if (!is_type_numeric(type)) { - error(&c->error_collector, op, "Operator `%.*s` is only allowed with numeric expressions", LIT(op.string)); + error(op, "Operator `%.*s` is only allowed with numeric expressions", LIT(op.string)); return false; } break; @@ -1099,7 +1086,7 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { case Token_XorEq: case Token_AndNotEq: if (!is_type_integer(type)) { - error(&c->error_collector, op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); + error(op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); return false; } break; @@ -1110,13 +1097,13 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { case Token_CmpAndEq: case Token_CmpOrEq: if (!is_type_boolean(type)) { - error(&c->error_collector, op, "Operator `%.*s` is only allowed with boolean expressions", LIT(op.string)); + error(op, "Operator `%.*s` is only allowed with boolean expressions", LIT(op.string)); return false; } break; default: - error(&c->error_collector, op, "Unknown operator `%.*s`", LIT(op.string)); + error(op, "Unknown operator `%.*s`", LIT(op.string)); return false; } @@ -1204,12 +1191,12 @@ void check_is_expressible(Checker *c, Operand *o, Type *type) { defer (gb_string_free(b)); if (is_type_numeric(o->type) && is_type_numeric(type)) { if (!is_type_integer(o->type) && is_type_integer(type)) { - error(&c->error_collector, ast_node_token(o->expr), "`%s` truncated to `%s`", a, b); + error(ast_node_token(o->expr), "`%s` truncated to `%s`", a, b); } else { - error(&c->error_collector, ast_node_token(o->expr), "`%s = %lld` overflows `%s`", a, o->value.value_integer, b); + error(ast_node_token(o->expr), "`%s = %lld` overflows `%s`", a, o->value.value_integer, b); } } else { - error(&c->error_collector, ast_node_token(o->expr), "Cannot convert `%s` to `%s`", a, b); + error(ast_node_token(o->expr), "Cannot convert `%s` to `%s`", a, b); } o->mode = Addressing_Invalid; @@ -1236,7 +1223,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { ast_node(ue, UnaryExpr, node); gbString str = expr_to_string(ue->expr); defer (gb_string_free(str)); - error(&c->error_collector, op, "Cannot take the pointer address of `%s`", str); + error(op, "Cannot take the pointer address of `%s`", str); o->mode = Addressing_Invalid; return; } @@ -1308,7 +1295,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { } if (err_str != NULL) { - error(&c->error_collector, op, "Cannot compare expression, %s", err_str); + error(op, "Cannot compare expression, %s", err_str); x->type = t_untyped_bool; return; } @@ -1344,7 +1331,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) { gbString err_str = expr_to_string(x->expr); defer (gb_string_free(err_str)); - error(&c->error_collector, ast_node_token(node), + error(ast_node_token(node), "Shifted operand `%s` must be an integer", err_str); x->mode = Addressing_Invalid; return; @@ -1361,7 +1348,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { } else { gbString err_str = expr_to_string(y->expr); defer (gb_string_free(err_str)); - error(&c->error_collector, ast_node_token(node), + error(ast_node_token(node), "Shift amount `%s` must be an unsigned integer", err_str); x->mode = Addressing_Invalid; return; @@ -1374,7 +1361,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { if (y_val.kind != ExactValue_Integer) { gbString err_str = expr_to_string(y->expr); defer (gb_string_free(err_str)); - error(&c->error_collector, ast_node_token(node), + error(ast_node_token(node), "Shift amount `%s` must be an unsigned integer", err_str); x->mode = Addressing_Invalid; return; @@ -1384,7 +1371,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { if (amount > 1074) { gbString err_str = expr_to_string(y->expr); defer (gb_string_free(err_str)); - error(&c->error_collector, ast_node_token(node), + error(ast_node_token(node), "Shift amount too large: `%s`", err_str); x->mode = Addressing_Invalid; return; @@ -1417,7 +1404,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { if (y->mode == Addressing_Constant && y->value.value_integer < 0) { gbString err_str = expr_to_string(y->expr); defer (gb_string_free(err_str)); - error(&c->error_collector, ast_node_token(node), + error(ast_node_token(node), "Shift amount cannot be negative: `%s`", err_str); } @@ -1558,7 +1545,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { defer (gb_string_free(expr_str)); defer (gb_string_free(to_type)); defer (gb_string_free(from_type)); - error(&c->error_collector, ast_node_token(x->expr), "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type); + error(ast_node_token(x->expr), "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type); x->mode = Addressing_Invalid; return; @@ -1583,7 +1570,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (x->mode == Addressing_Constant) { gbString expr_str = expr_to_string(x->expr); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute constant expression: `%s`", expr_str); + error(ast_node_token(x->expr), "Cannot transmute constant expression: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1591,7 +1578,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (is_type_untyped(x->type)) { gbString expr_str = expr_to_string(x->expr); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute untyped expression: `%s`", expr_str); + error(ast_node_token(x->expr), "Cannot transmute untyped expression: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1603,7 +1590,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { gbString type_str = type_to_string(type); defer (gb_string_free(expr_str)); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(x->expr), "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, otz, ttz); + error(ast_node_token(x->expr), "Cannot transmute `%s` to `%s`, %lld vs %lld bytes", expr_str, type_str, otz, ttz); x->mode = Addressing_Invalid; return; } @@ -1620,7 +1607,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (x->mode == Addressing_Constant) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(node), "Cannot `down_cast` a constant expression: `%s`", expr_str); + error(ast_node_token(node), "Cannot `down_cast` a constant expression: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1628,7 +1615,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (is_type_untyped(x->type)) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(node), "Cannot `down_cast` an untyped expression: `%s`", expr_str); + error(ast_node_token(node), "Cannot `down_cast` an untyped expression: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1636,7 +1623,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (!(is_type_pointer(x->type) && is_type_pointer(type))) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(node), "Can only `down_cast` pointers: `%s`", expr_str); + error(ast_node_token(node), "Can only `down_cast` pointers: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1649,7 +1636,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (!(is_type_struct(bsrc) || is_type_raw_union(bsrc))) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(node), "Can only `down_cast` pointer from structs or unions: `%s`", expr_str); + error(ast_node_token(node), "Can only `down_cast` pointer from structs or unions: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1657,7 +1644,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (!(is_type_struct(bdst) || is_type_struct(bdst))) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(node), "Can only `down_cast` pointer to structs or unions: `%s`", expr_str); + error(ast_node_token(node), "Can only `down_cast` pointer to structs or unions: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1666,7 +1653,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (param_name.len == 0) { gbString expr_str = expr_to_string(node); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(node), "Illegal `down_cast`: `%s`", expr_str); + error(ast_node_token(node), "Illegal `down_cast`: `%s`", expr_str); x->mode = Addressing_Invalid; return; } @@ -1716,7 +1703,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { defer (gb_string_free(xt)); defer (gb_string_free(yt)); err_str = expr_to_string(x->expr); - error(&c->error_collector, op, "Mismatched types in binary expression `%s` : `%s` vs `%s`", err_str, xt, yt); + error(op, "Mismatched types in binary expression `%s` : `%s` vs `%s`", err_str, xt, yt); } x->mode = Addressing_Invalid; return; @@ -1747,7 +1734,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { } if (fail) { - error(&c->error_collector, ast_node_token(y->expr), "Division by zero not allowed"); + error(ast_node_token(y->expr), "Division by zero not allowed"); x->mode = Addressing_Invalid; return; } @@ -1816,7 +1803,7 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) { gbString type_str = type_to_string(type); defer (gb_string_free(expr_str)); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(e), "Shifted operand %s must be an integer, got %s", expr_str, type_str); + error(ast_node_token(e), "Shifted operand %s must be an integer, got %s", expr_str, type_str); return; } @@ -1843,7 +1830,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { extra_text = " - Did you want `null`?"; } } - error(&c->error_collector, ast_node_token(operand->expr), "Cannot convert `%s` to `%s`%s", expr_str, type_str, extra_text); + error(ast_node_token(operand->expr), "Cannot convert `%s` to `%s`%s", expr_str, type_str, extra_text); operand->mode = Addressing_Invalid; } @@ -1944,7 +1931,7 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu if (!is_type_integer(get_enum_base_type(operand.type))) { gbString expr_str = expr_to_string(operand.expr); - error(&c->error_collector, ast_node_token(operand.expr), + error(ast_node_token(operand.expr), "Index `%s` must be an integer", expr_str); gb_string_free(expr_str); if (value) *value = 0; @@ -1955,7 +1942,7 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu i64 i = exact_value_to_integer(operand.value).value_integer; if (i < 0) { gbString expr_str = expr_to_string(operand.expr); - error(&c->error_collector, ast_node_token(operand.expr), + error(ast_node_token(operand.expr), "Index `%s` cannot be a negative value", expr_str); gb_string_free(expr_str); if (value) *value = 0; @@ -1966,7 +1953,7 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu if (value) *value = i; if (i >= max_count) { gbString expr_str = expr_to_string(operand.expr); - error(&c->error_collector, ast_node_token(operand.expr), + error(ast_node_token(operand.expr), "Index `%s` is out of bounds range [0, %lld)", expr_str, max_count); gb_string_free(expr_str); return false; @@ -2004,15 +1991,14 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { check_op_expr = false; entity = scope_lookup_entity(e->ImportName.scope, sel_name); if (entity == NULL) { - error(&c->error_collector, ast_node_token(op_expr), "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name)); + error(ast_node_token(op_expr), "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name)); goto error; } if (entity->type == NULL) { // Not setup yet check_entity_decl(c, entity, NULL, NULL); } GB_ASSERT(entity->type != NULL); - // if (!is_entity_exported(entity)) { - b32 is_not_exported = !((e->ImportName.scope == entity->scope) && (entity->kind != Entity_ImportName)); + b32 is_not_exported = !((e->ImportName.scope == entity->scope) && !is_entity_exported(entity)); if (is_not_exported) { auto found = map_get(&e->ImportName.scope->implicit, hash_string(sel_name)); @@ -2024,7 +2010,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { if (is_not_exported) { gbString sel_str = expr_to_string(selector); defer (gb_string_free(sel_str)); - error(&c->error_collector, ast_node_token(op_expr), "`%s` is not exported by `%.*s`", sel_str, LIT(name)); + error(ast_node_token(op_expr), "`%s` is not exported by `%.*s`", sel_str, LIT(name)); // NOTE(bill): Not really an error so don't goto error } @@ -2048,7 +2034,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { defer (gb_string_free(op_str)); defer (gb_string_free(type_str)); defer (gb_string_free(sel_str)); - error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); + error(ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); goto error; } @@ -2097,7 +2083,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) err = "Too many"; if (err) { ast_node(proc, Ident, ce->proc); - error(&c->error_collector, ce->close, "`%s` arguments for `%.*s`, expected %td, got %td", + error(ce->close, "`%s` arguments for `%.*s`, expected %td, got %td", err, LIT(proc->string), bp->arg_count, gb_array_count(ce->args)); return false; @@ -2124,7 +2110,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if (op.mode != Addressing_Type && type == NULL || type == t_invalid) { - error(&c->error_collector, ast_node_token(ce->args[0]), "Expected a type for `new`"); + error(ast_node_token(ce->args[0]), "Expected a type for `new`"); return false; } operand->mode = Addressing_Value; @@ -2136,7 +2122,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if (op.mode != Addressing_Type && type == NULL || type == t_invalid) { - error(&c->error_collector, ast_node_token(ce->args[0]), "Expected a type for `new_slice`"); + error(ast_node_token(ce->args[0]), "Expected a type for `new_slice`"); return false; } @@ -2152,7 +2138,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_integer(op.type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Length for `new_slice` must be an integer, got `%s`", type_str); return false; @@ -2165,13 +2151,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_integer(op.type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Capacity for `new_slice` must be an integer, got `%s`", type_str); return false; } if (ce->args[3] != NULL) { - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Too many arguments to `new_slice`, expected either 2 or 3"); return false; } @@ -2187,7 +2173,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if (!type) { - error(&c->error_collector, ast_node_token(ce->args[0]), "Expected a type for `size_of`"); + error(ast_node_token(ce->args[0]), "Expected a type for `size_of`"); return false; } @@ -2214,7 +2200,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) check_expr_or_type(c, &op, ce->args[0]); Type *type = op.type; if (!type) { - error(&c->error_collector, ast_node_token(ce->args[0]), "Expected a type for `align_of`"); + error(ast_node_token(ce->args[0]), "Expected a type for `align_of`"); return false; } operand->mode = Addressing_Constant; @@ -2240,16 +2226,16 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Type *type = get_base_type(op.type); AstNode *field_arg = unparen_expr(ce->args[1]); if (type != NULL) { - error(&c->error_collector, ast_node_token(ce->args[0]), "Expected a type for `offset_of`"); + error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`"); return false; } if (!is_type_struct(type)) { - error(&c->error_collector, ast_node_token(ce->args[0]), "Expected a structure type for `offset_of`"); + error(ast_node_token(ce->args[0]), "Expected a structure type for `offset_of`"); return false; } if (field_arg == NULL || field_arg->kind != AstNode_Ident) { - error(&c->error_collector, ast_node_token(field_arg), "Expected an identifier for field argument"); + error(ast_node_token(field_arg), "Expected an identifier for field argument"); return false; } @@ -2258,7 +2244,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Selection sel = lookup_field(type, arg->string, operand->mode == Addressing_Type); if (sel.entity == NULL) { gbString type_str = type_to_string(type); - error(&c->error_collector, ast_node_token(ce->args[0]), + error(ast_node_token(ce->args[0]), "`%s` has no field named `%.*s`", type_str, LIT(arg->string)); return false; } @@ -2274,7 +2260,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) AstNode *arg = unparen_expr(ce->args[0]); if (arg->kind != AstNode_SelectorExpr) { gbString str = expr_to_string(arg); - error(&c->error_collector, ast_node_token(arg), "`%s` is not a selector expression", str); + error(ast_node_token(arg), "`%s` is not a selector expression", str); return false; } ast_node(s, SelectorExpr, arg); @@ -2296,7 +2282,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Selection sel = lookup_field(type, i->string, operand->mode == Addressing_Type); if (sel.entity == NULL) { gbString type_str = type_to_string(type); - error(&c->error_collector, ast_node_token(arg), + error(ast_node_token(arg), "`%s` has no field named `%.*s`", type_str, LIT(i->string)); return false; } @@ -2331,14 +2317,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_boolean(operand->type) && operand->mode != Addressing_Constant) { gbString str = expr_to_string(ce->args[0]); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "`%s` is not a constant boolean", str); return false; } if (!operand->value.value_bool) { gbString str = expr_to_string(ce->args[0]); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Compile time assertion: `%s`", str); } break; @@ -2349,7 +2335,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_boolean(operand->type)) { gbString str = expr_to_string(ce->args[0]); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "`%s` is not a boolean", str); return false; } @@ -2376,7 +2362,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) src_type = s->Slice.elem; if (dest_type == NULL || src_type == NULL) { - error(&c->error_collector, ast_node_token(call), "`copy` only expects slices as arguments"); + error(ast_node_token(call), "`copy` only expects slices as arguments"); return false; } @@ -2389,7 +2375,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) defer (gb_string_free(s_arg)); defer (gb_string_free(d_str)); defer (gb_string_free(s_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Arguments to `copy`, %s, %s, have different elem types: %s vs %s", d_arg, s_arg, d_str, s_str); return false; @@ -2411,7 +2397,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) y_type = get_base_type(op.type); if (!(is_type_pointer(x_type) && is_type_slice(x_type->Pointer.elem))) { - error(&c->error_collector, ast_node_token(call), "First argument to `append` must be a pointer to a slice"); + error(ast_node_token(call), "First argument to `append` must be a pointer to a slice"); return false; } @@ -2425,7 +2411,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) defer (gb_string_free(s_arg)); defer (gb_string_free(d_str)); defer (gb_string_free(s_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Arguments to `append`, %s, %s, have different element types: %s vs %s", d_arg, s_arg, d_str, s_str); return false; @@ -2441,7 +2427,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_vector(vector_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "You can only `swizzle` a vector, got `%s`", type_str); return false; @@ -2458,17 +2444,17 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; Type *arg_type = get_base_type(op.type); if (!is_type_integer(arg_type) || op.mode != Addressing_Constant) { - error(&c->error_collector, ast_node_token(op.expr), "Indices to `swizzle` must be constant integers"); + error(ast_node_token(op.expr), "Indices to `swizzle` must be constant integers"); return false; } if (op.value.value_integer < 0) { - error(&c->error_collector, ast_node_token(op.expr), "Negative `swizzle` index"); + error(ast_node_token(op.expr), "Negative `swizzle` index"); return false; } if (max_count <= op.value.value_integer) { - error(&c->error_collector, ast_node_token(op.expr), "`swizzle` index exceeds vector length"); + error(ast_node_token(op.expr), "`swizzle` index exceeds vector length"); return false; } @@ -2476,7 +2462,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } if (arg_count > max_count) { - error(&c->error_collector, ast_node_token(call), "Too many `swizzle` indices, %td > %td", arg_count, max_count); + error(ast_node_token(call), "Too many `swizzle` indices, %td > %td", arg_count, max_count); return false; } @@ -2492,14 +2478,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a pointer to `ptr_offset`, got `%s`", type_str); return false; } if (ptr_type == t_rawptr) { - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "`rawptr` cannot have pointer arithmetic"); return false; } @@ -2511,7 +2497,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; Type *offset_type = get_base_type(op.type); if (!is_type_integer(offset_type)) { - error(&c->error_collector, ast_node_token(op.expr), "Pointer offsets for `ptr_offset` must be an integer"); + error(ast_node_token(op.expr), "Pointer offsets for `ptr_offset` must be an integer"); return false; } @@ -2534,14 +2520,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a pointer to `ptr_add`, got `%s`", type_str); return false; } if (ptr_type == t_rawptr) { - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "`rawptr` cannot have pointer arithmetic"); return false; } @@ -2553,14 +2539,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_pointer(op.type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a pointer to `ptr_add`, got `%s`", type_str); return false; } if (get_base_type(op.type) == t_rawptr) { - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "`rawptr` cannot have pointer arithmetic"); return false; } @@ -2570,7 +2556,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) gbString b = type_to_string(op.type); defer (gb_string_free(a)); defer (gb_string_free(b)); - error(&c->error_collector, ast_node_token(op.expr), + error(ast_node_token(op.expr), "`ptr_sub` requires to pointer of the same type. Got `%s` and `%s`.", a, b); return false; } @@ -2595,14 +2581,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_pointer(ptr_type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a pointer to `slice_ptr`, got `%s`", type_str); return false; } if (ptr_type == t_rawptr) { - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "`rawptr` cannot have pointer arithmetic"); return false; } @@ -2620,7 +2606,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_integer(op.type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Length for `slice_ptr` must be an integer, got `%s`", type_str); return false; @@ -2633,13 +2619,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_integer(op.type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Capacity for `slice_ptr` must be an integer, got `%s`", type_str); return false; } if (ce->args[2] != NULL) { - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Too many arguments to `slice_ptr`, expected either 2 or 3"); return false; } @@ -2655,7 +2641,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_comparable(type) || !is_type_numeric(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a comparable numeric type to `min`, got `%s`", type_str); return false; @@ -2670,7 +2656,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_comparable(b.type) || !is_type_numeric(type)) { gbString type_str = type_to_string(b.type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a comparable numeric type to `min`, got `%s`", type_str); return false; @@ -2700,7 +2686,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) gbString type_b = type_to_string(b.type); defer (gb_string_free(type_a)); defer (gb_string_free(type_b)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Mismatched types to `min`, `%s` vs `%s`", type_a, type_b); return false; @@ -2715,7 +2701,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_comparable(type) || !is_type_numeric(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a comparable numeric type to `max`, got `%s`", type_str); return false; @@ -2730,7 +2716,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_comparable(b.type) || !is_type_numeric(type)) { gbString type_str = type_to_string(b.type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a comparable numeric type to `max`, got `%s`", type_str); return false; @@ -2760,7 +2746,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) gbString type_b = type_to_string(b.type); defer (gb_string_free(type_a)); defer (gb_string_free(type_b)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Mismatched types to `max`, `%s` vs `%s`", type_a, type_b); return false; @@ -2775,7 +2761,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (!is_type_numeric(type)) { gbString type_str = type_to_string(operand->type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(call), + error(ast_node_token(call), "Expected a numeric type to `abs`, got `%s`", type_str); return false; @@ -2823,7 +2809,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode if (ce->ellipsis.pos.line != 0) { if (!variadic) { - error(&c->error_collector, ce->ellipsis, + error(ce->ellipsis, "Cannot use `..` in call to a non-variadic procedure: `%.*s`", LIT(ce->proc->Ident.string)); return; @@ -2859,7 +2845,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode if (vari_expand) { variadic_expand = true; if (param_index != param_count-1) { - error(&c->error_collector, ast_node_token(operand->expr), + error(ast_node_token(operand->expr), "`..` in a variadic procedure can only have one variadic argument at the end"); break; } @@ -2893,7 +2879,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode index = param_count-1; end_variadic = true; if (vari_expand) { - error(&c->error_collector, ast_node_token(operand->expr), + error(ast_node_token(operand->expr), "`..` in a variadic procedure cannot be applied to a %td-valued expression", tuple->variable_count); goto end; } @@ -2934,7 +2920,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode } gbString proc_str = expr_to_string(ce->proc); - error(&c->error_collector, ast_node_token(call), err_fmt, proc_str, param_count); + error(ast_node_token(call), err_fmt, proc_str, param_count); gb_string_free(proc_str); operand->mode = Addressing_Invalid; @@ -2971,7 +2957,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { AstNode *e = operand->expr; gbString str = expr_to_string(e); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(e), "Cannot call a non-procedure: `%s`", str); + error(ast_node_token(e), "Cannot call a non-procedure: `%s`", str); operand->mode = Addressing_Invalid; operand->expr = call; @@ -3017,7 +3003,7 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { if (err_str != NULL) { gbString str = expr_to_string(e); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(e), "`%s` %s", str, err_str); + error(ast_node_token(e), "`%s` %s", str, err_str); o->mode = Addressing_Invalid; } } @@ -3062,7 +3048,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->type = proc_type; } else { gbString str = expr_to_string(node); - error(&c->error_collector, ast_node_token(node), "Invalid procedure literal `%s`", str); + error(ast_node_token(node), "Invalid procedure literal `%s`", str); gb_string_free(str); goto error; } @@ -3088,7 +3074,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } if (type == NULL) { - error(&c->error_collector, ast_node_token(node), "Missing type in compound literal"); + error(ast_node_token(node), "Missing type in compound literal"); goto error; } @@ -3108,7 +3094,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint gb_for_array(i, cl->elems) { AstNode *elem = cl->elems[i]; if (elem->kind != AstNode_FieldValue) { - error(&c->error_collector, ast_node_token(elem), + error(ast_node_token(elem), "Mixture of `field = value` and value elements in a structure literal is not allowed"); continue; } @@ -3116,7 +3102,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (kv->field->kind != AstNode_Ident) { gbString expr_str = expr_to_string(kv->field); defer (gb_string_free(expr_str)); - error(&c->error_collector, ast_node_token(elem), + error(ast_node_token(elem), "Invalid field name `%s` in structure literal", expr_str); continue; } @@ -3124,13 +3110,13 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint Selection sel = lookup_field(type, name, o->mode == Addressing_Type); if (sel.entity == NULL) { - error(&c->error_collector, ast_node_token(elem), + error(ast_node_token(elem), "Unknown field `%.*s` in structure literal", LIT(name)); continue; } if (gb_array_count(sel.index) > 1) { - error(&c->error_collector, ast_node_token(elem), + error(ast_node_token(elem), "Cannot assign to an anonymous field `%.*s` in a structure literal (at the moment)", LIT(name)); continue; } @@ -3139,7 +3125,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint add_entity_use(&c->info, kv->field, field); if (fields_visited[sel.index[0]]) { - error(&c->error_collector, ast_node_token(elem), + error(ast_node_token(elem), "Duplicate field `%.*s` in structure literal", LIT(name)); continue; } @@ -3152,7 +3138,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint gb_for_array(index, cl->elems) { AstNode *elem = cl->elems[index]; if (elem->kind == AstNode_FieldValue) { - error(&c->error_collector, ast_node_token(elem), + error(ast_node_token(elem), "Mixture of `field = value` and value elements in a structure literal is not allowed"); continue; } @@ -3160,13 +3146,13 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint check_expr(c, o, elem); if (index >= field_count) { - error(&c->error_collector, ast_node_token(o->expr), "Too many values in structure literal, expected %td", field_count); + error(ast_node_token(o->expr), "Too many values in structure literal, expected %td", field_count); break; } check_assignment(c, o, field->type, make_string("structure literal")); } if (gb_array_count(cl->elems) < field_count) { - error(&c->error_collector, cl->close, "Too few values in structure literal, expected %td, got %td", field_count, gb_array_count(cl->elems)); + error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, gb_array_count(cl->elems)); } } } @@ -3196,7 +3182,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint for (; index < gb_array_count(cl->elems); index++) { AstNode *e = cl->elems[index]; if (e->kind == AstNode_FieldValue) { - error(&c->error_collector, ast_node_token(e), + error(ast_node_token(e), "`field = value` is only allowed in structure literals"); continue; } @@ -3205,12 +3191,12 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (t->kind == Type_Array && t->Array.count >= 0 && index >= t->Array.count) { - error(&c->error_collector, ast_node_token(e), "Index %lld is out of bounds (>= %lld) for array literal", index, t->Array.count); + error(ast_node_token(e), "Index %lld is out of bounds (>= %lld) for array literal", index, t->Array.count); } if (t->kind == Type_Vector && t->Vector.count >= 0 && index >= t->Vector.count) { - error(&c->error_collector, ast_node_token(e), "Index %lld is out of bounds (>= %lld) for vector literal", index, t->Vector.count); + error(ast_node_token(e), "Index %lld is out of bounds (>= %lld) for vector literal", index, t->Vector.count); } Operand o = {}; @@ -3222,7 +3208,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (t->kind == Type_Vector) { if (t->Vector.count > 1 && gb_is_between(index, 2, t->Vector.count-1)) { - error(&c->error_collector, ast_node_token(cl->elems[0]), + error(ast_node_token(cl->elems[0]), "Expected either 1 (broadcast) or %td elements in vector literal, got %td", t->Vector.count, index); } } @@ -3234,7 +3220,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint default: { gbString str = type_to_string(type); - error(&c->error_collector, ast_node_token(node), "Invalid compound literal type `%s`", str); + error(ast_node_token(node), "Invalid compound literal type `%s`", str); gb_string_free(str); goto error; } break; @@ -3252,7 +3238,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(te, TagExpr, node); // TODO(bill): Tag expressions - error(&c->error_collector, ast_node_token(node), "Tag expressions are not supported yet"); + error(ast_node_token(node), "Tag expressions are not supported yet"); kind = check_expr_base(c, o, te->expr, type_hint); o->expr = node; case_end; @@ -3338,14 +3324,14 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (!valid) { gbString str = expr_to_string(o->expr); - error(&c->error_collector, ast_node_token(o->expr), "Cannot index `%s`", str); + error(ast_node_token(o->expr), "Cannot index `%s`", str); gb_string_free(str); goto error; } if (ie->index == NULL) { gbString str = expr_to_string(o->expr); - error(&c->error_collector, ast_node_token(o->expr), "Missing index for `%s`", str); + error(ast_node_token(o->expr), "Missing index for `%s`", str); gb_string_free(str); goto error; } @@ -3373,7 +3359,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint max_count = o->value.value_string.len; } if (se->max != NULL) { - error(&c->error_collector, ast_node_token(se->max), "Max (3rd) index not needed in substring expression"); + error(ast_node_token(se->max), "Max (3rd) index not needed in substring expression"); } o->type = t_string; } @@ -3384,7 +3370,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint max_count = t->Array.count; if (o->mode != Addressing_Variable) { gbString str = expr_to_string(node); - error(&c->error_collector, ast_node_token(node), "Cannot slice array `%s`, value is not addressable", str); + error(ast_node_token(node), "Cannot slice array `%s`, value is not addressable", str); gb_string_free(str); goto error; } @@ -3407,7 +3393,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (!valid) { gbString str = expr_to_string(o->expr); - error(&c->error_collector, ast_node_token(o->expr), "Cannot slice `%s`", str); + error(ast_node_token(o->expr), "Cannot slice `%s`", str); gb_string_free(str); goto error; } @@ -3437,7 +3423,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint for (isize j = i+1; j < gb_count_of(indices); j++) { i64 b = indices[j]; if (a > b && b >= 0) { - error(&c->error_collector, se->close, "Invalid slice indices: [%td > %td]", a, b); + error(se->close, "Invalid slice indices: [%td > %td]", a, b); } } } @@ -3460,7 +3446,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->type = t->Pointer.elem; } else { gbString str = expr_to_string(o->expr); - error(&c->error_collector, ast_node_token(o->expr), "Cannot dereference `%s`", str); + error(ast_node_token(o->expr), "Cannot dereference `%s`", str); gb_string_free(str); goto error; } @@ -3528,11 +3514,11 @@ void check_multi_expr(Checker *c, Operand *o, AstNode *e) { case Addressing_NoValue: err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` used as value", err_str); + error(ast_node_token(e), "`%s` used as value", err_str); break; case Addressing_Type: err_str = expr_to_string(e); - error(&c->error_collector, ast_node_token(e), "`%s` is not an expression", err_str); + error(ast_node_token(e), "`%s` is not an expression", err_str); break; } o->mode = Addressing_Invalid; @@ -3544,7 +3530,7 @@ void check_not_tuple(Checker *c, Operand *o) { if (o->type->kind == Type_Tuple) { isize count = o->type->Tuple.variable_count; GB_ASSERT(count != 1); - error(&c->error_collector, ast_node_token(o->expr), + error(ast_node_token(o->expr), "%td-valued tuple found where single value expected", count); o->mode = Addressing_Invalid; } @@ -3564,7 +3550,7 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) { AstNode *e = o->expr; gbString str = expr_to_string(e); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(e), + error(ast_node_token(e), "`%s` used as value or type", str); o->mode = Addressing_Invalid; } @@ -3577,8 +3563,9 @@ gbString write_fields_to_string(gbString str, AstNodeArray fields, char *sep) { gb_for_array(i, fields) { AstNode *field = fields[i]; ast_node(f, Field, field); - if (i > 0) + if (i > 0) { str = gb_string_appendc(str, sep); + } str = write_expr_to_string(str, field); } @@ -3586,8 +3573,9 @@ gbString write_fields_to_string(gbString str, AstNodeArray fields, char *sep) { } gbString string_append_token(gbString str, Token token) { - if (token.string.len > 0) + if (token.string.len > 0) { return gb_string_append_length(str, token.string.text, token.string.len); + } return str; } diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index cf040c223..fa6f2ae0b 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -203,7 +203,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { gbString str = expr_to_string(op_b.expr); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(op_b.expr), "Cannot assign to `%s`", str); + error(ast_node_token(op_b.expr), "Cannot assign to `%s`", str); } break; } @@ -225,7 +225,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex defer (gb_string_free(expr_str)); // TODO(bill): is this a good enough error message? - error(&c->error_collector, ast_node_token(operand->expr), + error(ast_node_token(operand->expr), "Cannot assign builtin procedure `%s` in %.*s", expr_str, LIT(context_name)); @@ -244,7 +244,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex Type *t = operand->type; if (is_type_untyped(t)) { if (t == t_invalid) { - error(&c->error_collector, e->token, "Use of untyped thing in %.*s", LIT(context_name)); + error(e->token, "Use of untyped thing in %.*s", LIT(context_name)); e->type = t_invalid; return NULL; } @@ -285,6 +285,12 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra } isize rhs_count = gb_array_count(operands); + gb_for_array(i, operands) { + if (operands[i].mode == Addressing_Invalid) { + rhs_count--; + } + } + isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { @@ -292,7 +298,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra } if (rhs_count > 0 && lhs_count != rhs_count) { - error(&c->error_collector, lhs[0]->token, "Assignment count mismatch `%td` := `%td`", lhs_count, rhs_count); + error(lhs[0]->token, "Assignment count mismatch `%td` := `%td`", lhs_count, rhs_count); } } @@ -307,7 +313,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) { if (operand->mode != Addressing_Constant) { // TODO(bill): better error - error(&c->error_collector, ast_node_token(operand->expr), + error(ast_node_token(operand->expr), "`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string)); if (e->type == NULL) e->type = t_invalid; @@ -343,7 +349,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e if (!is_type_constant_type(t)) { gbString str = type_to_string(t); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(type_expr), + error(ast_node_token(type_expr), "Invalid constant type `%s`", str); e->type = t_invalid; return; @@ -411,13 +417,13 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); Entity *prev = scope_insert_entity(c->context.scope, uvar); if (prev != NULL) { - error(&c->error_collector, e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); + error(e->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); break; } } } } else { - error(&c->error_collector, e->token, "`using` can only be applied to variables of type struct or raw_union"); + error(e->token, "`using` can only be applied to variables of type struct or raw_union"); break; } } @@ -429,7 +435,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod check_stmt_list(c, bs->stmts, 0); if (type->Proc.result_count > 0) { if (!check_is_terminating(body)) { - error(&c->error_collector, bs->close, "Missing return statement at the end of the procedure"); + error(bs->close, "Missing return statement at the end of the procedure"); } } pop_procedure(c); @@ -501,20 +507,20 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { gbString str = type_to_string(proc_type); defer (gb_string_free(str)); - error(&c->error_collector, e->token, + error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str); } } } if (is_inline && is_no_inline) { - error(&c->error_collector, ast_node_token(pd->type), + error(ast_node_token(pd->type), "You cannot apply both `inline` and `no_inline` to a procedure"); } if (pd->body != NULL) { if (is_foreign) { - error(&c->error_collector, ast_node_token(pd->body), + error(ast_node_token(pd->body), "A procedure tagged as `#foreign` cannot have a body"); } @@ -543,7 +549,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { Type *this_type = get_base_type(e->type); Type *other_type = get_base_type(f->type); if (!are_signatures_similar_enough(this_type, other_type)) { - error(&c->error_collector, ast_node_token(d->proc_decl), + error(ast_node_token(d->proc_decl), "Redeclaration of #foreign procedure `%.*s` with different type signatures\n" "\tat %.*s(%td:%td)", LIT(name), LIT(pos.file), pos.line, pos.column); @@ -662,118 +668,115 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc -void check_var_decl_node(Checker *c, AstNode *node) { +void check_var_decl(Checker *c, AstNode *node) { ast_node(vd, VarDecl, node); isize entity_count = gb_array_count(vd->names); isize entity_index = 0; Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); - switch (vd->kind) { - case Declaration_Mutable: { - Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count); - isize new_entity_count = 0; - gb_for_array(i, vd->names) { - AstNode *name = vd->names[i]; - Entity *entity = NULL; - Token token = name->Ident; - if (name->kind == AstNode_Ident) { - String str = token.string; - Entity *found = NULL; - // NOTE(bill): Ignore assignments to `_` - b32 can_be_ignored = are_strings_equal(str, make_string("_")); - if (!can_be_ignored) { - found = current_scope_lookup_entity(c->context.scope, str); - } - if (found == NULL) { - entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); - if (!can_be_ignored) { - new_entities[new_entity_count++] = entity; - } - add_entity_definition(&c->info, name, entity); - } else { - TokenPos pos = found->token.pos; - error(&c->error_collector, token, - "Redeclaration of `%.*s` in this scope\n" - "\tat %.*s(%td:%td)", - LIT(str), LIT(pos.file), pos.line, pos.column); - entity = found; - } - } else { - error(&c->error_collector, token, "A variable declaration must be an identifier"); + gb_for_array(i, vd->names) { + AstNode *name = vd->names[i]; + Entity *entity = NULL; + Token token = name->Ident; + if (name->kind == AstNode_Ident) { + String str = token.string; + Entity *found = NULL; + // NOTE(bill): Ignore assignments to `_` + b32 can_be_ignored = are_strings_equal(str, make_string("_")); + if (!can_be_ignored) { + found = current_scope_lookup_entity(c->context.scope, str); } - if (entity == NULL) - entity = make_entity_dummy_variable(c->allocator, c->global_scope, token); - entities[entity_index++] = entity; - } - - Type *init_type = NULL; - if (vd->type) { - init_type = check_type(c, vd->type, NULL); - if (init_type == NULL) - init_type = t_invalid; - } - - for (isize i = 0; i < entity_count; i++) { - Entity *e = entities[i]; - GB_ASSERT(e != NULL); - if (e->Variable.visited) { - e->type = t_invalid; - continue; - } - e->Variable.visited = true; - - if (e->type == NULL) - e->type = init_type; - } - - check_init_variables(c, entities, entity_count, vd->values, make_string("variable declaration")); - - gb_for_array(i, vd->names) { - add_entity(c, c->context.scope, vd->names[i], new_entities[i]); - } - - } break; - - case Declaration_Immutable: { - gb_for_array(i, vd->values) { - AstNode *name = vd->names[i]; - AstNode *value = vd->values[i]; - - GB_ASSERT(name->kind == AstNode_Ident); - ExactValue v = {ExactValue_Invalid}; - String str = name->Ident.string; - Entity *found = current_scope_lookup_entity(c->context.scope, str); if (found == NULL) { - Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v); - entities[entity_index++] = e; - check_const_decl(c, e, vd->type, value); + entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); + add_entity_definition(&c->info, name, entity); } else { - entities[entity_index++] = found; + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of `%.*s` in this scope\n" + "\tat %.*s(%td:%td)", + LIT(str), LIT(pos.file), pos.line, pos.column); + entity = found; } + } else { + error(token, "A variable declaration must be an identifier"); } + if (entity == NULL) + entity = make_entity_dummy_variable(c->allocator, c->global_scope, token); + entities[entity_index++] = entity; + } - isize lhs_count = gb_array_count(vd->names); - isize rhs_count = gb_array_count(vd->values); + Type *init_type = NULL; + if (vd->type) { + init_type = check_type(c, vd->type, NULL); + if (init_type == NULL) + init_type = t_invalid; + } - // TODO(bill): Better error messages or is this good enough? - if (rhs_count == 0 && vd->type == NULL) { - error(&c->error_collector, ast_node_token(node), "Missing type or initial expression"); - } else if (lhs_count < rhs_count) { - error(&c->error_collector, ast_node_token(node), "Extra initial expression"); + for (isize i = 0; i < entity_count; i++) { + Entity *e = entities[i]; + GB_ASSERT(e != NULL); + if (e->Variable.visited) { + e->type = t_invalid; + continue; } + e->Variable.visited = true; - gb_for_array(i, vd->names) { + if (e->type == NULL) + e->type = init_type; + } + + check_init_variables(c, entities, entity_count, vd->values, make_string("variable declaration")); + + gb_for_array(i, vd->names) { + if (entities[i] != NULL) { add_entity(c, c->context.scope, vd->names[i], entities[i]); } - } break; + } - default: - error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST."); - return; +} + + +void check_const_decl(Checker *c, AstNode *node) { + ast_node(vd, ConstDecl, node); + isize entity_count = gb_array_count(vd->names); + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + + gb_for_array(i, vd->values) { + AstNode *name = vd->names[i]; + AstNode *value = vd->values[i]; + + GB_ASSERT(name->kind == AstNode_Ident); + ExactValue v = {ExactValue_Invalid}; + String str = name->Ident.string; + Entity *found = current_scope_lookup_entity(c->context.scope, str); + if (found == NULL) { + Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v); + entities[entity_index++] = e; + check_const_decl(c, e, vd->type, value); + } else { + entities[entity_index++] = found; + } + } + + isize lhs_count = gb_array_count(vd->names); + isize rhs_count = gb_array_count(vd->values); + + // TODO(bill): Better error messages or is this good enough? + if (rhs_count == 0 && vd->type == NULL) { + error(ast_node_token(node), "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error(ast_node_token(node), "Extra initial expression"); + } + + gb_for_array(i, vd->names) { + add_entity(c, c->context.scope, vd->names[i], entities[i]); } } + + void check_stmt(Checker *c, AstNode *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -786,7 +789,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { ExprKind kind = check_expr_base(c, &operand, es->expr); switch (operand.mode) { case Addressing_Type: - error(&c->error_collector, ast_node_token(node), "Is not an expression"); + error(ast_node_token(node), "Is not an expression"); break; case Addressing_NoValue: return; @@ -800,14 +803,14 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { return; } - error(&c->error_collector, ast_node_token(node), "Expression is not used: `%s`", expr_str); + error(ast_node_token(node), "Expression is not used: `%s`", expr_str); } break; } case_end; case_ast_node(ts, TagStmt, node); // TODO(bill): Tag Statements - error(&c->error_collector, ast_node_token(node), "Tag statements are not supported yet"); + error(ast_node_token(node), "Tag statements are not supported yet"); check_stmt(c, ts->stmt, flags); case_end; @@ -823,7 +826,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { op.string.len = 1; break; default: - error(&c->error_collector, ids->op, "Unknown inc/dec operation %.*s", LIT(ids->op.string)); + error(ids->op, "Unknown inc/dec operation %.*s", LIT(ids->op.string)); return; } @@ -832,7 +835,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { if (operand.mode == Addressing_Invalid) return; if (!is_type_numeric(operand.type)) { - error(&c->error_collector, ids->op, "Non numeric type"); + error(ids->op, "Non numeric type"); return; } @@ -855,7 +858,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case Token_Eq: { // a, b, c = 1, 2, 3; // Multisided if (gb_array_count(as->lhs) == 0) { - error(&c->error_collector, as->op, "Missing lhs in assignment statement"); + error(as->op, "Missing lhs in assignment statement"); return; } @@ -888,7 +891,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { check_assignment_variable(c, &operands[i], lhs); } if (lhs_count != rhs_count) { - error(&c->error_collector, ast_node_token(as->lhs[0]), "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); + error(ast_node_token(as->lhs[0]), "Assignment count mismatch `%td` = `%td`", lhs_count, rhs_count); } } break; @@ -896,11 +899,11 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { // a += 1; // Single-sided Token op = as->op; if (gb_array_count(as->lhs) != 1 || gb_array_count(as->rhs) != 1) { - error(&c->error_collector, op, "Assignment operation `%.*s` requires single-valued expressions", LIT(op.string)); + error(op, "Assignment operation `%.*s` requires single-valued expressions", LIT(op.string)); return; } if (!gb_is_between(op.kind, Token__AssignOpBegin+1, Token__AssignOpEnd-1)) { - error(&c->error_collector, op, "Unknown Assignment operation `%.*s`", LIT(op.string)); + error(op, "Unknown Assignment operation `%.*s`", LIT(op.string)); return; } // TODO(bill): Check if valid assignment operator @@ -938,7 +941,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { check_expr(c, &operand, is->cond); if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) { - error(&c->error_collector, ast_node_token(is->cond), + error(ast_node_token(is->cond), "Non-boolean condition in `if` statement"); } @@ -951,7 +954,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { check_stmt(c, is->else_stmt, mod_flags); break; default: - error(&c->error_collector, ast_node_token(is->else_stmt), + error(ast_node_token(is->else_stmt), "Invalid `else` statement in `if` statement"); break; } @@ -962,23 +965,28 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { GB_ASSERT(gb_array_count(c->proc_stack) > 0); if (c->in_defer) { - error(&c->error_collector, rs->token, "You cannot `return` within a defer statement"); + error(rs->token, "You cannot `return` within a defer statement"); // TODO(bill): Should I break here? break; } Type *proc_type = c->proc_stack[gb_array_count(c->proc_stack)-1]; isize result_count = 0; - if (proc_type->Proc.results) + if (proc_type->Proc.results) { result_count = proc_type->Proc.results->Tuple.variable_count; + } if (result_count != gb_array_count(rs->results)) { - error(&c->error_collector, rs->token, "Expected %td return %s, got %td", + error(rs->token, "Expected %td return %s, got %td", result_count, (result_count != 1 ? "values" : "value"), gb_array_count(rs->results)); } else if (result_count > 0) { - auto *tuple = &proc_type->Proc.results->Tuple; - check_init_variables(c, tuple->variables, tuple->variable_count, + Entity **variables = NULL; + if (proc_type->Proc.results != NULL) { + auto *tuple = &proc_type->Proc.results->Tuple; + variables = tuple->variables; + } + check_init_variables(c, variables, result_count, rs->results, make_string("return statement")); } case_end; @@ -995,7 +1003,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { check_expr(c, &operand, fs->cond); if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) { - error(&c->error_collector, ast_node_token(fs->cond), + error(ast_node_token(fs->cond), "Non-boolean condition in `for` statement"); } } @@ -1040,13 +1048,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { default_stmt = stmt; } } else { - error(&c->error_collector, ast_node_token(stmt), "Invalid AST - expected case clause"); + error(ast_node_token(stmt), "Invalid AST - expected case clause"); } if (default_stmt != NULL) { if (first_default != NULL) { TokenPos pos = ast_node_token(first_default).pos; - error(&c->error_collector, ast_node_token(stmt), + error(ast_node_token(stmt), "multiple `default` clauses\n" "\tfirst at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column); } else { @@ -1114,8 +1122,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { if (are_types_identical(y.type, tap.type)) { TokenPos pos = tap.token.pos; gbString expr_str = expr_to_string(y.expr); - error(&c->error_collector, - ast_node_token(y.expr), + error(ast_node_token(y.expr), "Duplicate case `%s`\n" "\tprevious case at %.*s(%td:%td)", expr_str, @@ -1158,7 +1165,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { if (!is_type_pointer(x.type) || !is_type_union(type_deref(x.type))) { gbString str = type_to_string(x.type); defer (gb_string_free(str)); - error(&c->error_collector, ast_node_token(x.expr), + error(ast_node_token(x.expr), "Expected a pointer to a union for this type match expression, got `%s`", str); break; } @@ -1177,13 +1184,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { default_stmt = stmt; } } else { - error(&c->error_collector, ast_node_token(stmt), "Invalid AST - expected case clause"); + error(ast_node_token(stmt), "Invalid AST - expected case clause"); } if (default_stmt != NULL) { if (first_default != NULL) { TokenPos pos = ast_node_token(first_default).pos; - error(&c->error_collector, ast_node_token(stmt), + error(ast_node_token(stmt), "multiple `default` clauses\n" "\tfirst at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column); } else { @@ -1226,7 +1233,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { if (!tag_type_found) { gbString type_str = type_to_string(y.type); defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(y.expr), + error(ast_node_token(y.expr), "Unknown tag type, got `%s`", type_str); continue; } @@ -1237,8 +1244,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { if (found) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); - error(&c->error_collector, - ast_node_token(y.expr), + error(ast_node_token(y.expr), "Duplicate type case `%s`\n" "\tprevious type case at %.*s(%td:%td)", expr_str, @@ -1266,7 +1272,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(ds, DeferStmt, node); if (is_ast_node_decl(ds->stmt)) { - error(&c->error_collector, ds->token, "You cannot defer a declaration"); + error(ds->token, "You cannot defer a declaration"); } else { b32 out_in_defer = c->in_defer; c->in_defer = true; @@ -1280,18 +1286,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { switch (token.kind) { case Token_break: if ((flags & Stmt_BreakAllowed) == 0) - error(&c->error_collector, token, "`break` only allowed in `for` or `match` statements"); + error(token, "`break` only allowed in `for` or `match` statements"); break; case Token_continue: if ((flags & Stmt_ContinueAllowed) == 0) - error(&c->error_collector, token, "`continue` only allowed in `for` statements"); + error(token, "`continue` only allowed in `for` statements"); break; case Token_fallthrough: if ((flags & Stmt_FallthroughAllowed) == 0) - error(&c->error_collector, token, "`fallthrough` statement in illegal position"); + error(token, "`fallthrough` statement in illegal position"); break; default: - error(&c->error_collector, token, "Invalid AST: Branch Statement `%.*s`", LIT(token.string)); + error(token, "Invalid AST: Branch Statement `%.*s`", LIT(token.string)); break; } case_end; @@ -1315,7 +1321,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { } if (e == NULL) { - error(&c->error_collector, us->token, "`using` applied to an unknown entity"); + error(us->token, "`using` applied to an unknown entity"); return; } @@ -1330,7 +1336,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *f = t->Record.other_fields[i]; Entity *found = scope_insert_entity(c->context.scope, f); if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); return; } f->using_parent = e; @@ -1340,7 +1346,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *f = t->Record.fields[i]; Entity *found = scope_insert_entity(c->context.scope, f); if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); return; } f->using_parent = e; @@ -1349,7 +1355,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *f = t->Record.other_fields[i]; Entity *found = scope_insert_entity(c->context.scope, f); if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); return; } f->using_parent = e; @@ -1363,7 +1369,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *decl = scope->elements.entries[i].value; Entity *found = scope_insert_entity(c->context.scope, decl); if (found != NULL) { - error(&c->error_collector, us->token, + error(us->token, "Namespace collision while `using` `%s` of: %.*s\n" "\tat %.*s(%td:%td)\n" "\tat %.*s(%td:%td)", @@ -1377,12 +1383,12 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { } break; case Entity_Constant: - error(&c->error_collector, us->token, "`using` cannot be applied to a constant"); + error(us->token, "`using` cannot be applied to a constant"); break; case Entity_Procedure: case Entity_Builtin: - error(&c->error_collector, us->token, "`using` cannot be applied to a procedure"); + error(us->token, "`using` cannot be applied to a procedure"); break; case Entity_Variable: { @@ -1399,13 +1405,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { } Entity *prev = scope_insert_entity(c->context.scope, uvar); if (prev != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); + error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); return; } } } } else { - error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or raw_union"); + error(us->token, "`using` can only be applied to variables of type struct or raw_union"); return; } } break; @@ -1417,9 +1423,9 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(vd, VarDecl, us->node); if (gb_array_count(vd->names) > 1 && vd->type != NULL) { - error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type"); + error(us->token, "`using` can only be applied to one variable of the same type"); } - check_var_decl_node(c, us->node); + check_var_decl(c, us->node); gb_for_array(name_index, vd->names) { AstNode *item = vd->names[name_index]; @@ -1436,13 +1442,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); Entity *prev = scope_insert_entity(c->context.scope, uvar); if (prev != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); + error(us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); return; } } } } else { - error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or raw_union"); + error(us->token, "`using` can only be applied to variables of type struct or raw_union"); return; } } @@ -1450,7 +1456,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { default: - error(&c->error_collector, us->token, "Invalid AST: Using Statement"); + error(us->token, "Invalid AST: Using Statement"); break; } case_end; @@ -1461,7 +1467,11 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(vd, VarDecl, node); - check_var_decl_node(c, node); + check_var_decl(c, node); + case_end; + + case_ast_node(cd, ConstDecl, node); + check_const_decl(c, node); case_end; case_ast_node(pd, ProcDecl, node); diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 04f1f88ea..a33b9e633 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -7,17 +7,9 @@ struct ssaGen { }; b32 ssa_gen_init(ssaGen *s, Checker *c) { - if (c->error_collector.count != 0) + if (global_error_collector.count != 0) return false; - gb_for_array(i, c->parser->files) { - AstFile *f = &c->parser->files[i]; - if (f->error_collector.count != 0) - return false; - if (f->tokenizer.error_count != 0) - return false; - } - isize tc = c->parser->total_token_count; if (tc < 2) { return false; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index fac8423b0..a2ff2a50a 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -3053,82 +3053,80 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_end; case_ast_node(vd, VarDecl, node); - if (vd->kind == Declaration_Mutable) { - if (gb_array_count(vd->names) == gb_array_count(vd->values)) { // 1:1 assigment - gbArray(ssaAddr) lvals; - gbArray(ssaValue *) inits; - gb_array_init_reserve(lvals, gb_heap_allocator(), gb_array_count(vd->names)); - gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(vd->names)); - defer (gb_array_free(lvals)); - defer (gb_array_free(inits)); + if (gb_array_count(vd->names) == gb_array_count(vd->values)) { // 1:1 assigment + gbArray(ssaAddr) lvals; + gbArray(ssaValue *) inits; + gb_array_init_reserve(lvals, gb_heap_allocator(), gb_array_count(vd->names)); + gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(vd->names)); + defer (gb_array_free(lvals)); + defer (gb_array_free(inits)); - gb_for_array(i, vd->names) { - AstNode *name = vd->names[i]; - ssaAddr lval = ssa_make_addr(NULL, NULL); - if (!ssa_is_blank_ident(name)) { - ssa_add_local_for_identifier(proc, name, false); - lval = ssa_build_addr(proc, name); - GB_ASSERT(lval.addr != NULL); - } - - gb_array_append(lvals, lval); + gb_for_array(i, vd->names) { + AstNode *name = vd->names[i]; + ssaAddr lval = ssa_make_addr(NULL, NULL); + if (!ssa_is_blank_ident(name)) { + ssa_add_local_for_identifier(proc, name, false); + lval = ssa_build_addr(proc, name); + GB_ASSERT(lval.addr != NULL); } - gb_for_array(i, vd->values) { - ssaValue *init = ssa_build_expr(proc, vd->values[i]); + + gb_array_append(lvals, lval); + } + gb_for_array(i, vd->values) { + ssaValue *init = ssa_build_expr(proc, vd->values[i]); + gb_array_append(inits, init); + } + + + gb_for_array(i, inits) { + ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_addr_type(lvals[i])); + ssa_lvalue_store(proc, lvals[i], v); + } + + } else if (gb_array_count(vd->values) == 0) { // declared and zero-initialized + gb_for_array(i, vd->names) { + AstNode *name = vd->names[i]; + if (!ssa_is_blank_ident(name)) { + ssa_add_local_for_identifier(proc, name, true); + } + } + } else { // Tuple(s) + gbArray(ssaAddr) lvals; + gbArray(ssaValue *) inits; + gb_array_init_reserve(lvals, gb_heap_allocator(), gb_array_count(vd->names)); + gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(vd->names)); + defer (gb_array_free(lvals)); + defer (gb_array_free(inits)); + + gb_for_array(i, vd->names) { + AstNode *name = vd->names[i]; + ssaAddr lval = ssa_make_addr(NULL, NULL); + if (!ssa_is_blank_ident(name)) { + ssa_add_local_for_identifier(proc, name, false); + lval = ssa_build_addr(proc, name); + } + + gb_array_append(lvals, lval); + } + + gb_for_array(i, vd->values) { + ssaValue *init = ssa_build_expr(proc, vd->values[i]); + Type *t = ssa_type(init); + if (t->kind == Type_Tuple) { + for (isize i = 0; i < t->Tuple.variable_count; i++) { + Entity *e = t->Tuple.variables[i]; + ssaValue *v = ssa_emit_struct_ev(proc, init, i, e->type); + gb_array_append(inits, v); + } + } else { gb_array_append(inits, init); } + } - gb_for_array(i, inits) { - ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_addr_type(lvals[i])); - ssa_lvalue_store(proc, lvals[i], v); - } - - } else if (gb_array_count(vd->values) == 0) { // declared and zero-initialized - gb_for_array(i, vd->names) { - AstNode *name = vd->names[i]; - if (!ssa_is_blank_ident(name)) { - ssa_add_local_for_identifier(proc, name, true); - } - } - } else { // Tuple(s) - gbArray(ssaAddr) lvals; - gbArray(ssaValue *) inits; - gb_array_init_reserve(lvals, gb_heap_allocator(), gb_array_count(vd->names)); - gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(vd->names)); - defer (gb_array_free(lvals)); - defer (gb_array_free(inits)); - - gb_for_array(i, vd->names) { - AstNode *name = vd->names[i]; - ssaAddr lval = ssa_make_addr(NULL, NULL); - if (!ssa_is_blank_ident(name)) { - ssa_add_local_for_identifier(proc, name, false); - lval = ssa_build_addr(proc, name); - } - - gb_array_append(lvals, lval); - } - - gb_for_array(i, vd->values) { - ssaValue *init = ssa_build_expr(proc, vd->values[i]); - Type *t = ssa_type(init); - if (t->kind == Type_Tuple) { - for (isize i = 0; i < t->Tuple.variable_count; i++) { - Entity *e = t->Tuple.variables[i]; - ssaValue *v = ssa_emit_struct_ev(proc, init, i, e->type); - gb_array_append(inits, v); - } - } else { - gb_array_append(inits, init); - } - } - - - gb_for_array(i, inits) { - ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_addr_type(lvals[i])); - ssa_lvalue_store(proc, lvals[i], v); - } + gb_for_array(i, inits) { + ssaValue *v = ssa_emit_conv(proc, inits[i], ssa_addr_type(lvals[i])); + ssa_lvalue_store(proc, lvals[i], v); } } case_end; diff --git a/src/parser.cpp b/src/parser.cpp index 128d944e1..ec6aea9dc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -34,8 +34,6 @@ struct AstFile { isize scope_level; Scope * scope; // NOTE(bill): Created in checker - ErrorCollector error_collector; - // TODO(bill): Error recovery // NOTE(bill): Error recovery #define PARSER_MAX_FIX_COUNT 6 @@ -59,13 +57,6 @@ struct Parser { isize total_token_count; }; -enum DeclKind { - Declaration_Invalid, - Declaration_Mutable, - Declaration_Immutable, - Declaration_Count, -}; - enum ProcTag : u64 { ProcTag_bounds_check = GB_BIT(0), ProcTag_no_bounds_check = GB_BIT(1), @@ -227,20 +218,25 @@ AST_NODE_KIND(_StmtEnd, "", struct{}) \ AST_NODE_KIND(_DeclBegin, "", struct{}) \ AST_NODE_KIND(BadDecl, "bad declaration", struct { Token begin, end; }) \ AST_NODE_KIND(VarDecl, "variable declaration", struct { \ - DeclKind kind; \ u64 tags; \ b32 is_using; \ AstNodeArray names; \ AstNode *type; \ AstNodeArray values; \ - }) \ + }) \ + AST_NODE_KIND(ConstDecl, "constant declaration", struct { \ + u64 tags; \ + AstNodeArray names; \ + AstNode *type; \ + AstNodeArray values; \ + }) \ AST_NODE_KIND(ProcDecl, "procedure declaration", struct { \ AstNode *name; \ AstNode *type; \ AstNode *body; \ u64 tags; \ String foreign_name; \ - }) \ + }) \ AST_NODE_KIND(TypeDecl, "type declaration", struct { Token token; AstNode *name, *type; }) \ AST_NODE_KIND(ImportDecl, "import declaration", struct { \ Token token, relpath; \ @@ -419,6 +415,8 @@ Token ast_node_token(AstNode *node) { return node->BadDecl.begin; case AstNode_VarDecl: return ast_node_token(node->VarDecl.names[0]); + case AstNode_ConstDecl: + return ast_node_token(node->ConstDecl.names[0]); case AstNode_ProcDecl: return node->ProcDecl.name->Ident; case AstNode_TypeDecl: @@ -458,26 +456,6 @@ HashKey hash_token(Token t) { return hash_string(t.string); } -#define ast_file_err(f, token, fmt, ...) ast_file_err_(f, __FUNCTION__, token, fmt, ##__VA_ARGS__) -void ast_file_err_(AstFile *file, char *function, Token token, char *fmt, ...) { - // NOTE(bill): Duplicate error, skip it - if (!token_pos_are_equal(file->error_collector.prev, token.pos)) { - va_list va; - - file->error_collector.prev = token.pos; - - #if 0 - gb_printf_err("%s()\n", function); - #endif - va_start(va, fmt); - gb_printf_err("%.*s(%td:%td) Syntax error: %s\n", - LIT(token.pos.file), token.pos.line, token.pos.column, - gb_bprintf_va(fmt, va)); - va_end(va); - } - file->error_collector.count++; -} - // NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ gb_inline AstNode *make_node(AstFile *f, AstNodeKind kind) { @@ -525,11 +503,11 @@ gb_inline AstNode *make_binary_expr(AstFile *f, Token op, AstNode *left, AstNode AstNode *result = make_node(f, AstNode_BinaryExpr); if (left == NULL) { - ast_file_err(f, op, "No lhs expression for binary expression `%.*s`", LIT(op.string)); + syntax_error(op, "No lhs expression for binary expression `%.*s`", LIT(op.string)); left = make_bad_expr(f, op, op); } if (right == NULL) { - ast_file_err(f, op, "No rhs expression for binary expression `%.*s`", LIT(op.string)); + syntax_error(op, "No rhs expression for binary expression `%.*s`", LIT(op.string)); right = make_bad_expr(f, op, op); } @@ -795,15 +773,22 @@ gb_inline AstNode *make_bad_decl(AstFile *f, Token begin, Token end) { return result; } -gb_inline AstNode *make_var_decl(AstFile *f, DeclKind kind, AstNodeArray names, AstNode *type, AstNodeArray values) { +gb_inline AstNode *make_var_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) { AstNode *result = make_node(f, AstNode_VarDecl); - result->VarDecl.kind = kind; result->VarDecl.names = names; result->VarDecl.type = type; result->VarDecl.values = values; return result; } +gb_inline AstNode *make_const_decl(AstFile *f, AstNodeArray names, AstNode *type, AstNodeArray values) { + AstNode *result = make_node(f, AstNode_ConstDecl); + result->ConstDecl.names = names; + result->ConstDecl.type = type; + result->ConstDecl.values = values; + return result; +} + gb_inline AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, b32 is_using) { AstNode *result = make_node(f, AstNode_Field); result->Field.names = names; @@ -918,7 +903,7 @@ gb_inline b32 next_token(AstFile *f) { f->cursor++; return true; } else { - ast_file_err(f, f->cursor[0], "Token is EOF"); + syntax_error(f->cursor[0], "Token is EOF"); return false; } } @@ -926,7 +911,7 @@ gb_inline b32 next_token(AstFile *f) { gb_inline Token expect_token(AstFile *f, TokenKind kind) { Token prev = f->cursor[0]; if (prev.kind != kind) { - ast_file_err(f, f->cursor[0], "Expected `%.*s`, got `%.*s`", + syntax_error(f->cursor[0], "Expected `%.*s`, got `%.*s`", LIT(token_strings[kind]), LIT(token_strings[prev.kind])); } @@ -937,7 +922,7 @@ gb_inline Token expect_token(AstFile *f, TokenKind kind) { gb_inline Token expect_operator(AstFile *f) { Token prev = f->cursor[0]; if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) { - ast_file_err(f, f->cursor[0], "Expected an operator, got `%.*s`", + syntax_error(f->cursor[0], "Expected an operator, got `%.*s`", LIT(token_strings[prev.kind])); } next_token(f); @@ -947,7 +932,7 @@ gb_inline Token expect_operator(AstFile *f) { gb_inline Token expect_keyword(AstFile *f) { Token prev = f->cursor[0]; if (!gb_is_between(prev.kind, Token__KeywordBegin+1, Token__KeywordEnd-1)) { - ast_file_err(f, f->cursor[0], "Expected a keyword, got `%.*s`", + syntax_error(f->cursor[0], "Expected a keyword, got `%.*s`", LIT(token_strings[prev.kind])); } next_token(f); @@ -1027,7 +1012,7 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) { if (f->cursor[0].pos.line == f->cursor[-1].pos.line) { if (f->cursor[0].kind != Token_CloseBrace) { // CLEANUP(bill): Semicolon handling in parser - ast_file_err(f, f->cursor[0], + syntax_error(f->cursor[0], "Expected `;` after %.*s, got `%.*s`", LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind])); return false; @@ -1126,7 +1111,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags = 0); void check_proc_add_tag(AstFile *f, AstNode *tag_expr, u64 *tags, ProcTag tag, String tag_name) { if (*tags & tag) { - ast_file_err(f, ast_node_token(tag_expr), "Procedure tag already used: %.*s", LIT(tag_name)); + syntax_error(ast_node_token(tag_expr), "Procedure tag already used: %.*s", LIT(tag_name)); } *tags |= tag; } @@ -1200,7 +1185,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { *foreign_name = f->cursor[0].string; // TODO(bill): Check if valid string if (!is_foreign_name_valid(*foreign_name)) { - ast_file_err(f, ast_node_token(tag_expr), "Invalid alternative foreign procedure name"); + syntax_error(ast_node_token(tag_expr), "Invalid alternative foreign procedure name"); } next_token(f); @@ -1216,22 +1201,22 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { ELSE_IF_ADD_TAG(fastcall) // ELSE_IF_ADD_TAG(cdecl) else { - ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag"); + syntax_error(ast_node_token(tag_expr), "Unknown procedure tag"); } #undef ELSE_IF_ADD_TAG } if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) { - ast_file_err(f, f->cursor[0], "You cannot apply both #inline and #no_inline to a procedure"); + syntax_error(f->cursor[0], "You cannot apply both #inline and #no_inline to a procedure"); } if ((*tags & ProcTag_bounds_check) && (*tags & ProcTag_no_bounds_check)) { - ast_file_err(f, f->cursor[0], "You cannot apply both #bounds_check and #no_bounds_check to a procedure"); + syntax_error(f->cursor[0], "You cannot apply both #bounds_check and #no_bounds_check to a procedure"); } if (((*tags & ProcTag_bounds_check) || (*tags & ProcTag_no_bounds_check)) && (*tags & ProcTag_foreign)) { - ast_file_err(f, f->cursor[0], "You cannot apply both #bounds_check or #no_bounds_check to a procedure without a body"); + syntax_error(f->cursor[0], "You cannot apply both #bounds_check or #no_bounds_check to a procedure without a body"); } } @@ -1272,7 +1257,7 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { Token *s = &f->cursor[0]; if (gb_utf8_strnlen(s->string.text, s->string.len) != 1) { - ast_file_err(f, *s, "Invalid rune literal %.*s", LIT(s->string)); + syntax_error(*s, "Invalid rune literal %.*s", LIT(s->string)); } s->kind = Token_Rune; // NOTE(bill): Change it } else { @@ -1308,7 +1293,7 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { String foreign_name = {}; parse_proc_tags(f, &tags, &foreign_name); if (tags & ProcTag_foreign) { - ast_file_err(f, f->cursor[0], "#foreign cannot be applied to procedure literals"); + syntax_error(f->cursor[0], "#foreign cannot be applied to procedure literals"); } if (f->cursor[0].kind != Token_OpenBrace) { @@ -1335,7 +1320,7 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { } Token begin = f->cursor[0]; - ast_file_err(f, begin, "Expected an operand"); + syntax_error(begin, "Expected an operand"); fix_advance_to_next_stmt(f); return make_bad_expr(f, begin, f->cursor[0]); } @@ -1365,7 +1350,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { f->cursor[0].kind != Token_EOF && ellipsis.pos.line == 0) { if (f->cursor[0].kind == Token_Comma) - ast_file_err(f, f->cursor[0], "Expected an expression not a ,"); + syntax_error(f->cursor[0], "Expected an expression not a ,"); if (f->cursor[0].kind == Token_Ellipsis) { ellipsis = f->cursor[0]; @@ -1425,7 +1410,7 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { operand = make_selector_expr(f, token, operand, parse_identifier(f)); break; default: { - ast_file_err(f, f->cursor[0], "Expected a selector"); + syntax_error(f->cursor[0], "Expected a selector"); next_token(f); operand = make_selector_expr(f, f->cursor[0], operand, NULL); } break; @@ -1467,11 +1452,11 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) { if (colon_count == 2) { triple_indexed = true; if (indices[1] == NULL) { - ast_file_err(f, colons[0], "Second index is required in a triple indexed slice"); + syntax_error(colons[0], "Second index is required in a triple indexed slice"); indices[1] = make_bad_expr(f, colons[0], colons[1]); } if (indices[2] == NULL) { - ast_file_err(f, colons[1], "Third index is required in a triple indexed slice"); + syntax_error(colons[1], "Third index is required in a triple indexed slice"); indices[2] = make_bad_expr(f, colons[1], close); } } @@ -1558,7 +1543,7 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) { default: right = parse_binary_expr(f, false, prec+1); if (!right) { - ast_file_err(f, op, "Expected expression on the right hand side of the binary operator"); + syntax_error(op, "Expected expression on the right hand side of the binary operator"); } break; } @@ -1622,13 +1607,13 @@ AstNode *parse_simple_stmt(AstFile *f) { case Token_CmpOrEq: { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a simple statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a simple statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } next_token(f); AstNodeArray rhs = parse_rhs_expr_list(f); if (gb_array_count(rhs) == 0) { - ast_file_err(f, token, "No right-hand side in assignment statement."); + syntax_error(token, "No right-hand side in assignment statement."); return make_bad_stmt(f, token, f->cursor[0]); } return make_assign_stmt(f, token, lhs, rhs); @@ -1639,7 +1624,7 @@ AstNode *parse_simple_stmt(AstFile *f) { } if (lhs_count > 1) { - ast_file_err(f, token, "Expected 1 expression"); + syntax_error(token, "Expected 1 expression"); return make_bad_stmt(f, token, f->cursor[0]); } @@ -1648,7 +1633,7 @@ AstNode *parse_simple_stmt(AstFile *f) { case Token_Increment: case Token_Decrement: if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a simple statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a simple statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } statement = make_inc_dec_stmt(f, token, lhs[0]); @@ -1663,7 +1648,7 @@ AstNode *parse_simple_stmt(AstFile *f) { AstNode *parse_block_stmt(AstFile *f) { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a block statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a block statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } AstNode *block_stmt = parse_body(f); @@ -1677,7 +1662,7 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { if (statement->kind == AstNode_ExprStmt) return statement->ExprStmt.expr; - ast_file_err(f, f->cursor[0], "Expected `%.*s`, found a simple statement.", LIT(kind)); + syntax_error(f->cursor[0], "Expected `%.*s`, found a simple statement.", LIT(kind)); return make_bad_expr(f, f->cursor[0], f->cursor[1]); } @@ -1710,7 +1695,7 @@ AstNode *parse_type(AstFile *f) { AstNode *type = parse_type_attempt(f); if (type == NULL) { Token token = f->cursor[0]; - ast_file_err(f, token, "Expected a type"); + syntax_error(token, "Expected a type"); next_token(f); return make_bad_expr(f, token, f->cursor[0]); } @@ -1738,11 +1723,11 @@ AstNode *parse_field_decl(AstFile *f) { AstNodeArray names = parse_lhs_expr_list(f); if (gb_array_count(names) == 0) { - ast_file_err(f, f->cursor[0], "Empty field declaration"); + syntax_error(f->cursor[0], "Empty field declaration"); } if (gb_array_count(names) > 1 && is_using) { - ast_file_err(f, f->cursor[0], "Cannot apply `using` to more than one of the same type"); + syntax_error(f->cursor[0], "Cannot apply `using` to more than one of the same type"); is_using = false; } @@ -1755,11 +1740,11 @@ AstNode *parse_field_decl(AstFile *f) { next_token(f); type = parse_type_attempt(f); if (type == NULL) { - ast_file_err(f, f->cursor[0], "variadic parameter is missing a type after `..`"); + syntax_error(f->cursor[0], "variadic parameter is missing a type after `..`"); type = make_bad_expr(f, ellipsis, f->cursor[0]); } else { if (gb_array_count(names) > 1) { - ast_file_err(f, f->cursor[0], "mutliple variadic parameters, only `..`"); + syntax_error(f->cursor[0], "mutliple variadic parameters, only `..`"); } else { type = make_ellipsis(f, ellipsis, type); } @@ -1769,7 +1754,7 @@ AstNode *parse_field_decl(AstFile *f) { } if (type == NULL) { - ast_file_err(f, f->cursor[0], "Expected a type for this field declaration"); + syntax_error(f->cursor[0], "Expected a type for this field declaration"); } AstNode *field = make_field(f, names, type, is_using); @@ -1804,15 +1789,15 @@ AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, b32 using_allow } AstNodeArray names = parse_lhs_expr_list(f); if (gb_array_count(names) == 0) { - ast_file_err(f, f->cursor[0], "Empty field declaration"); + syntax_error(f->cursor[0], "Empty field declaration"); } if (!using_allowed && is_using) { - ast_file_err(f, f->cursor[0], "Cannot apply `using` to members of a union"); + syntax_error(f->cursor[0], "Cannot apply `using` to members of a union"); is_using = false; } if (gb_array_count(names) > 1 && is_using) { - ast_file_err(f, f->cursor[0], "Cannot apply `using` to more than one of the same type"); + syntax_error(f->cursor[0], "Cannot apply `using` to more than one of the same type"); } AstNode *decl = NULL; @@ -1821,11 +1806,11 @@ AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, b32 using_allow decl = parse_decl(f, names); if (decl->kind == AstNode_ProcDecl) { - ast_file_err(f, f->cursor[0], "Procedure declarations are not allowed within a structure"); + syntax_error(f->cursor[0], "Procedure declarations are not allowed within a structure"); decl = make_bad_decl(f, ast_node_token(names[0]), f->cursor[0]); } } else { - ast_file_err(f, f->cursor[0], "Illegal structure field"); + syntax_error(f->cursor[0], "Illegal structure field"); decl = make_bad_decl(f, ast_node_token(names[0]), f->cursor[0]); } @@ -1835,13 +1820,9 @@ AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, b32 using_allow gb_array_append(decls, decl); if (decl->kind == AstNode_VarDecl) { decl->VarDecl.is_using = is_using && using_allowed; - - if (decl->VarDecl.kind == Declaration_Mutable) { - if (gb_array_count(decl->VarDecl.values) > 0) { - ast_file_err(f, f->cursor[0], "Default variable assignments within a structure will be ignored (at the moment)"); - } + if (gb_array_count(decl->VarDecl.values) > 0) { + syntax_error(f->cursor[0], "Default variable assignments within a structure will be ignored (at the moment)"); } - } else { decl_count += 1; } @@ -1925,12 +1906,12 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { } else if (are_strings_equal(tag.string, make_string("ordered"))) { is_ordered = true; } else { - ast_file_err(f, tag, "Expected a `#packed` or `#ordered` tag"); + syntax_error(tag, "Expected a `#packed` or `#ordered` tag"); } } if (is_packed && is_ordered) { - ast_file_err(f, token, "`#ordered` is not needed with `#packed` which implies ordering"); + syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering"); } Token open = expect_token(f, Token_OpenBrace); @@ -2034,8 +2015,8 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) { break; // fallthrough default: - ast_file_err(f, f->cursor[0], - "Expected a type after `%.*s`, got `%.*s`", LIT(f->cursor[-1].string), LIT(f->cursor[0].string)); + syntax_error(f->cursor[0], + "Expected a type or identifier after `%.*s`, got `%.*s`", LIT(f->cursor[-1].string), LIT(f->cursor[0].string)); break; } @@ -2109,7 +2090,7 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { if (f->cursor[0].kind == Token_OpenBrace) { if ((tags & ProcTag_foreign) != 0) { - ast_file_err(f, f->cursor[0], "A procedure tagged as `#foreign` cannot have a body"); + syntax_error(f->cursor[0], "A procedure tagged as `#foreign` cannot have a body"); } body = parse_body(f); } @@ -2127,7 +2108,7 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { String n = name->Ident.string; // NOTE(bill): Check for reserved identifiers if (are_strings_equal(n, make_string("context"))) { - ast_file_err(f, ast_node_token(name), "`context` is a reserved identifier"); + syntax_error(ast_node_token(name), "`context` is a reserved identifier"); break; } } @@ -2138,15 +2119,16 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { type = parse_identifier_or_type(f); } } else if (f->cursor[0].kind != Token_Eq && f->cursor[0].kind != Token_Semicolon) { - ast_file_err(f, f->cursor[0], "Expected type separator `:` or `=`"); + syntax_error(f->cursor[0], "Expected type separator `:` or `=`"); } - DeclKind declaration_kind = Declaration_Mutable; + b32 is_mutable = true; if (f->cursor[0].kind == Token_Eq || f->cursor[0].kind == Token_Colon) { - if (f->cursor[0].kind == Token_Colon) - declaration_kind = Declaration_Immutable; + if (f->cursor[0].kind == Token_Colon) { + is_mutable = false; + } next_token(f); if (f->cursor[0].kind == Token_type || @@ -2159,71 +2141,67 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) { next_token(f); } if (gb_array_count(names) != 1) { - ast_file_err(f, ast_node_token(names[0]), "You can only declare one type at a time"); + syntax_error(ast_node_token(names[0]), "You can only declare one type at a time"); return make_bad_decl(f, names[0]->Ident, token); } if (type != NULL) { - ast_file_err(f, f->cursor[-1], "Expected either `type` or nothing between : and :"); + syntax_error(f->cursor[-1], "Expected either `type` or nothing between : and :"); // NOTE(bill): Do not fail though } AstNode *type = parse_type(f); return make_type_decl(f, token, names[0], type); } else if (f->cursor[0].kind == Token_proc && - declaration_kind == Declaration_Immutable) { + is_mutable == false) { // NOTE(bill): Procedure declarations Token proc_token = f->cursor[0]; AstNode *name = names[0]; if (gb_array_count(names) != 1) { - ast_file_err(f, proc_token, "You can only declare one procedure at a time"); + syntax_error(proc_token, "You can only declare one procedure at a time"); return make_bad_decl(f, name->Ident, proc_token); } - AstNode *proc_decl = parse_proc_decl(f, proc_token, name); - return proc_decl; + return parse_proc_decl(f, proc_token, name); } else { values = parse_rhs_expr_list(f); if (gb_array_count(values) > gb_array_count(names)) { - ast_file_err(f, f->cursor[0], "Too many values on the right hand side of the declaration"); - } else if (gb_array_count(values) < gb_array_count(names) && - declaration_kind == Declaration_Immutable) { - ast_file_err(f, f->cursor[0], "All constant declarations must be defined"); + syntax_error(f->cursor[0], "Too many values on the right hand side of the declaration"); + } else if (gb_array_count(values) < gb_array_count(names) && !is_mutable) { + syntax_error(f->cursor[0], "All constant declarations must be defined"); } else if (gb_array_count(values) == 0) { - ast_file_err(f, f->cursor[0], "Expected an expression for this declaration"); + syntax_error(f->cursor[0], "Expected an expression for this declaration"); } } } - if (declaration_kind == Declaration_Mutable) { + if (is_mutable) { if (type == NULL && gb_array_count(values) == 0) { - ast_file_err(f, f->cursor[0], "Missing variable type or initialization"); - return make_bad_decl(f, f->cursor[0], f->cursor[0]); - } - } else if (declaration_kind == Declaration_Immutable) { - if (type == NULL && gb_array_count(values) == 0 && gb_array_count(names) > 0) { - ast_file_err(f, f->cursor[0], "Missing constant value"); + syntax_error(f->cursor[0], "Missing variable type or initialization"); return make_bad_decl(f, f->cursor[0], f->cursor[0]); } } else { - Token begin = f->cursor[0]; - ast_file_err(f, begin, "Unknown type of variable declaration"); - fix_advance_to_next_stmt(f); - return make_bad_decl(f, begin, f->cursor[0]); + if (type == NULL && gb_array_count(values) == 0 && gb_array_count(names) > 0) { + syntax_error(f->cursor[0], "Missing constant value"); + return make_bad_decl(f, f->cursor[0], f->cursor[0]); + } } if (values == NULL) { values = make_ast_node_array(f); } - return make_var_decl(f, declaration_kind, names, type, values); + if (is_mutable) { + return make_var_decl(f, names, type, values); + } + return make_const_decl(f, names, type, values); } AstNode *parse_if_stmt(AstFile *f) { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use an if statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use an if statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2252,7 +2230,7 @@ AstNode *parse_if_stmt(AstFile *f) { f->expr_level = prev_level; if (cond == NULL) { - ast_file_err(f, f->cursor[0], "Expected condition for if statement"); + syntax_error(f->cursor[0], "Expected condition for if statement"); } body = parse_block_stmt(f); @@ -2266,7 +2244,7 @@ AstNode *parse_if_stmt(AstFile *f) { else_stmt = parse_block_stmt(f); break; default: - ast_file_err(f, f->cursor[0], "Expected if statement block statement"); + syntax_error(f->cursor[0], "Expected if statement block statement"); else_stmt = make_bad_stmt(f, f->cursor[0], f->cursor[1]); break; } @@ -2277,7 +2255,7 @@ AstNode *parse_if_stmt(AstFile *f) { AstNode *parse_return_stmt(AstFile *f) { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a return statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a return statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2297,7 +2275,7 @@ AstNode *parse_return_stmt(AstFile *f) { AstNode *parse_for_stmt(AstFile *f) { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a for statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a for statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2314,7 +2292,7 @@ AstNode *parse_for_stmt(AstFile *f) { if (f->cursor[0].kind != Token_Semicolon) { cond = parse_simple_stmt(f); if (is_ast_node_complex_stmt(cond)) { - ast_file_err(f, f->cursor[0], + syntax_error(f->cursor[0], "You are not allowed that type of statement in a for statement, it is too complex!"); } } @@ -2371,7 +2349,7 @@ AstNode *parse_type_case_clause(AstFile *f) { AstNode *parse_match_stmt(AstFile *f) { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a match statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a match statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2444,7 +2422,7 @@ AstNode *parse_match_stmt(AstFile *f) { AstNode *parse_defer_stmt(AstFile *f) { if (f->curr_proc == NULL) { - ast_file_err(f, f->cursor[0], "You cannot use a defer statement in the file scope"); + syntax_error(f->cursor[0], "You cannot use a defer statement in the file scope"); return make_bad_stmt(f, f->cursor[0], f->cursor[0]); } @@ -2452,13 +2430,13 @@ AstNode *parse_defer_stmt(AstFile *f) { AstNode *statement = parse_stmt(f); switch (statement->kind) { case AstNode_EmptyStmt: - ast_file_err(f, token, "Empty statement after defer (e.g. `;`)"); + syntax_error(token, "Empty statement after defer (e.g. `;`)"); break; case AstNode_DeferStmt: - ast_file_err(f, token, "You cannot defer a defer statement"); + syntax_error(token, "You cannot defer a defer statement"); break; case AstNode_ReturnStmt: - ast_file_err(f, token, "You cannot a return statement"); + syntax_error(token, "You cannot a return statement"); break; } @@ -2554,14 +2532,12 @@ AstNode *parse_stmt(AstFile *f) { } } break; case AstNode_VarDecl: - if (node->VarDecl.kind == Declaration_Mutable) { - valid = true; - } + valid = true; break; } if (!valid) { - ast_file_err(f, token, "Illegal use of `using` statement."); + syntax_error(token, "Illegal use of `using` statement."); return make_bad_stmt(f, token, f->cursor[0]); } @@ -2577,7 +2553,7 @@ AstNode *parse_stmt(AstFile *f) { f->is_global_scope = true; return make_empty_stmt(f, f->cursor[0]); } - ast_file_err(f, token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope."); + syntax_error(token, "You cannot use #shared_global_scope within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, f->cursor[0]); } else if (are_strings_equal(tag, make_string("import"))) { // TODO(bill): better error messages @@ -2589,7 +2565,7 @@ AstNode *parse_stmt(AstFile *f) { if (f->curr_proc == NULL) { return make_import_decl(f, s->TagStmt.token, file_path, import_name, false); } - ast_file_err(f, token, "You cannot use #import within a procedure. This must be done at the file scope."); + syntax_error(token, "You cannot use #import within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); } else if (are_strings_equal(tag, make_string("load"))) { // TODO(bill): better error messages @@ -2600,24 +2576,23 @@ AstNode *parse_stmt(AstFile *f) { if (f->curr_proc == NULL) { return make_import_decl(f, s->TagStmt.token, file_path, import_name, true); } - ast_file_err(f, token, "You cannot use #load within a procedure. This must be done at the file scope."); + syntax_error(token, "You cannot use #load within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); } else if (are_strings_equal(tag, make_string("foreign_system_library"))) { Token file_path = expect_token(f, Token_String); if (f->curr_proc == NULL) { return make_foreign_system_library(f, s->TagStmt.token, file_path); } - ast_file_err(f, token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope."); + syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); } else if (are_strings_equal(tag, make_string("thread_local"))) { AstNode *var_decl = parse_simple_stmt(f); - if (var_decl->kind != AstNode_VarDecl || - var_decl->VarDecl.kind != Declaration_Mutable) { - ast_file_err(f, token, "#thread_local may only be applied to variable declarations"); + if (var_decl->kind != AstNode_VarDecl) { + syntax_error(token, "#thread_local may only be applied to variable declarations"); return make_bad_decl(f, token, ast_node_token(var_decl)); } if (f->curr_proc != NULL) { - ast_file_err(f, token, "#thread_local is only allowed at the file scope."); + syntax_error(token, "#thread_local is only allowed at the file scope."); return make_bad_decl(f, token, ast_node_token(var_decl)); } var_decl->VarDecl.tags |= VarDeclTag_thread_local; @@ -2626,14 +2601,14 @@ AstNode *parse_stmt(AstFile *f) { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_bounds_check; if ((s->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) { - ast_file_err(f, token, "#bounds_check and #no_bounds_check cannot be applied together"); + syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together"); } return s; } else if (are_strings_equal(tag, make_string("no_bounds_check"))) { s = parse_stmt(f); s->stmt_state_flags |= StmtStateFlag_no_bounds_check; if ((s->stmt_state_flags & StmtStateFlag_bounds_check) != 0) { - ast_file_err(f, token, "#bounds_check and #no_bounds_check cannot be applied together"); + syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together"); } return s; } @@ -2651,7 +2626,7 @@ AstNode *parse_stmt(AstFile *f) { return s; } - ast_file_err(f, token, + syntax_error(token, "Expected a statement, got `%.*s`", LIT(token_strings[token.kind])); fix_advance_to_next_stmt(f); @@ -2837,14 +2812,14 @@ void parse_file(Parser *p, AstFile *f) { node->kind != AstNode_BadStmt && node->kind != AstNode_EmptyStmt) { // NOTE(bill): Sanity check - ast_file_err(f, ast_node_token(node), "Only declarations are allowed at file scope"); + syntax_error(ast_node_token(node), "Only declarations are allowed at file scope"); } else { if (node->kind == AstNode_ImportDecl) { auto *id = &node->ImportDecl; String file_str = id->relpath.string; if (!is_import_path_valid(file_str)) { - ast_file_err(f, ast_node_token(node), "Invalid `load` path"); + syntax_error(ast_node_token(node), "Invalid `load` path"); continue; } @@ -2868,7 +2843,7 @@ void parse_file(Parser *p, AstFile *f) { String file_str = id->filepath.string; if (!is_import_path_valid(file_str)) { - ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path"); + syntax_error(ast_node_token(node), "Invalid `foreign_system_library` path"); continue; } diff --git a/src/printer.cpp b/src/printer.cpp index f53e69364..1b246c07a 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -142,11 +142,18 @@ void print_ast(AstNode *node, isize indent) { case AstNode_VarDecl: print_indent(indent); - if (node->VarDecl.kind == Declaration_Mutable) { - gb_printf("(decl:var,mutable)\n"); - } else if (node->VarDecl.kind == Declaration_Immutable) { - gb_printf("(decl:var,immutable)\n"); + gb_printf("(decl:var)\n"); + gb_for_array(i, node->VarDecl.names) { + print_ast(node->VarDecl.names[i], indent+1); } + print_ast(node->VarDecl.type, indent+1); + gb_for_array(i, node->VarDecl.values) { + print_ast(node->VarDecl.values[i], indent+1); + } + break; + case AstNode_ConstDecl: + print_indent(indent); + gb_printf("(decl:const)\n"); gb_for_array(i, node->VarDecl.names) { print_ast(node->VarDecl.names[i], indent+1); } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 12b394a01..6f645b7a6 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -155,31 +155,58 @@ Token empty_token = {Token_Invalid}; struct ErrorCollector { TokenPos prev; i64 count; + i64 warning_count; }; -gb_no_inline void error(ErrorCollector *ec, Token token, char *fmt, ...) { - ec->count++; - // NOTE(bill): Duplicate error, skip it - if (!token_pos_are_equal(ec->prev, token.pos)) { - ec->prev = token.pos; +gb_global ErrorCollector global_error_collector; + +void warning(Token token, char *fmt, ...) { + global_error_collector.warning_count++; + // NOTE(bill): Duplicate error, skip it + if (!token_pos_are_equal(global_error_collector.prev, token.pos)) { va_list va; + + global_error_collector.prev = token.pos; + + va_start(va, fmt); + gb_printf_err("%.*s(%td:%td) Warning: %s\n", + LIT(token.pos.file), token.pos.line, token.pos.column, + gb_bprintf_va(fmt, va)); + va_end(va); + } +} + +void error(Token token, char *fmt, ...) { + global_error_collector.count++; + // NOTE(bill): Duplicate error, skip it + if (!token_pos_are_equal(global_error_collector.prev, token.pos)) { + va_list va; + + global_error_collector.prev = token.pos; + va_start(va, fmt); gb_printf_err("%.*s(%td:%td) %s\n", LIT(token.pos.file), token.pos.line, token.pos.column, gb_bprintf_va(fmt, va)); va_end(va); - } } -gb_no_inline void warning(Token token, char *fmt, ...) { - va_list va; - va_start(va, fmt); - gb_printf_err("%.*s(%td:%td) Warning: %s\n", - LIT(token.pos.file), token.pos.line, token.pos.column, - gb_bprintf_va(fmt, va)); - va_end(va); +void syntax_error(Token token, char *fmt, ...) { + global_error_collector.count++; + // NOTE(bill): Duplicate error, skip it + if (!token_pos_are_equal(global_error_collector.prev, token.pos)) { + va_list va; + + global_error_collector.prev = token.pos; + + va_start(va, fmt); + gb_printf_err("%.*s(%td:%td) Syntax Error: %s\n", + LIT(token.pos.file), token.pos.line, token.pos.column, + gb_bprintf_va(fmt, va)); + va_end(va); + } }