aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--code/demo.odin3
-rw-r--r--code/fmt.odin583
-rw-r--r--code/os.odin107
-rw-r--r--code/punity.odin484
-rw-r--r--src/checker/checker.cpp131
-rw-r--r--src/checker/entity.cpp3
-rw-r--r--src/checker/expr.cpp410
-rw-r--r--src/checker/stmt.cpp306
-rw-r--r--src/codegen/codegen.cpp10
-rw-r--r--src/codegen/ssa.cpp126
-rw-r--r--src/parser.cpp251
-rw-r--r--src/printer.cpp15
-rw-r--r--src/tokenizer.cpp51
13 files changed, 1825 insertions, 655 deletions
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, "<invalid>")
+ }
+
+ 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(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);
- }
+ 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(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);
- 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?
- }
+ 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;
- 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;
- }
+ case_ast_node(vd, VarDecl, decl);
+ 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?
+ }
- add_file_entity(c, file_scope, name, e, d);
+ 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;
}
- } 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<Entity *>
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_Invalid:
+ break;
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:
+ 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 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_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;
- }
+
+ 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);
+ add_entity_definition(&c->info, name, entity);
} else {
- error(&c->error_collector, token, "A variable declaration must be an identifier");
+ 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;
}
- 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;
+ } 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;
+ }
- 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;
+ Type *init_type = NULL;
+ if (vd->type) {
+ init_type = check_type(c, vd->type, NULL);
+ if (init_type == NULL)
+ init_type = t_invalid;
+ }
- if (e->type == NULL)
- e->type = init_type;
+ 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;
- check_init_variables(c, entities, entity_count, vd->values, make_string("variable declaration"));
+ if (e->type == NULL)
+ e->type = init_type;
+ }
- gb_for_array(i, vd->names) {
- add_entity(c, c->context.scope, vd->names[i], new_entities[i]);
- }
+ check_init_variables(c, entities, entity_count, vd->values, make_string("variable declaration"));
- } break;
+ gb_for_array(i, vd->names) {
+ if (entities[i] != NULL) {
+ add_entity(c, c->context.scope, vd->names[i], entities[i]);
+ }
+ }
- 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);
- } else {
- entities[entity_index++] = found;
- }
- }
- isize lhs_count = gb_array_count(vd->names);
- isize rhs_count = gb_array_count(vd->values);
+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);
- // 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");
+ 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;
}
+ }
- gb_for_array(i, vd->names) {
- add_entity(c, c->context.scope, vd->names[i], entities[i]);
- }
- } break;
+ isize lhs_count = gb_array_count(vd->names);
+ isize rhs_count = gb_array_count(vd->values);
- default:
- error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
- return;
+ // 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_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->values) {
+ ssaValue *init = ssa_build_expr(proc, vd->values[i]);
+ gb_array_append(inits, init);
+ }
- 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);
+ }
- 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 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);
}
- } 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_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, 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");
+ syntax_error(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) {
+ } else {
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 constant value");
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 (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++;
+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(ec->prev, token.pos)) {
- ec->prev = token.pos;
+ 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);
+ }
}