diff options
| author | Zachary Pierson <zacpiersonhehe@gmail.com> | 2017-02-10 23:41:23 -0600 |
|---|---|---|
| committer | Zachary Pierson <zacpiersonhehe@gmail.com> | 2017-02-10 23:41:23 -0600 |
| commit | cad46ae51c8d3baed5a6c6d64a6e5d57fbe2a397 (patch) | |
| tree | e931af6c1536ab8913d8168e7ee109a64dc7c981 | |
| parent | 3424b2badd347b76ced3f4107d98a12bb50ae49b (diff) | |
| parent | 73d6a55f5c96459d30eca5747d1458bcf6e9fec4 (diff) | |
Merge https://github.com/gingerBill/Odin
| -rw-r--r-- | code/demo.odin | 77 | ||||
| -rw-r--r-- | code/http_test.odin | 2 | ||||
| -rw-r--r-- | core/_preload.odin | 45 | ||||
| -rw-r--r-- | core/fmt.odin | 42 | ||||
| -rw-r--r-- | core/math.odin | 4 | ||||
| -rw-r--r-- | core/mem.odin | 73 | ||||
| -rw-r--r-- | core/sys/windows.odin | 7 | ||||
| -rw-r--r-- | core/types.odin | 48 | ||||
| -rw-r--r-- | src/check_expr.c | 181 | ||||
| -rw-r--r-- | src/check_stmt.c | 30 | ||||
| -rw-r--r-- | src/checker.c | 99 | ||||
| -rw-r--r-- | src/entity.c | 1 | ||||
| -rw-r--r-- | src/ir.c | 170 | ||||
| -rw-r--r-- | src/ir_print.c | 21 | ||||
| -rw-r--r-- | src/parser.c | 118 | ||||
| -rw-r--r-- | src/tokenizer.c | 209 | ||||
| -rw-r--r-- | src/types.c | 91 |
17 files changed, 532 insertions, 686 deletions
diff --git a/code/demo.odin b/code/demo.odin index bc193ef1f..2577f8d3c 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,16 +11,27 @@ main :: proc() { { + Fruit :: enum { + APPLE, + BANANA, + COCONUT, + } + + fmt.println(Fruit.names); + } + +when false { + { m: map[f32]int; - reserve(^m, 16); + reserve(m, 16); defer free(m); m[1.0] = 1278; m[2.0] = 7643; m[3.0] = 564; - c := m[3.0]; _, ok := m[3.0]; - // assert(ok && c == 564); + c := m[3.0]; + assert(ok && c == 564); fmt.print("map["); i := 0; @@ -28,7 +39,7 @@ main :: proc() { if i > 0 { fmt.print(", "); } - fmt.printf("%f=%v", key, val); + fmt.printf("%v=%v", key, val); i += 1; } fmt.println("]"); @@ -48,48 +59,36 @@ main :: proc() { fmt.println(m); } - - - // fm: map[128, int]f32; - -/* { - sig: u32; - x := __cpuid(0, ^sig); - fmt.println(sig, x); - } - - - - i: int; - - fmt.println("Hellope!"); + fmt.println("Hellope!"); - x: [dynamic]f64; - defer free(x); - append(^x, 2_000_000.500_000, 3, 5, 7); + x: [dynamic]f64; + reserve(x, 16); + defer free(x); + append(x, 2_000_000.500_000, 3, 5, 7); - for p, i in x { - if i > 0 { fmt.print(", "); } - fmt.print(p); - } - fmt.println(); + for p, i in x { + if i > 0 { fmt.print(", "); } + fmt.print(p); + } + fmt.println(); - { - Vec3 :: [vector 3]f32; + { + Vec3 :: [vector 3]f32; - x := Vec3{1, 2, 3}; - y := Vec3{4, 5, 6}; - fmt.println(x < y); - fmt.println(x + y); - fmt.println(x - y); - fmt.println(x * y); - fmt.println(x / y); + x := Vec3{1, 2, 3}; + y := Vec3{4, 5, 6}; + fmt.println(x < y); + fmt.println(x + y); + fmt.println(x - y); + fmt.println(x * y); + fmt.println(x / y); - for i in x { - fmt.println(i); + for i in x { + fmt.println(i); + } } } -*/ +} } diff --git a/code/http_test.odin b/code/http_test.odin index e6c5f1173..ca76e1c55 100644 --- a/code/http_test.odin +++ b/code/http_test.odin @@ -3,7 +3,7 @@ #foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows"; -SOCKET :: type uint; +SOCKET :: #type uint; INVALID_SOCKET :: ~(cast(SOCKET)0); AF :: enum i32 { diff --git a/core/_preload.odin b/core/_preload.odin index 1eb8a2d06..802fc3801 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -52,15 +52,12 @@ Type_Info :: union { Float: struct #ordered { size: int, // in bytes }, - Any: struct #ordered {}, String: struct #ordered {}, Boolean: struct #ordered {}, + Any: struct #ordered {}, Pointer: struct #ordered { elem: ^Type_Info, // nil -> rawptr }, - Maybe: struct #ordered { - elem: ^Type_Info, - }, Procedure: struct #ordered { params: ^Type_Info, // Type_Info.Tuple results: ^Type_Info, // Type_Info.Tuple @@ -112,7 +109,7 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { return nil; } base := info; - match type i in base { + match i in base { case Type_Info.Named: base = i.base; } @@ -125,7 +122,7 @@ type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info { return nil; } base := info; - match type i in base { + match i in base { case Type_Info.Named: base = i.base; case Type_Info.Enum: @@ -146,6 +143,8 @@ __cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid" + + // IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it) Allocator_Mode :: enum u8 { ALLOC, @@ -153,9 +152,9 @@ Allocator_Mode :: enum u8 { FREE_ALL, RESIZE, } -Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64) -> rawptr; +Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr; Allocator :: struct #ordered { procedure: Allocator_Proc, data: rawptr, @@ -199,23 +198,17 @@ free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline { if ptr == nil { return; } - a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0); -} - -__free_raw_dynamic_array :: proc(a: ^Raw_Dynamic_Array) { - if a.allocator.procedure == nil { - return; - } - if a.data == nil { + if a.procedure == nil { return; } - free_ptr_with_allocator(a.allocator, a.data); + a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0); } free_ptr :: proc(ptr: rawptr) #inline { __check_context(); free_ptr_with_allocator(context.allocator, ptr); } + free_all :: proc() #inline { __check_context(); a := context.allocator; @@ -306,11 +299,11 @@ __string_eq :: proc(a, b: string) -> bool { if a.data == b.data { return true; } - return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, a.count) == 0; + return __string_cmp(a, b) == 0; } __string_cmp :: proc(a, b: string) -> int { - return mem.compare(cast(rawptr)a.data, cast(rawptr)b.data, min(a.count, b.count)); + return mem.compare(cast([]byte)a, cast([]byte)b); } __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); } @@ -504,7 +497,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) { nm: Raw_Dynamic_Map; new_header.m = ^nm; - reserve(^nm.hashes, new_count); + reserve(nm.hashes, new_count); nm.hashes.count = nm.hashes.capacity; __dynamic_array_reserve(^nm.entries, entry_size, entry_align, m.entries.count); for _, i in nm.hashes { @@ -660,3 +653,13 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) { m.hashes[last.hash_index] = fr.entry_index; } } + + +__print_ti_ptr :: proc(ti: ^Type_Info) { + fmt.println(ti); + match e in ti { + case Type_Info.Enum: + fmt.println(e.names); + } +} + diff --git a/core/fmt.odin b/core/fmt.odin index 91519167b..caa17f77d 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -107,7 +107,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { } using Type_Info; - match type info in ti { + match info in ti { case Named: buffer_write_string(buf, info.name); case Integer: @@ -134,9 +134,6 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { buffer_write_string(buf, "^"); buffer_write_type(buf, info.elem); } - case Maybe: - buffer_write_string(buf, "?"); - buffer_write_type(buf, info.elem); case Procedure: buffer_write_string(buf, "proc"); if info.params == nil { @@ -358,7 +355,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) { if arg_index < args.count { arg := args[arg_index]; arg.type_info = type_info_base(arg.type_info); - match type i in arg { + match i in arg { case int: num = i; case i8: num = cast(int)i; case i16: num = cast(int)i; @@ -420,8 +417,9 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { } fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) { - negative := signed && cast(i64)u < 0; - u = abs(u); + s := cast(i64)u; + negative := signed && s < 0; + u = cast(u64)abs(s); buf: [256]byte; if fi.width_set || fi.prec_set { width := fi.width + fi.prec + 3; @@ -628,6 +626,7 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) { fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) { match verb { case 'p', 'v': + // Okay default: fmt_bad_verb(fi, verb); return; @@ -646,7 +645,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { } using Type_Info; - match type e in v.type_info { + match e in v.type_info { default: fmt_bad_verb(fi, verb); return; @@ -659,7 +658,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) { f: f64; ok := false; a := any{type_info_base(e.base), v.data}; - match type v in a { + match v in a { case i8: i = cast(i64)v; case i16: i = cast(i64)v; case i32: i = cast(i64)v; @@ -710,9 +709,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { } using Type_Info; - match type info in v.type_info { + match info in v.type_info { case Named: - match type b in info.base { + match b in info.base { case Struct: if verb != 'v' { fmt_bad_verb(fi, verb); @@ -747,16 +746,6 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_pointer(fi, (cast(^rawptr)v.data)^, verb); } - case Maybe: - // TODO(bill): Correct verbs for Maybe types? - size := mem.size_of_type_info(info.elem); - data := slice_ptr(cast(^byte)v.data, size+1); - if data[size] != 0 { - fmt_arg(fi, any{info.elem, v.data}, verb); - } else { - buffer_write_string(fi.buf, "nil"); - } - case Array: if verb != 'v' { fmt_bad_verb(fi, verb); @@ -799,9 +788,10 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { buffer_write_string(fi.buf, "map["); defer buffer_write_byte(fi.buf, ']'); entries := ^(cast(^Raw_Dynamic_Map)v.data).entries; - gs, _ := union_cast(^Struct)info.generated_struct; - ed, _ := union_cast(^Dynamic_Array)gs.fields[1].type_info; - entry_type, _ := union_cast(^Struct)ed.elem; + gs, gs_ok := union_cast(^Struct)type_info_base(info.generated_struct); assert(gs_ok); + ed, ed_ok := union_cast(^Dynamic_Array)type_info_base(gs.fields[1].type_info); assert(ed_ok); + + entry_type, et_ok := union_cast(^Struct)ed.elem; assert(et_ok); entry_size := ed.elem_size; for i in 0..<entries.count { if i > 0 { @@ -892,7 +882,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { if verb == 'T' { ti := arg.type_info; - match type a in arg { + match a in arg { case ^Type_Info: ti = a; } buffer_write_type(fi.buf, ti); @@ -902,7 +892,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { base_arg := arg; base_arg.type_info = type_info_base(base_arg.type_info); - match type a in base_arg { + match a in base_arg { case bool: fmt_bool(fi, a, verb); case f32: fmt_float(fi, cast(f64)a, 32, verb); case f64: fmt_float(fi, a, 64, verb); diff --git a/core/math.odin b/core/math.odin index b8f8df360..6214bf824 100644 --- a/core/math.odin +++ b/core/math.odin @@ -46,10 +46,6 @@ bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16"; bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32"; bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64"; -byte_swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16"; -byte_swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32"; -byte_swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64"; - fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32"; fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64"; diff --git a/core/mem.odin b/core/mem.odin index bf789c608..ce1c4a21c 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -1,6 +1,11 @@ #import "fmt.odin"; #import "os.odin"; +swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16"; +swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32"; +swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64"; + + set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" { llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64"; llvm_memset_64bit(data, cast(byte)value, len, 1, false); @@ -12,22 +17,21 @@ zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" { } copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" { - // NOTE(bill): This _must_ implemented like C's memmove + // NOTE(bill): This _must_ be implemented like C's memmove llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64"; llvm_memmove_64bit(dst, src, len, 1, false); return dst; } copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" { - // NOTE(bill): This _must_ implemented like C's memcpy + // NOTE(bill): This _must_ be implemented like C's memcpy llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64"; llvm_memcpy_64bit(dst, src, len, 1, false); return dst; } -compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" { - a := slice_ptr(cast(^byte)dst, n); - b := slice_ptr(cast(^byte)src, n); +compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" { + n := min(a.count, b.count); for i in 0..<n { match { case a[i] < b[i]: @@ -43,8 +47,8 @@ compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" { kilobytes :: proc(x: int) -> int #inline { return (x) * 1024; } megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024; } -gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; } -terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024; } +gigabytes :: proc(x: int) -> int #inline { return megabytes(x) * 1024; } +terabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024; } is_power_of_two :: proc(x: int) -> bool { if x <= 0 { @@ -213,8 +217,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int { WORD_SIZE :: size_of(int); MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants? using Type_Info; - - match type info in type_info { + match info in type_info { case Named: return align_of_type_info(info.base); case Integer: @@ -225,14 +228,16 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int { return WORD_SIZE; case Boolean: return 1; + case Any: + return WORD_SIZE; case Pointer: return WORD_SIZE; - case Maybe: - return max(align_of_type_info(info.elem), 1); case Procedure: return WORD_SIZE; case Array: return align_of_type_info(info.elem); + case Dynamic_Array: + return WORD_SIZE; case Slice: return WORD_SIZE; case Vector: @@ -240,12 +245,18 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int { count := cast(int)max(prev_pow2(cast(i64)info.count), 1); total := size * count; return clamp(total, 1, MAX_ALIGN); + case Tuple: + return info.align; case Struct: return info.align; case Union: return info.align; case Raw_Union: return info.align; + case Enum: + return align_of_type_info(info.base); + case Map: + return align_of_type_info(info.generated_struct); } return 0; @@ -259,23 +270,21 @@ align_formula :: proc(size, align: int) -> int { size_of_type_info :: proc(type_info: ^Type_Info) -> int { WORD_SIZE :: size_of(int); using Type_Info; - match type info in type_info { + match info in type_info { case Named: return size_of_type_info(info.base); case Integer: return info.size; case Float: return info.size; - case Any: - return 2*WORD_SIZE; case String: return 2*WORD_SIZE; case Boolean: return 1; + case Any: + return 2*WORD_SIZE; case Pointer: return WORD_SIZE; - case Maybe: - return size_of_type_info(info.elem) + 1; case Procedure: return WORD_SIZE; case Array: @@ -287,39 +296,29 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int { align := align_of_type_info(info.elem); alignment := align_formula(size, align); return alignment*(count-1) + size; + case Dynamic_Array: + return size_of(rawptr) + 2*size_of(int) + size_of(Allocator); case Slice: - return 3*WORD_SIZE; + return 2*WORD_SIZE; case Vector: - is_bool :: proc(type_info: ^Type_Info) -> bool { - match type info in type_info { - case Named: - return is_bool(info.base); - case Boolean: - return true; - } - return false; - } - count := info.count; if count == 0 { return 0; } - bit_size := 8*size_of_type_info(info.elem); - if is_bool(info.elem) { - // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1` - // Silly LLVM spec - bit_size = 1; - } - total_size_in_bits := bit_size * count; - total_size := (total_size_in_bits+7)/8; - return total_size; - + size := size_of_type_info(info.elem); + align := align_of_type_info(info.elem); + alignment := align_formula(size, align); + return alignment*(count-1) + size; case Struct: return info.size; case Union: return info.size; case Raw_Union: return info.size; + case Enum: + return size_of_type_info(info.base); + case Map: + return size_of_type_info(info.generated_struct); } return 0; diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 01bad758c..2aca8fe1d 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -1,3 +1,4 @@ +_ := compile_assert(ODIN_OS == "windows"); #foreign_system_library "kernel32.lib"; #foreign_system_library "user32.lib"; #foreign_system_library "gdi32.lib"; @@ -19,7 +20,7 @@ LPARAM :: int; LRESULT :: int; ATOM :: i16; BOOL :: i32; -WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; +WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; INVALID_HANDLE_VALUE :: cast(HANDLE)(~cast(int)0); @@ -358,8 +359,8 @@ PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000; PFD_STEREO_DONTCARE :: 0x80000000; HGLRC :: HANDLE; -PROC :: type proc() #cc_c; -wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; +PROC :: #type proc() #cc_c; +wglCreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; PIXELFORMATDESCRIPTOR :: struct #ordered { diff --git a/core/types.odin b/core/types.odin index 5464346d1..5a46770d5 100644 --- a/core/types.odin +++ b/core/types.odin @@ -11,7 +11,7 @@ is_signed :: proc(info: ^Type_Info) -> bool { is_integer :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Integer: return true; } return false; @@ -19,7 +19,7 @@ is_integer :: proc(info: ^Type_Info) -> bool { is_float :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Float: return true; } return false; @@ -27,7 +27,7 @@ is_float :: proc(info: ^Type_Info) -> bool { is_any :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Any: return true; } return false; @@ -35,7 +35,7 @@ is_any :: proc(info: ^Type_Info) -> bool { is_string :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.String: return true; } return false; @@ -43,7 +43,7 @@ is_string :: proc(info: ^Type_Info) -> bool { is_boolean :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Boolean: return true; } return false; @@ -51,23 +51,15 @@ is_boolean :: proc(info: ^Type_Info) -> bool { is_pointer :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Pointer: return true; } return false; } -is_maybe :: proc(info: ^Type_Info) -> bool { - if info == nil { return false; } - - match type i in type_info_base(info) { - case Type_Info.Maybe: return true; - } - return false; -} is_procedure :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Procedure: return true; } return false; @@ -75,7 +67,7 @@ is_procedure :: proc(info: ^Type_Info) -> bool { is_array :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Array: return true; } return false; @@ -83,15 +75,23 @@ is_array :: proc(info: ^Type_Info) -> bool { is_dynamic_array :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Dynamic_Array: return true; } return false; } +is_dynamic_map :: proc(info: ^Type_Info) -> bool { + if info == nil { return false; } + + match i in type_info_base(info) { + case Type_Info.Map: return i.count == 0; + } + return false; +} is_slice :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Slice: return true; } return false; @@ -99,7 +99,7 @@ is_slice :: proc(info: ^Type_Info) -> bool { is_vector :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Vector: return true; } return false; @@ -107,7 +107,7 @@ is_vector :: proc(info: ^Type_Info) -> bool { is_tuple :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Tuple: return true; } return false; @@ -115,7 +115,7 @@ is_tuple :: proc(info: ^Type_Info) -> bool { is_struct :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Struct: return true; } return false; @@ -123,7 +123,7 @@ is_struct :: proc(info: ^Type_Info) -> bool { is_union :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Union: return true; } return false; @@ -131,7 +131,7 @@ is_union :: proc(info: ^Type_Info) -> bool { is_raw_union :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Raw_Union: return true; } return false; @@ -139,7 +139,7 @@ is_raw_union :: proc(info: ^Type_Info) -> bool { is_enum :: proc(info: ^Type_Info) -> bool { if info == nil { return false; } - match type i in type_info_base(info) { + match i in type_info_base(info) { case Type_Info.Enum: return true; } return false; diff --git a/src/check_expr.c b/src/check_expr.c index 04f246532..d3bc5895c 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -167,14 +167,6 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { return 1; } - if (is_type_maybe(dst)) { - Type *elem = base_type(dst)->Maybe.elem; - if (are_types_identical(elem, s)) { - return 1; - } - return -1; - } - if (check_is_assignable_to_using_subtype(operand->type, type)) { return 4; } @@ -743,7 +735,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod } else if (str_eq(name, str_lit("max_value"))) { error_node(field, "`max_value` is a reserved identifier for enumerations"); continue; - } + } else if (str_eq(name, str_lit("names"))) { + error_node(field, "`names` is a reserved identifier for enumerations"); + continue; + }/* else if (str_eq(name, str_lit("base_type"))) { + error_node(field, "`base_type` is a reserved identifier for enumerations"); + continue; + } */ if (compare_exact_values(Token_Gt, min_value, iota)) { min_value = iota; @@ -779,6 +777,11 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope, make_token_ident(str_lit("max_value")), constant_type, max_value); + enum_type->Record.enum_names = make_entity_field(c->allocator, c->context.scope, + make_token_ident(str_lit("names")), t_string_slice, false, 0); + enum_type->Record.enum_names->Variable.is_immutable = true; + enum_type->Record.enum_names->flags |= EntityFlag_EnumField; + gb_temp_arena_memory_end(tmp); } @@ -909,7 +912,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { } -void check_ident (Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint) { +void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint) { GB_ASSERT(n->kind == AstNode_Ident); o->mode = Addressing_Invalid; o->expr = n; @@ -1285,12 +1288,6 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { goto end; case_end; - case_ast_node(mt, MaybeType, e); - Type *elem = check_type(c, mt->type); - type = make_type_maybe(c->allocator, elem); - goto end; - case_end; - case_ast_node(at, ArrayType, e); if (at->count != NULL) { Type *elem = check_type_extra(c, at->elem, NULL); @@ -1689,29 +1686,6 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { o->type = make_type_pointer(c->allocator, o->type); return; } - - case Token_Maybe: { // Make maybe - Type *t = default_type(o->type); - - if (o->mode == Addressing_Type) { - o->type = make_type_pointer(c->allocator, t); - return; - } - - if (!is_operand_value(*o) || is_type_untyped(t)) { - if (ast_node_expect(node, AstNode_UnaryExpr)) { - ast_node(ue, UnaryExpr, node); - gbString str = expr_to_string(ue->expr); - error(op, "Cannot convert `%s` to a maybe", str); - gb_string_free(str); - } - o->mode = Addressing_Invalid; - return; - } - o->mode = Addressing_Value; - o->type = make_type_maybe(c->allocator, t); - return; - } } if (!check_unary_op(c, o, op)) { @@ -2436,13 +2410,6 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level } break; - case Type_Maybe: - if (is_type_untyped_nil(operand->type)) { - // Okay - } else if (level == 0) { - goto error; - } - default: if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { goto error; @@ -2545,7 +2512,14 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h check_op_expr = false; entity = scope_lookup_entity(e->ImportName.scope, sel_name); - if (entity == NULL) { + bool is_declared = entity != NULL; + if (entity->kind == Entity_Builtin) { + is_declared = false; + } + if (entity->scope->is_global && !e->ImportName.scope->is_global) { + is_declared = false; + } + if (!is_declared) { error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name)); goto error; } @@ -2638,6 +2612,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h if (entity == NULL && selector->kind == AstNode_Ident) { sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type); entity = sel.entity; + + // NOTE(bill): Add enum type info needed for fields like `names` + if (entity != NULL && (entity->flags&EntityFlag_EnumField)) { + add_type_info_type(c, operand->type); + } } if (entity == NULL && selector->kind == AstNode_BasicLit) { if (is_type_struct(operand->type) || is_type_tuple(operand->type)) { @@ -2699,6 +2678,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h } + add_entity_use(c, selector, entity); switch (entity->kind) { @@ -2755,10 +2735,11 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } if (err) { - ast_node(proc, Ident, ce->proc); - error(ce->close, "`%s` arguments for `%.*s`, expected %td, got %td", - err, LIT(proc->string), + gbString expr = expr_to_string(ce->proc); + error(ce->close, "`%s` arguments for `%s`, expected %td, got %td", + err, expr, bp->arg_count, ce->args.count); + gb_string_free(expr); return false; } } @@ -2852,19 +2833,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_reserve: { - // reserve :: proc(^[dynamic]Type, count: int) { - // reserve :: proc(^map[Key]Type, count: int) { + // reserve :: proc([dynamic]Type, count: int) { + // reserve :: proc(map[Key]Type, count: int) { Type *type = operand->type; - if (!is_type_pointer(type)) { - gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer, got `%s`", str); - gb_string_free(str); - return false; - } - type = type_deref(type); if (!is_type_dynamic_array(type) && !is_type_dynamic_map(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array or dynamic map, got `%s`", str); + error_node(operand->expr, "Expected a dynamic array or dynamic map, got `%s`", str); gb_string_free(str); return false; } @@ -2887,16 +2861,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_clear: { Type *type = operand->type; - if (!is_type_pointer(type)) { - gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer, got `%s`", str); - gb_string_free(str); - return false; - } - type = type_deref(type); if (!is_type_dynamic_array(type) && !is_type_map(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a map or dynamic array, got `%s`", str); + error_node(operand->expr, "Expected a map or dynamic array, got `%s`", str); gb_string_free(str); return false; } @@ -2906,18 +2873,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; case BuiltinProc_append: { - // append :: proc(^[dynamic]Type, item: ...Type) { + // append :: proc([dynamic]Type, item: ...Type) { Type *type = operand->type; - if (!is_type_pointer(type)) { - gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str); - gb_string_free(str); - return false; - } - type = base_type(type_deref(type)); + type = base_type(type); if (!is_type_dynamic_array(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str); + error_node(operand->expr, "Expected a dynamic array, got `%s`", str); gb_string_free(str); return false; } @@ -3140,7 +3101,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; case BuiltinProc_compile_assert: - // compile_assert :: proc(cond: bool) + // compile_assert :: proc(cond: bool) -> bool if (!is_type_boolean(operand->type) && operand->mode != Addressing_Constant) { gbString str = expr_to_string(ce->args.e[0]); @@ -3153,10 +3114,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id error_node(call, "Compile time assertion: `%s`", str); gb_string_free(str); } + + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; break; case BuiltinProc_assert: - // assert :: proc(cond: bool) + // assert :: proc(cond: bool) -> bool if (!is_type_boolean(operand->type)) { gbString str = expr_to_string(ce->args.e[0]); @@ -3165,7 +3129,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - operand->mode = Addressing_NoValue; + operand->mode = Addressing_Value; + operand->type = t_untyped_bool; break; case BuiltinProc_panic: @@ -4801,11 +4766,12 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->expr = node; case_end; - case_ast_node(te, TagExpr, node); - // TODO(bill): Tag expressions - error_node(node, "Tag expressions are not supported yet"); - kind = check_expr_base(c, o, te->expr, type_hint); + String name = te->name.string; + error_node(node, "Unknown tag expression, #%.*s", LIT(name)); + if (te->expr) { + kind = check_expr_base(c, o, te->expr, type_hint); + } o->expr = node; case_end; @@ -5187,37 +5153,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } case_end; - case_ast_node(de, DemaybeExpr, node); - check_expr_or_type(c, o, de->expr); - if (o->mode == Addressing_Invalid) { - goto error; - } else { - Type *t = base_type(o->type); - if (t->kind == Type_Maybe) { - Entity **variables = gb_alloc_array(c->allocator, Entity *, 2); - Type *elem = t->Maybe.elem; - Token tok = make_token_ident(str_lit("")); - variables[0] = make_entity_param(c->allocator, NULL, tok, elem, false, true); - variables[1] = make_entity_param(c->allocator, NULL, tok, t_bool, false, true); - - Type *tuple = make_type_tuple(c->allocator); - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = 2; - - o->type = tuple; - o->mode = Addressing_Variable; - } else { - gbString str = expr_to_string(o->expr); - error_node(o->expr, "Cannot demaybe `%s`", str); - gb_string_free(str); - goto error; - } - } - case_end; - case AstNode_ProcType: case AstNode_PointerType: - case AstNode_MaybeType: case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: @@ -5401,14 +5338,17 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, ue->expr); case_end; - case_ast_node(de, DerefExpr, node); - str = write_expr_to_string(str, de->expr); - str = gb_string_appendc(str, "^"); + case_ast_node(ce, CastExpr, node); + str = string_append_token(str, ce->token); + str = gb_string_appendc(str, "("); + str = write_expr_to_string(str, ce->type); + str = gb_string_appendc(str, ")"); + str = write_expr_to_string(str, ce->expr); case_end; - case_ast_node(de, DemaybeExpr, node); + case_ast_node(de, DerefExpr, node); str = write_expr_to_string(str, de->expr); - str = gb_string_appendc(str, "?"); + str = gb_string_appendc(str, "^"); case_end; case_ast_node(be, BinaryExpr, node); @@ -5462,11 +5402,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, pt->type); case_end; - case_ast_node(mt, MaybeType, node); - str = gb_string_appendc(str, "?"); - str = write_expr_to_string(str, mt->type); - case_end; - case_ast_node(at, ArrayType, node); str = gb_string_appendc(str, "["); str = write_expr_to_string(str, at->count); diff --git a/src/check_stmt.c b/src/check_stmt.c index 9155947fc..9067d1037 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -942,7 +942,25 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { bool is_union_ptr = false; bool is_any = false; - check_expr(c, &x, ms->tag); + if (ms->tag->kind != AstNode_AssignStmt) { + error_node(ms->tag, "Expected an `in` assignment for this type match statement"); + break; + } + + ast_node(as, AssignStmt, ms->tag); + Token as_token = ast_node_token(ms->tag); + if (as->lhs.count != 1) { + syntax_error(as_token, "Expected 1 name before `in`"); + break; + } + if (as->rhs.count != 1) { + syntax_error(as_token, "Expected 1 expression after `in`"); + break; + } + AstNode *lhs = as->lhs.e[0]; + AstNode *rhs = as->rhs.e[0]; + + check_expr(c, &x, rhs); check_assignment(c, &x, NULL, str_lit("type match expression")); if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) { gbString str = type_to_string(x.type); @@ -980,7 +998,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { } } - if (ms->var->kind != AstNode_Ident) { + + if (unparen_expr(lhs)->kind != AstNode_Ident) { + error_node(rhs, "Expected an identifier, got `%.*s`", LIT(ast_node_strings[rhs->kind])); break; } @@ -1056,10 +1076,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { tt = make_type_pointer(c->allocator, case_type); add_type_info_type(c, tt); } - Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tt, true); + Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, tt, true); tag_var->flags |= EntityFlag_Used; - add_entity(c, c->context.scope, ms->var, tag_var); - add_entity_use(c, ms->var, tag_var); + add_entity(c, c->context.scope, lhs, tag_var); + add_entity_use(c, lhs, tag_var); } check_stmt_list(c, cc->stmts, mod_flags); check_close_scope(c); diff --git a/src/checker.c b/src/checker.c index 09c97ceed..d991561ce 100644 --- a/src/checker.c +++ b/src/checker.c @@ -630,11 +630,12 @@ void init_universal_scope(BuildContext *bc) { } - t_u8_ptr = make_type_pointer(a, t_u8); - t_int_ptr = make_type_pointer(a, t_int); - t_i64_ptr = make_type_pointer(a, t_i64); - t_f64_ptr = make_type_pointer(a, t_f64); - t_byte_slice = make_type_slice(a, t_byte); + t_u8_ptr = make_type_pointer(a, t_u8); + t_int_ptr = make_type_pointer(a, t_int); + t_i64_ptr = make_type_pointer(a, t_i64); + t_f64_ptr = make_type_pointer(a, t_f64); + t_byte_slice = make_type_slice(a, t_byte); + t_string_slice = make_type_slice(a, t_string); } @@ -911,11 +912,6 @@ void add_type_info_type(Checker *c, Type *t) { } } break; - case Type_Maybe: - add_type_info_type(c, bt->Maybe.elem); - add_type_info_type(c, t_bool); - break; - case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break; @@ -1099,48 +1095,46 @@ void init_preload(Checker *c) { - if (record->field_count != 20) { + if (record->field_count != 19) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->fields[ 1]->type; t_type_info_integer = record->fields[ 2]->type; t_type_info_float = record->fields[ 3]->type; - t_type_info_any = record->fields[ 4]->type; - t_type_info_string = record->fields[ 5]->type; - t_type_info_boolean = record->fields[ 6]->type; + t_type_info_string = record->fields[ 4]->type; + t_type_info_boolean = record->fields[ 5]->type; + t_type_info_any = record->fields[ 6]->type; t_type_info_pointer = record->fields[ 7]->type; - t_type_info_maybe = record->fields[ 8]->type; - t_type_info_procedure = record->fields[ 9]->type; - t_type_info_array = record->fields[10]->type; - t_type_info_dynamic_array = record->fields[11]->type; - t_type_info_slice = record->fields[12]->type; - t_type_info_vector = record->fields[13]->type; - t_type_info_tuple = record->fields[14]->type; - t_type_info_struct = record->fields[15]->type; - t_type_info_union = record->fields[16]->type; - t_type_info_raw_union = record->fields[17]->type; - t_type_info_enum = record->fields[18]->type; - t_type_info_map = record->fields[19]->type; - - t_type_info_named_ptr = make_type_pointer(heap_allocator(), t_type_info_named); - t_type_info_integer_ptr = make_type_pointer(heap_allocator(), t_type_info_integer); - t_type_info_float_ptr = make_type_pointer(heap_allocator(), t_type_info_float); - t_type_info_any_ptr = make_type_pointer(heap_allocator(), t_type_info_any); - t_type_info_string_ptr = make_type_pointer(heap_allocator(), t_type_info_string); - t_type_info_boolean_ptr = make_type_pointer(heap_allocator(), t_type_info_boolean); - t_type_info_pointer_ptr = make_type_pointer(heap_allocator(), t_type_info_pointer); - t_type_info_maybe_ptr = make_type_pointer(heap_allocator(), t_type_info_maybe); - t_type_info_procedure_ptr = make_type_pointer(heap_allocator(), t_type_info_procedure); - t_type_info_array_ptr = make_type_pointer(heap_allocator(), t_type_info_array); - t_type_info_dynamic_array_ptr = make_type_pointer(heap_allocator(), t_type_info_dynamic_array); - t_type_info_slice_ptr = make_type_pointer(heap_allocator(), t_type_info_slice); - t_type_info_vector_ptr = make_type_pointer(heap_allocator(), t_type_info_vector); - t_type_info_tuple_ptr = make_type_pointer(heap_allocator(), t_type_info_tuple); - t_type_info_struct_ptr = make_type_pointer(heap_allocator(), t_type_info_struct); - t_type_info_union_ptr = make_type_pointer(heap_allocator(), t_type_info_union); - t_type_info_raw_union_ptr = make_type_pointer(heap_allocator(), t_type_info_raw_union); - t_type_info_enum_ptr = make_type_pointer(heap_allocator(), t_type_info_enum); - t_type_info_map_ptr = make_type_pointer(heap_allocator(), t_type_info_map); + t_type_info_procedure = record->fields[ 8]->type; + t_type_info_array = record->fields[ 9]->type; + t_type_info_dynamic_array = record->fields[10]->type; + t_type_info_slice = record->fields[11]->type; + t_type_info_vector = record->fields[12]->type; + t_type_info_tuple = record->fields[13]->type; + t_type_info_struct = record->fields[14]->type; + t_type_info_union = record->fields[15]->type; + t_type_info_raw_union = record->fields[16]->type; + t_type_info_enum = record->fields[17]->type; + t_type_info_map = record->fields[18]->type; + + t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named); + t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer); + t_type_info_float_ptr = make_type_pointer(c->allocator, t_type_info_float); + t_type_info_string_ptr = make_type_pointer(c->allocator, t_type_info_string); + t_type_info_boolean_ptr = make_type_pointer(c->allocator, t_type_info_boolean); + t_type_info_any_ptr = make_type_pointer(c->allocator, t_type_info_any); + t_type_info_pointer_ptr = make_type_pointer(c->allocator, t_type_info_pointer); + t_type_info_procedure_ptr = make_type_pointer(c->allocator, t_type_info_procedure); + t_type_info_array_ptr = make_type_pointer(c->allocator, t_type_info_array); + t_type_info_dynamic_array_ptr = make_type_pointer(c->allocator, t_type_info_dynamic_array); + t_type_info_slice_ptr = make_type_pointer(c->allocator, t_type_info_slice); + t_type_info_vector_ptr = make_type_pointer(c->allocator, t_type_info_vector); + t_type_info_tuple_ptr = make_type_pointer(c->allocator, t_type_info_tuple); + t_type_info_struct_ptr = make_type_pointer(c->allocator, t_type_info_struct); + t_type_info_union_ptr = make_type_pointer(c->allocator, t_type_info_union); + t_type_info_raw_union_ptr = make_type_pointer(c->allocator, t_type_info_raw_union); + t_type_info_enum_ptr = make_type_pointer(c->allocator, t_type_info_enum); + t_type_info_map_ptr = make_type_pointer(c->allocator, t_type_info_map); } if (t_allocator == NULL) { @@ -1727,6 +1721,19 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { file_str = import_file; } + if (fl->cond != NULL) { + Operand operand = {Addressing_Invalid}; + check_expr(c, &operand, fl->cond); + if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) { + error_node(fl->cond, "Non-constant boolean `when` condition"); + continue; + } + if (operand.value.kind == ExactValue_Bool && + !operand.value.value_bool) { + continue; + } + } + String library_name = path_to_entity_name(fl->library_name.string, file_str); if (str_eq(library_name, str_lit("_"))) { error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string)); diff --git a/src/entity.c b/src/entity.c index 221ec91b6..37c79b488 100644 --- a/src/entity.c +++ b/src/entity.c @@ -37,6 +37,7 @@ typedef enum EntityFlag { EntityFlag_VectorElem = 1<<5, EntityFlag_Ellipsis = 1<<6, EntityFlag_NoAlias = 1<<7, + EntityFlag_EnumField = 1<<8, } EntityFlag; typedef enum OverloadKind { @@ -1788,11 +1788,6 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { case 0: result_type = make_type_pointer(a, t_type_info_ptr); break; case 1: result_type = make_type_pointer(a, t_rawptr); break; } - } else if (is_type_maybe(t)) { - switch (index) { - case 0: result_type = make_type_pointer(a, t->Maybe.elem); break; - case 1: result_type = make_type_pointer(a, t_bool); break; - } } else if (is_type_dynamic_array(t)) { switch (index) { case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->DynamicArray.elem)); break; @@ -1848,11 +1843,6 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { case 0: result_type = t_type_info_ptr; break; case 1: result_type = t_rawptr; break; } - } else if (is_type_maybe(t)) { - switch (index) { - case 0: result_type = t->Maybe.elem; break; - case 1: result_type = t_bool; break; - } } else if (is_type_dynamic_array(t)) { switch (index) { case 0: result_type = make_type_pointer(a, t->DynamicArray.elem); break; @@ -2165,15 +2155,6 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { return value; } - if (is_type_maybe(dst)) { - irValue *maybe = ir_add_local_generated(proc, dst); - irValue *val = ir_emit_struct_ep(proc, maybe, 0); - irValue *set = ir_emit_struct_ep(proc, maybe, 1); - ir_emit_store(proc, val, value); - ir_emit_store(proc, set, v_true); - return ir_emit_load(proc, maybe); - } - // integer -> integer if (is_type_integer(src) && is_type_integer(dst)) { GB_ASSERT(src->kind == Type_Basic && @@ -2396,7 +2377,6 @@ bool ir_is_type_aggregate(Type *t) { case Type_Array: case Type_Slice: - case Type_Maybe: case Type_Record: case Type_Tuple: return true; @@ -3130,22 +3110,33 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv args[1] = ptr; return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2); } else if (is_type_dynamic_map(type)) { - // irValue *val = ir_build_expr(proc, node); - // irValue *map_ptr = ir_address_from_load_or_generate_local(proc, val); - - // { - // irValue *array = ir_emit_conv(proc, ir_emit_struct_ep(proc, map_ptr, 0), t_raw_dynamic_array_ptr); - // irValue **args = gb_alloc_array(a, irValue *, 1); - // args[0] = array; - // ir_emit_global_call(proc, "__free_raw_dynamic_array", args, 1); - // } - // { - // irValue *array = ir_emit_conv(proc, ir_emit_struct_ep(proc, map_ptr, 1), t_raw_dynamic_array_ptr); - // irValue **args = gb_alloc_array(a, irValue *, 1); - // args[0] = array; - // ir_emit_global_call(proc, "__free_raw_dynamic_array", args, 1); - // } + irValue *map = ir_build_expr(proc, node); + irValue *map_ptr = ir_address_from_load_or_generate_local(proc, map); + + { + irValue *array = ir_emit_struct_ep(proc, map_ptr, 0); + irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3)); + irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0)); + da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = da_allocator; + args[1] = da_ptr; + ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2); + } + { + irValue *array = ir_emit_struct_ep(proc, map_ptr, 1); + + irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3)); + irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0)); + da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr); + + irValue **args = gb_alloc_array(a, irValue *, 1); + args[0] = da_allocator; + args[1] = da_ptr; + ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2); + } return NULL; } @@ -3176,7 +3167,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv ir_emit_comment(proc, str_lit("reserve")); gbAllocator a = proc->module->allocator; - irValue *ptr = ir_build_expr(proc, ce->args.e[0]); + irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr; Type *type = ir_type(ptr); GB_ASSERT(is_type_pointer(type)); type = base_type(type_deref(type)); @@ -3208,8 +3199,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv } break; case BuiltinProc_clear: { - ir_emit_comment(proc, str_lit("reserve")); - irValue *ptr = ir_build_expr(proc, ce->args.e[0]); + ir_emit_comment(proc, str_lit("clear")); + irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr; Type *t = base_type(type_deref(ir_type(ptr))); if (is_type_dynamic_array(t)) { irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); @@ -3229,7 +3220,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv ir_emit_comment(proc, str_lit("append")); gbAllocator a = proc->module->allocator; - irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]); + irValue *array_ptr = ir_build_addr(proc, ce->args.e[0]).addr; Type *type = ir_type(array_ptr); GB_ASSERT(is_type_pointer(type)); type = base_type(type_deref(type)); @@ -3348,7 +3339,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv ir_emit_jump(proc, done); ir_start_block(proc, done); - return NULL; + return cond; } break; case BuiltinProc_panic: { @@ -3596,10 +3587,6 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv return ir_emit_call(proc, value, args, arg_count); case_end; - case_ast_node(de, DemaybeExpr, expr); - return ir_addr_load(proc, ir_build_addr(proc, expr)); - case_end; - case_ast_node(se, SliceExpr, expr); return ir_addr_load(proc, ir_build_addr(proc, expr)); case_end; @@ -3722,7 +3709,34 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { AstNode *sel = unparen_expr(se->selector); if (sel->kind == AstNode_Ident) { String selector = sel->Ident.string; - Type *type = base_type(type_of_expr(proc->module->info, se->expr)); + Type *type = type_of_expr(proc->module->info, se->expr); + + if (is_type_enum(type)) { + Selection sel = lookup_field(proc->module->allocator, type, selector, true); + Entity *e = sel.entity; + GB_ASSERT(e->kind == Entity_Variable); + i32 index = e->Variable.field_index; + switch (index) { + case 0: { + irValue *ti_ptr = ir_type_info(proc, type); + { + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1); + args[0] = ti_ptr; + ti_ptr = ir_emit_global_call(proc, "type_info_base", args, 1); + } + + + irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); + irValue *names_ptr = ir_emit_struct_ep(proc, enum_info, 1); + return ir_make_addr(names_ptr); + } break; + default: + GB_PANIC("Unhandled enum index %d %.*s", index, LIT(selector)); + break; + } + } + + type = base_type(type); if (type == t_invalid) { // NOTE(bill): Imports @@ -4056,18 +4070,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { return ir_make_addr(addr); case_end; - case_ast_node(de, DemaybeExpr, expr); - ir_emit_comment(proc, str_lit("DemaybeExpr")); - irValue *maybe = ir_build_expr(proc, de->expr); - Type *t = default_type(type_of_expr(proc->module->info, expr)); - GB_ASSERT(is_type_tuple(t)); - - irValue *result = ir_add_local_generated(proc, t); - ir_emit_store(proc, result, maybe); - - return ir_make_addr(result); - case_end; - case_ast_node(ce, CallExpr, expr); // NOTE(bill): This is make sure you never need to have an `array_ev` irValue *e = ir_build_expr(proc, expr); @@ -5253,7 +5255,13 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ir_emit_comment(proc, str_lit("TypeMatchStmt")); gbAllocator allocator = proc->module->allocator; - irValue *parent = ir_build_expr(proc, ms->tag); + ast_node(as, AssignStmt, ms->tag); + GB_ASSERT(as->lhs.count == 1); + GB_ASSERT(as->rhs.count == 1); + AstNode *lhs = as->lhs.e[0]; + AstNode *rhs = as->rhs.e[0]; + + irValue *parent = ir_build_expr(proc, rhs); bool is_union_ptr = false; bool is_any = false; GB_ASSERT(check_valid_type_match_type(ir_type(parent), &is_union_ptr, &is_any)); @@ -5274,7 +5282,8 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ast_node(body, BlockStmt, ms->body); - String tag_var_name = ms->var->Ident.string; + String tag_var_name = lhs->Ident.string; + AstNodeArray default_stmts = {0}; irBlock *default_block = NULL; @@ -5291,19 +5300,32 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { default_block = ir_new_block(proc, clause, "type-match.dflt.body"); continue; } + GB_ASSERT(cc->list.count == 1); irBlock *body = ir_new_block(proc, clause, "type-match.case.body"); - Scope *scope = *map_scope_get(&proc->module->info->scopes, hash_pointer(clause)); - Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name); - GB_ASSERT_MSG(tag_var_entity != NULL, "%.*s", LIT(tag_var_name)); + Entity *tag_var_entity = NULL; + Type *tag_var_type = NULL; + if (str_eq(tag_var_name, str_lit("_"))) { + Type *t = type_of_expr(proc->module->info, cc->list.e[0]); + if (is_union_ptr) { + t = make_type_pointer(proc->module->allocator, t); + } + tag_var_type = t; + } else { + Scope *scope = *map_scope_get(&proc->module->info->scopes, hash_pointer(clause)); + tag_var_entity = current_scope_lookup_entity(scope, tag_var_name); + GB_ASSERT_MSG(tag_var_entity != NULL, "%.*s", LIT(tag_var_name)); + tag_var_type = tag_var_entity->type; + } + GB_ASSERT(tag_var_type != NULL); irBlock *next_cond = NULL; irValue *cond = NULL; if (is_union_ptr) { - Type *bt = type_deref(tag_var_entity->type); + Type *bt = type_deref(tag_var_type); irValue *index = NULL; Type *ut = base_type(type_deref(ir_type(parent))); GB_ASSERT(ut->Record.kind == TypeRecord_Union); @@ -5316,16 +5338,25 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { } GB_ASSERT(index != NULL); - irValue *tag_var = ir_add_local(proc, tag_var_entity); - irValue *data_ptr = ir_emit_conv(proc, union_data, tag_var_entity->type); + irValue *tag_var = NULL; + if (tag_var_entity != NULL) { + tag_var = ir_add_local(proc, tag_var_entity); + } else { + tag_var = ir_add_local_generated(proc, tag_var_type); + } + + + irValue *data_ptr = ir_emit_conv(proc, union_data, tag_var_type); ir_emit_store(proc, tag_var, data_ptr); cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index); } else if (is_any) { - Type *type = tag_var_entity->type; + Type *type = tag_var_type; irValue *any_data = ir_emit_struct_ev(proc, parent, 1); irValue *data = ir_emit_conv(proc, any_data, make_type_pointer(proc->module->allocator, type)); - ir_module_add_value(proc->module, tag_var_entity, data); + if (tag_var_entity != NULL) { + ir_module_add_value(proc->module, tag_var_entity, data); + } irValue *any_ti = ir_emit_struct_ev(proc, parent, 0); irValue *case_ti = ir_type_info(proc, type); @@ -6228,11 +6259,6 @@ void ir_gen_tree(irGen *s) { irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Pointer.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); } break; - case Type_Maybe: { - tag = ir_emit_conv(proc, ti_ptr, t_type_info_maybe_ptr); - irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Maybe.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); - } break; case Type_Array: { tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr); irValue *gep = ir_get_type_info_ptr(proc, type_info_data, t->Array.elem); diff --git a/src/ir_print.c b/src/ir_print.c index 670db48cd..da411fdc6 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -172,13 +172,6 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { ir_print_type(f, m, t->Pointer.elem); ir_fprintf(f, "*"); return; - case Type_Maybe: - ir_fprintf(f, "{"); - ir_print_type(f, m, t->Maybe.elem); - ir_fprintf(f, ", "); - ir_print_type(f, m, t_bool); - ir_fprintf(f, "}"); - return; case Type_Array: ir_fprintf(f, "[%lld x ", t->Array.count); ir_print_type(f, m, t->Array.elem); @@ -306,25 +299,11 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type ir_print_type(f, m, elem_type); ir_fprintf(f, " "); - if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) { - Type *t = base_type(elem_type)->Maybe.elem; - ir_fprintf(f, "{"); - ir_print_type(f, m, t); - ir_fprintf(f, " "); - } - if (v.kind == ExactValue_Invalid || base_type(elem_type) == t_any) { ir_fprintf(f, "zeroinitializer"); } else { ir_print_exact_value(f, m, v, elem_type); } - - if (v.kind != ExactValue_Invalid && is_type_maybe(elem_type)) { - ir_fprintf(f, ", "); - ir_print_type(f, m, t_bool); - ir_fprintf(f, " "); - ir_fprintf(f, "true}"); - } } void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) { diff --git a/src/parser.c b/src/parser.c index 079e39c2f..3179509e7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -147,7 +147,6 @@ AST_NODE_KIND(_ExprBegin, "", i32) \ AST_NODE_KIND(SelectorExpr, "selector expression", struct { Token token; AstNode *expr, *selector; }) \ AST_NODE_KIND(IndexExpr, "index expression", struct { AstNode *expr, *index; Token open, close; }) \ AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \ - AST_NODE_KIND(DemaybeExpr, "demaybe expression", struct { Token op; AstNode *expr; }) \ AST_NODE_KIND(SliceExpr, "slice expression", struct { \ AstNode *expr; \ Token open, close, interval; \ @@ -251,7 +250,6 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \ AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \ Token token; \ AstNode *tag; \ - AstNode *var; \ AstNode *body; \ }) \ AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \ @@ -333,10 +331,6 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ Token token; \ AstNode *type; \ }) \ - AST_NODE_KIND(MaybeType, "maybe type", struct { \ - Token token; \ - AstNode *type; \ - }) \ AST_NODE_KIND(ArrayType, "array type", struct { \ Token token; \ AstNode *count; \ @@ -469,7 +463,6 @@ Token ast_node_token(AstNode *node) { case AstNode_CastExpr: return node->CastExpr.token; case AstNode_FieldValue: return node->FieldValue.eq; case AstNode_DerefExpr: return node->DerefExpr.op; - case AstNode_DemaybeExpr: return node->DemaybeExpr.op; case AstNode_BlockExpr: return node->BlockExpr.open; case AstNode_GiveExpr: return node->GiveExpr.token; case AstNode_IfExpr: return node->IfExpr.token; @@ -513,7 +506,6 @@ Token ast_node_token(AstNode *node) { case AstNode_HelperType: return node->HelperType.token; case AstNode_ProcType: return node->ProcType.token; case AstNode_PointerType: return node->PointerType.token; - case AstNode_MaybeType: return node->MaybeType.token; case AstNode_ArrayType: return node->ArrayType.token; case AstNode_DynamicArrayType: return node->DynamicArrayType.token; case AstNode_VectorType: return node->VectorType.token; @@ -693,13 +685,6 @@ AstNode *ast_deref_expr(AstFile *f, AstNode *expr, Token op) { return result; } -AstNode *ast_demaybe_expr(AstFile *f, AstNode *expr, Token op) { - AstNode *result = make_ast_node(f, AstNode_DemaybeExpr); - result->DemaybeExpr.expr = expr; - result->DemaybeExpr.op = op; - return result; -} - AstNode *ast_interval_expr(AstFile *f, Token op, AstNode *left, AstNode *right) { AstNode *result = make_ast_node(f, AstNode_IntervalExpr); @@ -907,11 +892,10 @@ AstNode *ast_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, As } -AstNode *ast_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *var, AstNode *body) { +AstNode *ast_type_match_stmt(AstFile *f, Token token, AstNode *tag, AstNode *body) { AstNode *result = make_ast_node(f, AstNode_TypeMatchStmt); result->TypeMatchStmt.token = token; result->TypeMatchStmt.tag = tag; - result->TypeMatchStmt.var = var; result->TypeMatchStmt.body = body; return result; } @@ -1031,13 +1015,6 @@ AstNode *ast_pointer_type(AstFile *f, Token token, AstNode *type) { return result; } -AstNode *ast_maybe_type(AstFile *f, Token token, AstNode *type) { - AstNode *result = make_ast_node(f, AstNode_MaybeType); - result->MaybeType.token = token; - result->MaybeType.type = type; - return result; -} - AstNode *ast_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem) { AstNode *result = make_ast_node(f, AstNode_ArrayType); result->ArrayType.token = token; @@ -1777,6 +1754,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { } else if (str_eq(name.string, str_lit("file"))) { return ast_basic_directive(f, token, name.string); } else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string); } else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string); + } else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f)); } else { operand = ast_tag_expr(f, token, name, parse_expr(f, false)); } @@ -1999,10 +1977,6 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { operand = ast_deref_expr(f, operand, expect_token(f, Token_Pointer)); break; - case Token_Maybe: // Demaybe - operand = ast_demaybe_expr(f, operand, expect_token(f, Token_Maybe)); - break; - case Token_OpenBrace: if (!lhs && is_literal_type(operand) && f->expr_level >= 0) { operand = parse_literal_value(f, operand); @@ -2205,9 +2179,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) { bool is_mutable = true; if (allow_token(f, Token_Colon)) { - if (!allow_token(f, Token_type)) { - type = parse_type_attempt(f); - } + type = parse_type_attempt(f); } else if (f->curr_token.kind != Token_Eq && f->curr_token.kind != Token_Semicolon) { syntax_error(f->curr_token, "Expected a type separator `:` or `=`"); @@ -2553,10 +2525,16 @@ AstNode *parse_type_or_ident(AstFile *f) { return e; } - case Token_type: { - Token token = expect_token(f, Token_type); - AstNode *type = parse_type(f); - return ast_helper_type(f, token, type); + case Token_Hash: { + Token hash_token = expect_token(f, Token_Hash); + Token name = expect_token(f, Token_Ident); + String tag = name.string; + if (str_eq(tag, str_lit("type"))) { + AstNode *type = parse_type(f); + return ast_helper_type(f, hash_token, type); + } + syntax_error(name, "Expected `type` after #"); + return ast_bad_expr(f, hash_token, f->curr_token); } case Token_Pointer: { @@ -2565,12 +2543,6 @@ AstNode *parse_type_or_ident(AstFile *f) { return ast_pointer_type(f, token, elem); } - case Token_Maybe: { - Token token = expect_token(f, Token_Maybe); - AstNode *elem = parse_type(f); - return ast_maybe_type(f, token, elem); - } - case Token_OpenBracket: { Token token = expect_token(f, Token_OpenBracket); AstNode *count_expr = NULL; @@ -2972,8 +2944,7 @@ AstNode *parse_for_stmt(AstFile *f) { f->expr_level = -1; if (f->curr_token.kind != Token_Semicolon) { cond = parse_simple_stmt(f, true); - if (cond->kind == AstNode_AssignStmt && - cond->AssignStmt.op.kind == Token_in) { + if (cond->kind == AstNode_AssignStmt && cond->AssignStmt.op.kind == Token_in) { is_range = true; } } @@ -3065,6 +3036,7 @@ AstNode *parse_for_stmt(AstFile *f) { #endif } + AstNode *parse_case_clause(AstFile *f) { Token token = f->curr_token; AstNodeArray list = make_ast_node_array(f); @@ -3097,6 +3069,7 @@ AstNode *parse_type_case_clause(AstFile *f) { } + AstNode *parse_match_stmt(AstFile *f) { if (f->curr_proc == NULL) { syntax_error(f->curr_token, "You cannot use a match statement in the file scope"); @@ -3108,37 +3081,16 @@ AstNode *parse_match_stmt(AstFile *f) { AstNode *tag = NULL; AstNode *body = NULL; Token open, close; + bool is_type_match = false; - if (allow_token(f, Token_type)) { + if (f->curr_token.kind != Token_OpenBrace) { isize prev_level = f->expr_level; f->expr_level = -1; - AstNode *var = parse_ident(f); - expect_token_after(f, Token_in, "match type name"); - tag = parse_simple_stmt(f, false); - - f->expr_level = prev_level; - - open = expect_token(f, Token_OpenBrace); - AstNodeArray list = make_ast_node_array(f); - - while (f->curr_token.kind == Token_case || - f->curr_token.kind == Token_default) { - array_add(&list, parse_type_case_clause(f)); - } - - close = expect_token(f, Token_CloseBrace); - body = ast_block_stmt(f, list, open, close); - - tag = convert_stmt_to_expr(f, tag, str_lit("type match expression")); - return ast_type_match_stmt(f, token, tag, var, body); - } else { - if (f->curr_token.kind != Token_OpenBrace) { - isize prev_level = f->expr_level; - f->expr_level = -1; - if (f->curr_token.kind != Token_Semicolon) { - tag = parse_simple_stmt(f, false); - } + tag = parse_simple_stmt(f, true); + if (tag->kind == AstNode_AssignStmt && tag->AssignStmt.op.kind == Token_in) { + is_type_match = true; + } else { if (allow_token(f, Token_Semicolon)) { init = tag; tag = NULL; @@ -3146,28 +3098,33 @@ AstNode *parse_match_stmt(AstFile *f) { tag = parse_simple_stmt(f, false); } } - - f->expr_level = prev_level; } + f->expr_level = prev_level; + } + open = expect_token(f, Token_OpenBrace); + AstNodeArray list = make_ast_node_array(f); - open = expect_token(f, Token_OpenBrace); - AstNodeArray list = make_ast_node_array(f); - - while (f->curr_token.kind == Token_case || - f->curr_token.kind == Token_default) { + while (f->curr_token.kind == Token_case || + f->curr_token.kind == Token_default) { + if (is_type_match) { + array_add(&list, parse_type_case_clause(f)); + } else { array_add(&list, parse_case_clause(f)); } + } - close = expect_token(f, Token_CloseBrace); + close = expect_token(f, Token_CloseBrace); - body = ast_block_stmt(f, list, open, close); + body = ast_block_stmt(f, list, open, close); + if (!is_type_match) { tag = convert_stmt_to_expr(f, tag, str_lit("match expression")); return ast_match_stmt(f, token, init, tag, body); + } else { + return ast_type_match_stmt(f, token, tag, body); } } - AstNode *parse_defer_stmt(AstFile *f) { if (f->curr_proc == NULL) { syntax_error(f->curr_token, "You cannot use a defer statement in the file scope"); @@ -3359,6 +3316,7 @@ AstNode *parse_stmt(AstFile *f) { Token hash_token = expect_token(f, Token_Hash); Token name = expect_token(f, Token_Ident); String tag = name.string; + if (str_eq(tag, str_lit("import"))) { AstNode *cond = NULL; Token import_name = {0}; diff --git a/src/tokenizer.c b/src/tokenizer.c index 9dacdba64..92256f021 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -12,23 +12,24 @@ TOKEN_KIND(Token__LiteralBegin, "_LiteralBegin"), \ TOKEN_KIND(Token__LiteralEnd, "_LiteralEnd"), \ \ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ - TOKEN_KIND(Token_Eq, "="), \ - TOKEN_KIND(Token_Not, "!"), \ - TOKEN_KIND(Token_Hash, "#"), \ - TOKEN_KIND(Token_At, "@"), \ - TOKEN_KIND(Token_Pointer, "^"), \ - TOKEN_KIND(Token_Maybe, "?"), \ - TOKEN_KIND(Token_Add, "+"), \ - TOKEN_KIND(Token_Sub, "-"), \ - TOKEN_KIND(Token_Mul, "*"), \ - TOKEN_KIND(Token_Quo, "/"), \ - TOKEN_KIND(Token_Mod, "%"), \ - TOKEN_KIND(Token_And, "&"), \ - TOKEN_KIND(Token_Or, "|"), \ - TOKEN_KIND(Token_Xor, "~"), \ - TOKEN_KIND(Token_AndNot, "&~"), \ - TOKEN_KIND(Token_Shl, "<<"), \ - TOKEN_KIND(Token_Shr, ">>"), \ + TOKEN_KIND(Token_Eq, "="), \ + TOKEN_KIND(Token_Not, "!"), \ + TOKEN_KIND(Token_Hash, "#"), \ + TOKEN_KIND(Token_At, "@"), \ + TOKEN_KIND(Token_Dollar, "$"), \ + TOKEN_KIND(Token_Pointer, "^"), \ + TOKEN_KIND(Token_Question, "?"), \ + TOKEN_KIND(Token_Add, "+"), \ + TOKEN_KIND(Token_Sub, "-"), \ + TOKEN_KIND(Token_Mul, "*"), \ + TOKEN_KIND(Token_Quo, "/"), \ + TOKEN_KIND(Token_Mod, "%"), \ + TOKEN_KIND(Token_And, "&"), \ + TOKEN_KIND(Token_Or, "|"), \ + TOKEN_KIND(Token_Xor, "~"), \ + TOKEN_KIND(Token_AndNot, "&~"), \ + TOKEN_KIND(Token_Shl, "<<"), \ + TOKEN_KIND(Token_Shr, ">>"), \ \ /*TOKEN_KIND(Token_as, "as"), */\ /*TOKEN_KIND(Token_transmute, "transmute"), */\ @@ -55,6 +56,8 @@ TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ TOKEN_KIND(Token_ArrowRight, "->"), \ TOKEN_KIND(Token_ArrowLeft, "<-"), \ + TOKEN_KIND(Token_Increment, "++"), \ + TOKEN_KIND(Token_Decrement, "--"), \ \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token_CmpEq, "=="), \ @@ -80,45 +83,45 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \ \ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ - /* TODO(bill): So of these keywords are not used but "reserved", why not remove them? */ \ - TOKEN_KIND(Token_when, "when"), \ - TOKEN_KIND(Token_if, "if"), \ - TOKEN_KIND(Token_else, "else"), \ - TOKEN_KIND(Token_for, "for"), \ - TOKEN_KIND(Token_in, "in"), \ - TOKEN_KIND(Token_break, "break"), \ - TOKEN_KIND(Token_continue, "continue"), \ - TOKEN_KIND(Token_fallthrough, "fallthrough"), \ - TOKEN_KIND(Token_match, "match"), \ - TOKEN_KIND(Token_type, "type"), \ - TOKEN_KIND(Token_default, "default"), \ - TOKEN_KIND(Token_case, "case"), \ - TOKEN_KIND(Token_defer, "defer"), \ - TOKEN_KIND(Token_return, "return"), \ - TOKEN_KIND(Token_give, "give"), \ - TOKEN_KIND(Token_proc, "proc"), \ - TOKEN_KIND(Token_macro, "macro"), \ - TOKEN_KIND(Token_struct, "struct"), \ - TOKEN_KIND(Token_union, "union"), \ - TOKEN_KIND(Token_raw_union, "raw_union"), \ - TOKEN_KIND(Token_enum, "enum"), \ - TOKEN_KIND(Token_vector, "vector"), \ - TOKEN_KIND(Token_map, "map"), \ - TOKEN_KIND(Token_static, "static"), \ - TOKEN_KIND(Token_dynamic, "dynamic"), \ - TOKEN_KIND(Token_using, "using"), \ - TOKEN_KIND(Token_no_alias, "no_alias"), \ - /* TOKEN_KIND(Token_mutable, "mutable"), */\ + /* TODO(bill): Of these keywords are not used but "reserved", why not remove them? */ \ + TOKEN_KIND(Token_when, "when"), \ + TOKEN_KIND(Token_if, "if"), \ + TOKEN_KIND(Token_else, "else"), \ + TOKEN_KIND(Token_for, "for"), \ + TOKEN_KIND(Token_in, "in"), \ + TOKEN_KIND(Token_break, "break"), \ + TOKEN_KIND(Token_continue, "continue"), \ + TOKEN_KIND(Token_fallthrough, "fallthrough"), \ + TOKEN_KIND(Token_match, "match"), \ + /* TOKEN_KIND(Token_type, "type"), */ \ + TOKEN_KIND(Token_default, "default"), \ + TOKEN_KIND(Token_case, "case"), \ + TOKEN_KIND(Token_defer, "defer"), \ + TOKEN_KIND(Token_return, "return"), \ + TOKEN_KIND(Token_give, "give"), \ + TOKEN_KIND(Token_proc, "proc"), \ + TOKEN_KIND(Token_macro, "macro"), \ + TOKEN_KIND(Token_struct, "struct"), \ + TOKEN_KIND(Token_union, "union"), \ + TOKEN_KIND(Token_raw_union, "raw_union"), \ + TOKEN_KIND(Token_enum, "enum"), \ + TOKEN_KIND(Token_vector, "vector"), \ + TOKEN_KIND(Token_map, "map"), \ + TOKEN_KIND(Token_static, "static"), \ + TOKEN_KIND(Token_dynamic, "dynamic"), \ + TOKEN_KIND(Token_using, "using"), \ + TOKEN_KIND(Token_no_alias, "no_alias"), \ + /* TOKEN_KIND(Token_mutable, "mutable"), */ \ /* TOKEN_KIND(Token_immutable, "immutable"), */\ - TOKEN_KIND(Token_thread_local, "thread_local"), \ - TOKEN_KIND(Token_cast, "cast"), \ - TOKEN_KIND(Token_transmute, "transmute"), \ - TOKEN_KIND(Token_down_cast, "down_cast"), \ - TOKEN_KIND(Token_union_cast, "union_cast"), \ - TOKEN_KIND(Token_context, "context"), \ - TOKEN_KIND(Token_push_context, "push_context"), \ - TOKEN_KIND(Token_push_allocator, "push_allocator"), \ - TOKEN_KIND(Token_asm, "asm"), \ + TOKEN_KIND(Token_thread_local, "thread_local"), \ + TOKEN_KIND(Token_cast, "cast"), \ + TOKEN_KIND(Token_transmute, "transmute"), \ + TOKEN_KIND(Token_down_cast, "down_cast"), \ + TOKEN_KIND(Token_union_cast, "union_cast"), \ + TOKEN_KIND(Token_context, "context"), \ + TOKEN_KIND(Token_push_context, "push_context"), \ + TOKEN_KIND(Token_push_allocator, "push_allocator"), \ + TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token_Count, "") @@ -478,7 +481,6 @@ gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) { } } - Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) { Token token = {0}; token.kind = Token_Integer; @@ -734,20 +736,10 @@ Token tokenizer_get_token(Tokenizer *t) { // NOTE(bill): All keywords are > 1 if (token.string.len > 1) { - /* if (str_eq(token.string, token_strings[Token_as])) { - token.kind = Token_as; - } else if (str_eq(token.string, token_strings[Token_transmute])) { - token.kind = Token_transmute; - } else if (str_eq(token.string, token_strings[Token_down_cast])) { - token.kind = Token_down_cast; - } else if (str_eq(token.string, token_strings[Token_union_cast])) { - token.kind = Token_union_cast; - } else */{ - for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { - if (str_eq(token.string, token_strings[k])) { - token.kind = cast(TokenKind)k; - break; - } + for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) { + if (str_eq(token.string, token_strings[k])) { + token.kind = cast(TokenKind)k; + break; } } } @@ -861,57 +853,28 @@ Token tokenizer_get_token(Tokenizer *t) { } break; - case '#': - token.kind = Token_Hash; - break; - case '@': - token.kind = Token_At; - break; - case '^': - token.kind = Token_Pointer; - break; - case '?': - token.kind = Token_Maybe; - break; - case ';': - token.kind = Token_Semicolon; - break; - case ',': - token.kind = Token_Comma; - break; - case ':': - token.kind = Token_Colon; - break; - case '(': - token.kind = Token_OpenParen; - break; - case ')': - token.kind = Token_CloseParen; - break; - case '[': - token.kind = Token_OpenBracket; - break; - case ']': - token.kind = Token_CloseBracket; - break; - case '{': - token.kind = Token_OpenBrace; - break; - case '}': - token.kind = Token_CloseBrace; - break; - - case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; - case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; - case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; - case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; - case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; - case '+': - token.kind = token_kind_variant2(t, Token_Add, Token_AddEq); - break; - case '-': - token.kind = token_kind_variant3(t, Token_Sub, Token_SubEq, '>', Token_ArrowRight); - break; + case '#': token.kind = Token_Hash; break; + case '@': token.kind = Token_At; break; + case '$': token.kind = Token_Dollar; break; + case '?': token.kind = Token_Question; break; + case '^': token.kind = Token_Pointer; break; + case ';': token.kind = Token_Semicolon; break; + case ',': token.kind = Token_Comma; break; + case ':': token.kind = Token_Colon; break; + case '(': token.kind = Token_OpenParen; break; + case ')': token.kind = Token_CloseParen; break; + case '[': token.kind = Token_OpenBracket; break; + case ']': token.kind = Token_CloseBracket; break; + case '{': token.kind = Token_OpenBrace; break; + case '}': token.kind = Token_CloseBrace; break; + + case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; + case '%': token.kind = token_kind_variant2(t, Token_Mod, Token_ModEq); break; + case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; + case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; + case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; + case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Increment); break; + case '-': token.kind = token_kind_variant4(t, Token_Sub, Token_SubEq, '-', Token_Decrement, '>', Token_ArrowRight); break; case '/': { if (t->curr_rune == '/') { while (t->curr_rune != '\n' && t->curr_rune != GB_RUNE_EOF) { @@ -951,9 +914,7 @@ Token tokenizer_get_token(Tokenizer *t) { token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); } break; - case '>': - token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); - break; + case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break; case '&': token.kind = Token_And; diff --git a/src/types.c b/src/types.c index dbded4a73..71888a372 100644 --- a/src/types.c +++ b/src/types.c @@ -11,6 +11,20 @@ typedef enum BasicKind { Basic_u32, Basic_i64, Basic_u64, + +/* Basic_i16le, + Basic_i16be, + Basic_u16le, + Basic_u16be, + Basic_i32le, + Basic_i32be, + Basic_u32le, + Basic_u32be, + Basic_i64le, + Basic_i64be, + Basic_u64le, + Basic_u64be, */ + // Basic_i128, // Basic_u128, // Basic_f16, @@ -93,6 +107,7 @@ typedef struct TypeRecord { Entity * enum_count; Entity * enum_min_value; Entity * enum_max_value; + Entity * enum_names; } TypeRecord; #define TYPE_KINDS \ @@ -102,7 +117,6 @@ typedef struct TypeRecord { TYPE_KIND(DynamicArray, struct { Type *elem; }) \ TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \ TYPE_KIND(Slice, struct { Type *elem; }) \ - TYPE_KIND(Maybe, struct { Type *elem; }) \ TYPE_KIND(Record, TypeRecord) \ TYPE_KIND(Named, struct { \ String name; \ @@ -177,16 +191,16 @@ typedef struct BaseTypeSizes { } BaseTypeSizes; -typedef Array(isize) Array_isize; +typedef Array(i32) Array_i32; typedef struct Selection { - Entity * entity; - Array_isize index; - bool indirect; // Set if there was a pointer deref anywhere down the line + Entity * entity; + Array_i32 index; + bool indirect; // Set if there was a pointer deref anywhere down the line } Selection; Selection empty_selection = {0}; -Selection make_selection(Entity *entity, Array_isize index, bool indirect) { +Selection make_selection(Entity *entity, Array_i32 index, bool indirect) { Selection s = {entity, index, indirect}; return s; } @@ -273,6 +287,7 @@ gb_global Type *t_int_ptr = NULL; gb_global Type *t_i64_ptr = NULL; gb_global Type *t_f64_ptr = NULL; gb_global Type *t_byte_slice = NULL; +gb_global Type *t_string_slice = NULL; gb_global Type *t_type_info = NULL; @@ -289,7 +304,6 @@ gb_global Type *t_type_info_any = NULL; gb_global Type *t_type_info_string = NULL; gb_global Type *t_type_info_boolean = NULL; gb_global Type *t_type_info_pointer = NULL; -gb_global Type *t_type_info_maybe = NULL; gb_global Type *t_type_info_procedure = NULL; gb_global Type *t_type_info_array = NULL; gb_global Type *t_type_info_dynamic_array = NULL; @@ -310,7 +324,6 @@ gb_global Type *t_type_info_any_ptr = NULL; gb_global Type *t_type_info_string_ptr = NULL; gb_global Type *t_type_info_boolean_ptr = NULL; gb_global Type *t_type_info_pointer_ptr = NULL; -gb_global Type *t_type_info_maybe_ptr = NULL; gb_global Type *t_type_info_procedure_ptr = NULL; gb_global Type *t_type_info_array_ptr = NULL; gb_global Type *t_type_info_dynamic_array_ptr = NULL; @@ -393,12 +406,6 @@ Type *make_type_pointer(gbAllocator a, Type *elem) { return t; } -Type *make_type_maybe(gbAllocator a, Type *elem) { - Type *t = alloc_type(a, Type_Maybe); - t->Maybe.elem = elem; - return t; -} - Type *make_type_array(gbAllocator a, Type *elem, i64 count) { Type *t = alloc_type(a, Type_Array); t->Array.elem = elem; @@ -630,10 +637,6 @@ bool is_type_pointer(Type *t) { } return t->kind == Type_Pointer; } -bool is_type_maybe(Type *t) { - t = base_type(t); - return t->kind == Type_Maybe; -} bool is_type_tuple(Type *t) { t = base_type(t); return t->kind == Type_Tuple; @@ -780,7 +783,6 @@ bool type_has_nil(Type *t) { case Type_DynamicArray: case Type_Proc: case Type_Pointer: - case Type_Maybe: return true; } return false; @@ -890,12 +892,6 @@ bool are_types_identical(Type *x, Type *y) { } break; - case Type_Maybe: - if (y->kind == Type_Maybe) { - return are_types_identical(x->Maybe.elem, y->Maybe.elem); - } - break; - case Type_Named: if (y->kind == Type_Named) { return x->Named.base == y->Named.base; @@ -981,9 +977,6 @@ bool is_type_cte_safe(Type *type) { case Type_Slice: return false; - case Type_Maybe: - return is_type_cte_safe(type->Maybe.elem); - case Type_Record: { if (type->Record.kind != TypeRecord_Struct) { return false; @@ -1026,12 +1019,14 @@ typedef enum ProcTypeOverloadKind { ProcOverload_ResultCount, ProcOverload_ResultTypes, + ProcOverload_NotProcedure, + } ProcTypeOverloadKind; ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { - GB_ASSERT(is_type_proc(x)); - GB_ASSERT(is_type_proc(y)); + if (!is_type_proc(x)) return ProcOverload_NotProcedure; + if (!is_type_proc(y)) return ProcOverload_NotProcedure; TypeProc *px = &base_type(x)->Proc; TypeProc *py = &base_type(y)->Proc; @@ -1113,7 +1108,7 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { Entity *f = type->Record.fields[i]; if (f->kind == Entity_Variable) { if (f->Variable.field_src_index == index) { - Array_isize sel_array = {0}; + Array_i32 sel_array = {0}; array_init_count(&sel_array, a, 1); sel_array.e[0] = i; return make_selection(f, sel_array, false); @@ -1125,7 +1120,7 @@ Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { for (isize i = 0; i < max_count; i++) { Entity *f = type->Tuple.variables[i]; if (i == index) { - Array_isize sel_array = {0}; + Array_i32 sel_array = {0}; array_init_count(&sel_array, a, 1); sel_array.e[0] = i; return make_selection(f, sel_array, false); @@ -1352,6 +1347,10 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n sel.entity = type->Record.enum_max_value; return sel; } + if (str_eq(field_name, str_lit("names"))) { + sel.entity = type->Record.enum_names; + return sel; + } } for (isize i = 0; i < type->Record.field_count; i++) { @@ -1558,17 +1557,6 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type return max; } break; - case Type_Maybe: { - Type *elem = t->Maybe.elem; - type_path_push(path, elem); - if (path->failure) { - return FAILURE_ALIGNMENT; - } - i64 align = gb_max(type_align_of_internal(s, allocator, t->Maybe.elem, path), type_align_of_internal(s, allocator, t_bool, path)); - type_path_pop(path); - return align; - } - case Type_Map: { if (t->Map.count == 0) { // Dynamic return type_align_of_internal(s, allocator, t->Map.generated_struct_type, path); @@ -1773,18 +1761,6 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP case Type_Slice: // ptr + count return 2 * s.word_size; - case Type_Maybe: { // value + bool - i64 align, size; - Type *elem = t->Maybe.elem; - align = type_align_of_internal(s, allocator, elem, path); - if (path->failure) { - return FAILURE_SIZE; - } - size = align_formula(type_size_of_internal(s, allocator, elem, path), align); - size += type_size_of_internal(s, allocator, t_bool, path); - return align_formula(size, align); - } - case Type_Map: { if (t->Map.count == 0) { // Dynamic return type_size_of_internal(s, allocator, t->Map.generated_struct_type, path); @@ -1969,11 +1945,6 @@ gbString write_type_to_string(gbString str, Type *type) { str = write_type_to_string(str, type->Pointer.elem); break; - case Type_Maybe: - str = gb_string_appendc(str, "?"); - str = write_type_to_string(str, type->Maybe.elem); - break; - case Type_Array: str = gb_string_appendc(str, gb_bprintf("[%lld]", type->Array.count)); str = write_type_to_string(str, type->Array.elem); |