diff --git a/examples/basic.odin b/examples/basic.odin index ced4df599..e3e6709d9 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -183,10 +183,10 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { u: uint = 0; if arg.data != null { match info.size { - case 1: u = (arg.data as ^u8)^ as uint - case 2: u = (arg.data as ^u16)^ as uint - case 4: u = (arg.data as ^u32)^ as uint - case 8: u = (arg.data as ^u64)^ as uint + case 1: u = (arg.data as ^u8)^ as uint + case 2: u = (arg.data as ^u16)^ as uint + case 4: u = (arg.data as ^u32)^ as uint + case 8: u = (arg.data as ^u64)^ as uint case 16: u = (arg.data as ^u128)^ as uint } } @@ -195,10 +195,10 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { v: int = 0; if arg.data != null { match info.size { - case 1: v = (arg.data as ^i8)^ as int - case 2: v = (arg.data as ^i16)^ as int - case 4: v = (arg.data as ^i32)^ as int - case 8: v = (arg.data as ^i64)^ as int + case 1: v = (arg.data as ^i8)^ as int + case 2: v = (arg.data as ^i16)^ as int + case 4: v = (arg.data as ^i32)^ as int + case 8: v = (arg.data as ^i64)^ as int case 16: v = (arg.data as ^i128)^ as int } } diff --git a/examples/demo.odin b/examples/demo.odin index 0e4c2b737..8fa141c3f 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -1,7 +1,5 @@ #load "basic.odin" -#load "math.odin" main :: proc() { - a: any = 1 println(137, "Hello", 1.25, true) } diff --git a/examples/game.odin b/examples/game.odin index 050db29fe..d55daf6a2 100644 --- a/examples/game.odin +++ b/examples/game.odin @@ -16,9 +16,7 @@ time_now :: proc() -> f64 { win32_print_last_error :: proc() { err_code := GetLastError() as int if err_code != 0 { - print_string("GetLastError: ") - print_int(err_code) - print_string("\n") + println("GetLastError:", err_code) } } @@ -46,7 +44,8 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W class_name := "Win32-Odin-Window\x00" c_class_name := ^class_name[0] - w.c_title = to_c_string(title) + // w.c_title = to_c_string(title) + w.c_title = "Title\x00" as []byte instance := GetModuleHandleA(null) @@ -59,6 +58,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: WNDPROC) -> (W }; if RegisterClassExA(^w.wc) == 0 { + win32_print_last_error( ) return w, false } @@ -129,6 +129,7 @@ run_game :: proc() { return DefWindowProcA(hwnd, msg, wparam, lparam) } + window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc) if !window_success { return @@ -155,7 +156,7 @@ run_game :: proc() { _ = DispatchMessageA(^msg) } - if is_key_down(VK_ESCAPE) { + if is_key_down(Key_Code.ESCAPE) { running = false } @@ -163,10 +164,10 @@ run_game :: proc() { SPEED :: 500 v: Vec2 - if is_key_down(VK_RIGHT) { v[0] += 1 } - if is_key_down(VK_LEFT) { v[0] -= 1 } - if is_key_down(VK_UP) { v[1] += 1 } - if is_key_down(VK_DOWN) { v[1] -= 1 } + if is_key_down(Key_Code.RIGHT) { v[0] += 1 } + if is_key_down(Key_Code.LEFT) { v[0] -= 1 } + if is_key_down(Key_Code.UP) { v[1] += 1 } + if is_key_down(Key_Code.DOWN) { v[1] -= 1 } v = vec2_norm0(v) diff --git a/examples/old_demos/demo002.odin b/examples/old_demos/demo002.odin new file mode 100644 index 000000000..899f9fc32 --- /dev/null +++ b/examples/old_demos/demo002.odin @@ -0,0 +1,900 @@ +// Demo 002 +#load "basic.odin" +#load "math.odin" +// #load "game.odin" + +#thread_local tls_int: int + +main :: proc() { + // Forenotes + + // Semicolons are now optional + // Rule for when a semicolon is expected after a statement + // - If the next token is not on the same line + // - if the next token is a closing brace } + // - Otherwise, a semicolon is needed + // + // Expections: + // for, if, match + // if x := thing(); x < 123 {} + // for i := 0; i < 123; i++ {} + + // Q: Should I use the new rule or go back to the old one without optional semicolons? + + + // #thread_local - see runtime.odin and above at `tls_int` + // #foreign_system_library - see win32.odin + + // struct_compound_literals() + // enumerations() + // variadic_procedures() + // new_builtins() + // match_statement() + // namespacing() + // subtyping() + // tagged_unions() +} + +struct_compound_literals :: proc() { + Thing :: type struct { + id: int + x: f32 + name: string + } + { + t1: Thing + t1.id = 1 + + t3 := Thing{} + t4 := Thing{1, 2, "Fred"} + // t5 := Thing{1, 2} + + t6 := Thing{ + name = "Tom", + x = 23, + } + } +} + +enumerations :: proc() { + { + Fruit :: type enum { + APPLE, // 0 + BANANA, // 1 + PEAR, // 2 + } + + f := Fruit.APPLE + // g12: int = Fruit.BANANA + g: int = Fruit.BANANA as int + // However, you can use enums are index values as _any_ integer allowed + } + { + Fruit1 :: type enum int { + APPLE, + BANANA, + PEAR, + } + + Fruit2 :: type enum u8 { + APPLE, + BANANA, + PEAR, + } + + Fruit3 :: type enum u8 { + APPLE = 1, + BANANA, // 2 + PEAR = 5, + TOMATO, // 6 + } + } + + // Q: remove the need for `type` if it's a record (struct/enum/raw_union/union)? +} + +variadic_procedures :: proc() { + print_ints :: proc(args: ..int) { + for i := 0; i < len(args); i++ { + if i > 0 { + print_string(", ") + } + print_int(args[i]) + } + } + + print_ints(); // nl() + print_ints(1); nl() + print_ints(1, 2, 3); nl() + + print_prefix_f32s :: proc(prefix: string, args: ..f32) { + print_string(prefix) + print_string(": ") + for i := 0; i < len(args); i++ { + if i > 0 { + print_string(", ") + } + print_f32(args[i]) + } + } + + print_prefix_f32s("a"); nl() + print_prefix_f32s("b", 1); nl() + print_prefix_f32s("c", 1, 2, 3); nl() + + // Internally, the variadic procedures get allocated to an array on the stack, + // and this array is passed a slice + + // This is first step for a `print` procedure but I do not have an `any` type + // yet as this requires a few other things first - i.e. introspection + + // NOTE(bill): I haven't yet added the feature of expanding a slice or array into + // a variadic a parameter but it's pretty trivial to add +} + +new_builtins :: proc() { + { + a := new(int) + b := new_slice(int, 12) + c := new_slice(int, 12, 16) + + defer delete(a) + defer delete(b) + defer delete(c) + + // NOTE(bill): These use the current context's allocator not the default allocator + // see runtime.odin + + // Q: Should this be `free` rather than `delete` and should I overload it for slices too? + + { + prev_context := context + defer context = prev_context + // Q: Should I add a `push_context` feature to the language? + + context.allocator = __default_allocator() + + a := new(int) + defer delete(a) + + // Do whatever + + } + } + + { + a: int = 123 + b: type_of_val(a) = 321 + + // NOTE(bill): This matches the current naming scheme + // size_of + // align_of + // offset_of + // + // size_of_val + // align_of_val + // offset_of_val + // type_of_val + } + + { + // Compile time assert + COND :: true + assert(COND) + // assert(!COND) + + // Runtime assert + x := true + assert(x) + // assert(!x) + } + + { + x: ^u32 = null; + y := ptr_offset(x, 100) + z := ptr_sub(y, x) + w := slice_ptr(x, 12) + t := slice_ptr(x, 12, 16) + + // NOTE(bill): These are here because I've removed: + // pointer arithmetic + // pointer indexing + // pointer slicing + + // Reason + + a: [16]int + a[1] = 1; + b := ^a + // Auto pointer deref + // consistent with record members + assert(b[1] == 1) + + // Q: Should I add them back in at the cost of inconsitency? + } + + { + a, b := -1, 2 + print_int(min(a, b)); nl() + print_int(max(a, b)); nl() + print_int(abs(a)); nl() + + // These work at compile time too + A :: -1 + B :: 2 + C :: min(A, B) + D :: max(A, B) + E :: abs(A) + + print_int(C); nl() + print_int(D); nl() + print_int(E); nl() + } +} + + +match_statement :: proc() { + // NOTE(bill): `match` statements are similar to `switch` statements + // in other languages but there are few differences + + { + match x := 5; x { + case 1: // cases must be constant expression + print_string("1!\n") + // break by default + + case 2: + s := "2!\n"; // Each case has its own scope + print_string(s) + break // explicit break + + case 3, 4: // multiple cases + print_string("3 or 4!\n") + + case 5: + print_string("5!\n") + fallthrough // explicit fallthrough + + default: + print_string("default!\n") + } + + + + match x := 1.5; x { + case 1.5: + print_string("1.5!\n") + // break by default + case MATH_TAU: + print_string("τ!\n") + default: + print_string("default!\n") + } + + + + match x := "Hello"; x { + case "Hello": + print_string("greeting\n") + // break by default + case "Goodbye": + print_string("farewell\n") + default: + print_string("???\n") + } + + + + + + + a := 53 + match { + case a == 1: + print_string("one\n") + case a == 2: + print_string("a couple\n") + case a < 7, a == 7: + print_string("a few\n") + case a < 12: // intentional bug + print_string("several\n") + case a >= 12 && a < 100: + print_string("dozens\n") + case a >= 100 && a < 1000: + print_string("hundreds\n") + default: + print_string("a fuck ton\n") + } + + // Identical to this + + b := 53 + if b == 1 { + print_string("one\n") + } else if b == 2 { + print_string("a couple\n") + } else if b < 7 || b == 7 { + print_string("a few\n") + } else if b < 12 { // intentional bug + print_string("several\n") + } else if b >= 12 && b < 100 { + print_string("dozens\n") + } else if b >= 100 && b < 1000 { + print_string("hundreds\n") + } else { + print_string("a fuck ton\n") + } + + // However, match statements allow for `break` and `fallthrough` unlike + // an if statement + } +} + +Vector3 :: type struct { + x, y, z: f32 +} + +print_floats :: proc(args: ..f32) { + for i := 0; i < len(args); i++ { + if i > 0 { + print_string(", ") + } + print_f32(args[i]) + } + print_nl() +} + +namespacing :: proc() { + { + Thing :: type struct { + x: f32 + name: string + } + + a: Thing + a.x = 3 + { + Thing :: type struct { + y: int + test: bool + } + + b: Thing // Uses this scope's Thing + b.test = true + } + } + + { + Entity :: type struct { + Guid :: type int + Nested :: type struct { + MyInt :: type int + i: int + } + + CONSTANT :: 123 + + + guid: Guid + name: string + pos: Vector3 + vel: Vector3 + nested: Nested + } + + guid: Entity.Guid = Entity.CONSTANT + i: Entity.Nested.MyInt + + + + { + using Entity + guid: Guid = CONSTANT + using Nested + i: MyInt + } + + + { + using Entity.Nested + guid: Entity.Guid = Entity.CONSTANT + i: MyInt + } + + + { + e: Entity + using e + guid = 27832 + name = "Bob" + + print_int(e.guid as int); nl() + print_string(e.name); nl() + } + + { + using e: Entity + guid = 78456 + name = "Thing" + + print_int(e.guid as int); nl() + print_string(e.name); nl() + } + } + + { + Entity :: type struct { + Guid :: type int + Nested :: type struct { + MyInt :: type int + i: int + } + + CONSTANT :: 123 + + + guid: Guid + name: string + using pos: Vector3 + vel: Vector3 + using nested: ^Nested + } + + e := Entity{nested = new(Entity.Nested)} + e.x = 123 + e.i = Entity.CONSTANT + } + + + + { + Entity :: type struct { + position: Vector3 + } + + print_pos_1 :: proc(entity: ^Entity) { + print_string("print_pos_1: ") + print_floats(entity.position.x, entity.position.y, entity.position.z) + } + + print_pos_2 :: proc(entity: ^Entity) { + using entity + print_string("print_pos_2: ") + print_floats(position.x, position.y, position.z) + } + + print_pos_3 :: proc(using entity: ^Entity) { + print_string("print_pos_3: ") + print_floats(position.x, position.y, position.z) + } + + print_pos_4 :: proc(using entity: ^Entity) { + using position + print_string("print_pos_4: ") + print_floats(x, y, z) + } + + e := Entity{position = Vector3{1, 2, 3}} + print_pos_1(^e) + print_pos_2(^e) + print_pos_3(^e) + print_pos_4(^e) + + // This is similar to C++'s `this` pointer that is implicit and only available in methods + } +} + +subtyping :: proc() { + { + // C way for subtyping/subclassing + + Entity :: type struct { + position: Vector3 + } + + Frog :: type struct { + entity: Entity + jump_height: f32 + } + + f: Frog + f.entity.position = Vector3{1, 2, 3} + + using f.entity + position = Vector3{1, 2, 3} + + } + + { + // C++ way for subtyping/subclassing + + Entity :: type struct { + position: Vector3 + } + + Frog :: type struct { + using entity: Entity + jump_height: f32 + } + + f: Frog + f.position = Vector3{1, 2, 3} + + + print_pos :: proc(using entity: Entity) { + print_string("print_pos: ") + print_floats(position.x, position.y, position.z) + } + + print_pos(f.entity) + print_pos(f) + + // Subtype Polymorphism + } + + { + // More than C++ way for subtyping/subclassing + + Entity :: type struct { + position: Vector3 + } + + Frog :: type struct { + jump_height: f32 + using entity: ^Entity // Doesn't have to be first member! + } + + f: Frog + f.entity = new(Entity) + f.position = Vector3{1, 2, 3} + + + print_pos :: proc(using entity: ^Entity) { + print_string("print_pos: ") + print_floats(position.x, position.y, position.z) + } + + print_pos(f.entity) + print_pos(^f) + print_pos(f) + } + + { + // More efficient subtyping + + Entity :: type struct { + position: Vector3 + } + + Frog :: type struct { + jump_height: f32 + using entity: ^Entity + } + + MAX_ENTITES :: 64 + entities: [MAX_ENTITES]Entity + entity_count := 0 + + next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity { + e := ^entities[entity_count^] + entity_count^++ + return e + } + + f: Frog + f.entity = next_entity(entities[:], ^entity_count) + f.position = Vector3{3, 4, 6} + + using f.position + print_floats(x, y, z) + } + + { + // Down casting + + Entity :: type struct { + position: Vector3 + } + + Frog :: type struct { + jump_height: f32 + using entity: Entity + } + + f: Frog + f.jump_height = 564 + e := ^f.entity + + frog := e down_cast ^Frog + print_string("down_cast: ") + print_f32(frog.jump_height); nl() + + // NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time + // Q: Should I completely remove `down_cast` as I added it in about 30 minutes + } + + { + // Multiple "inheritance"/subclassing + + Entity :: type struct { + position: Vector3 + } + Climber :: type struct { + speed: f32 + } + + Frog :: type struct { + using entity: Entity + using climber: Climber + } + } +} + +tagged_unions :: proc() { + { + EntityKind :: type enum { + INVALID, + FROG, + GIRAFFE, + HELICOPTER, + } + + Entity :: type struct { + kind: EntityKind + using data: raw_union { + frog: struct { + jump_height: f32 + colour: u32 + } + giraffe: struct { + neck_length: f32 + spot_count: int + } + helicopter: struct { + blade_count: int + weight: f32 + pilot_name: string + } + } + } + + e: Entity + e.kind = EntityKind.FROG + e.frog.jump_height = 12 + + f: type_of_val(e.frog); + + // But this is very unsafe and extremely cumbersome to write + // In C++, I use macros to alleviate this but it's not a solution + } + + { + Entity :: type union { + Frog: struct { + jump_height: f32 + colour: u32 + } + Giraffe: struct { + neck_length: f32 + spot_count: int + } + Helicopter: struct { + blade_count: int + weight: f32 + pilot_name: string + } + } + + using Entity + f1: Frog = Frog{12, 0xff9900} + f2: Entity = Frog{12, 0xff9900} // Implicit cast + f3 := Frog{12, 0xff9900} as Entity // Explicit cast + + // f3.Frog.jump_height = 12 // There are "members" of a union + + + + e, f, g, h: Entity + f = Frog{12, 0xff9900} + g = Giraffe{2.1, 23} + h = Helicopter{4, 1000, "Frank"} + + + + + // Requires a pointer to the union + // `x` will be a pointer to type of the case + + match type x : ^f { + case Frog: + print_string("Frog!\n") + print_f32(x.jump_height); nl() + x.jump_height = 3 + print_f32(x.jump_height); nl() + case Giraffe: + print_string("Giraffe!\n") + case Helicopter: + print_string("ROFLCOPTER!\n") + default: + print_string("invalid entity\n") + } + + + // Q: Allow for a non pointer version with takes a copy instead? + // Or it takes the pointer the data and not a copy + + + fp := ^f as ^Frog // Unsafe + print_f32(fp.jump_height); nl() + + + // Internals of a tagged union + /* + struct { + data: [size_of_biggest_tag]u8 + tag_index: int + } + */ + // This is to allow for pointer casting if needed + + + // Advantage over subtyping version + MAX_ENTITES :: 64 + entities: [MAX_ENTITES]Entity + + entities[0] = Frog{} + entities[1] = Helicopter{} + // etc. + } + + + { + // Transliteration of code from this actual compiler + // Some stuff is missing + Type :: type struct {} + Scope :: type struct {} + Token :: type struct {} + AstNode :: type struct {} + ExactValue :: type struct {} + + EntityKind :: type enum { + Invalid, + Constant, + Variable, + UsingVariable, + TypeName, + Procedure, + Builtin, + Count, + } + + Entity :: type struct { + Guid :: type i64 + + kind: EntityKind + guid: Guid + + scope: ^Scope + token: Token + type_: ^Type + + using data: raw_union { + Constant: struct { + value: ExactValue + } + Variable: struct { + visited: bool // Cycle detection + used: bool // Variable is used + is_field: bool // Is struct field + anonymous: bool // Variable is an anonymous + } + UsingVariable: struct { + } + TypeName: struct { + } + Procedure: struct { + used: bool + } + Builtin: struct { + id: int + } + } + } + + // Plus all the constructing procedures that go along with them!!!! + // It's a nightmare + } + + { + Type :: type struct {} + Scope :: type struct {} + Token :: type struct {} + AstNode :: type struct {} + ExactValue :: type struct {} + + + Entity :: type union { + Base :: type struct { + Guid :: type i64 + guid: Guid + + scope: ^Scope + token: Token + type_: ^Type + } + + + Constant: struct { + using base: Base + value: ExactValue + } + Variable: struct { + using base: Base + visited: bool // Cycle detection + used: bool // Variable is used + is_field: bool // Is struct field + anonymous: bool // Variable is an anonymous + } + UsingVariable: struct { + using base: Base + } + TypeName: struct { + using base: Base + } + Procedure: struct { + using base: Base + used: bool + } + Builtin: struct { + using base: Base + id: int + } + } + + using Entity + + e: Entity + + e = Variable{ + base = Base{}, + used = true, + anonymous = false, + } + + + + // Q: Allow a "base" type to be added to a union? + // Or even `using` on union to get the same properties? + } + + + { + // `Raw` unions still have uses, especially for mathematic types + + Vector2 :: type raw_union { + using xy_: struct { x, y: f32 } + e: [2]f32 + v: {2}f32 + } + + Vector3 :: type raw_union { + using xyz_: struct { x, y, z: f32 } + xy: Vector2 + e: [3]f32 + v: {3}f32 + } + + v2: Vector2 + v2.x = 1 + v2.e[0] = 1 + v2.v[0] = 1 + + v3: Vector3 + v3.x = 1 + v3.e[0] = 1 + v3.v[0] = 1 + v3.xy.x = 1 + } +} + +nl :: proc() { print_nl() } diff --git a/examples/old_runtime.odin b/examples/old_runtime.odin new file mode 100644 index 000000000..44ae3d64a --- /dev/null +++ b/examples/old_runtime.odin @@ -0,0 +1,412 @@ +#load "win32.odin" + +assume :: proc(cond: bool) #foreign "llvm.assume" + +__debug_trap :: proc() #foreign "llvm.debugtrap" +__trap :: proc() #foreign "llvm.trap" +read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter" + +bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16" +bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32" +bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64" + +byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16" +byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32" +byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" + +fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" +fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" + +// TODO(bill): make custom heap procedures +heap_alloc :: proc(len: int) -> rawptr #foreign "malloc" +heap_dealloc :: proc(ptr: rawptr) #foreign "free" + +memory_zero :: proc(data: rawptr, len: int) { + d := slice_ptr(data as ^byte, len) + for i := 0; i < len; i++ { + d[i] = 0 + } +} + +memory_compare :: proc(dst, src: rawptr, len: int) -> int { + s1, s2: ^byte = dst, src + for i := 0; i < len; i++ { + a := ptr_offset(s1, i)^ + b := ptr_offset(s2, i)^ + if a != b { + return (a - b) as int + } + } + return 0 +} + +memory_copy :: proc(dst, src: rawptr, n: int) #inline { + if dst == src { + return + } + + v128b :: type {4}u32 + assert(align_of(v128b) == 16) + + d, s: ^byte = dst, src + + for ; s as uint % 16 != 0 && n != 0; n-- { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + + if d as uint % 16 == 0 { + for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 { + (d as ^v128b)^ = (s as ^v128b)^ + } + + if n&8 != 0 { + (d as ^u64)^ = (s as ^u64)^ + d, s = ptr_offset(d, 8), ptr_offset(s, 8) + } + if n&4 != 0 { + (d as ^u32)^ = (s as ^u32)^; + d, s = ptr_offset(d, 4), ptr_offset(s, 4) + } + if n&2 != 0 { + (d as ^u16)^ = (s as ^u16)^ + d, s = ptr_offset(d, 2), ptr_offset(s, 2) + } + if n&1 != 0 { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + return; + } + + // IMPORTANT NOTE(bill): Little endian only + LS :: proc(a, b: u32) -> u32 #inline { return a << b } + RS :: proc(a, b: u32) -> u32 #inline { return a >> b } + /* NOTE(bill): Big endian version + LS :: proc(a, b: u32) -> u32 #inline { return a >> b; } + RS :: proc(a, b: u32) -> u32 #inline { return a << b; } + */ + + w, x: u32 + + if d as uint % 4 == 1 { + w = (s as ^u32)^ + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + n -= 3 + + for n > 16 { + d32 := d as ^u32 + s32 := ptr_offset(s, 1) as ^u32 + x = s32^; d32^ = LS(w, 24) | RS(x, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 24) | RS(w, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 24) | RS(x, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 24) | RS(w, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 + } + + } else if d as uint % 4 == 2 { + w = (s as ^u32)^ + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + n -= 2 + + for n > 17 { + d32 := d as ^u32 + s32 := ptr_offset(s, 2) as ^u32 + x = s32^; d32^ = LS(w, 16) | RS(x, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 16) | RS(w, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 16) | RS(x, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 16) | RS(w, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 + } + + } else if d as uint % 4 == 3 { + w = (s as ^u32)^ + d^ = s^ + n -= 1 + + for n > 18 { + d32 := d as ^u32 + s32 := ptr_offset(s, 3) as ^u32 + x = s32^; d32^ = LS(w, 8) | RS(x, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 8) | RS(w, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 8) | RS(x, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 8) | RS(w, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 + } + } + + if n&16 != 0 { + (d as ^v128b)^ = (s as ^v128b)^ + d, s = ptr_offset(d, 16), ptr_offset(s, 16) + } + if n&8 != 0 { + (d as ^u64)^ = (s as ^u64)^ + d, s = ptr_offset(d, 8), ptr_offset(s, 8) + } + if n&4 != 0 { + (d as ^u32)^ = (s as ^u32)^; + d, s = ptr_offset(d, 4), ptr_offset(s, 4) + } + if n&2 != 0 { + (d as ^u16)^ = (s as ^u16)^ + d, s = ptr_offset(d, 2), ptr_offset(s, 2) + } + if n&1 != 0 { + d^ = s^ + } +} + +memory_move :: proc(dst, src: rawptr, n: int) #inline { + d, s: ^byte = dst, src + if d == s { + return + } + if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s { + memory_copy(d, s, n) + return + } + + // TODO(bill): Vectorize the shit out of this + if d < s { + if s as int % size_of(int) == d as int % size_of(int) { + for d as int % size_of(int) != 0 { + if n == 0 { + return + } + n-- + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + di, si := d as ^int, s as ^int + for n >= size_of(int) { + di^ = si^ + di, si = ptr_offset(di, 1), ptr_offset(si, 1) + n -= size_of(int) + } + } + for ; n > 0; n-- { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + } else { + if s as int % size_of(int) == d as int % size_of(int) { + for ptr_offset(d, n) as int % size_of(int) != 0 { + if n == 0 { + return + } + n-- + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + for n >= size_of(int) { + n -= size_of(int) + di := ptr_offset(d, n) as ^int + si := ptr_offset(s, n) as ^int + di^ = si^ + } + for ; n > 0; n-- { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + } + for n > 0 { + n-- + dn := ptr_offset(d, n) + sn := ptr_offset(s, n) + dn^ = sn^ + } + } +} + +__string_eq :: proc(a, b: string) -> bool { + if len(a) != len(b) { + return false + } + if ^a[0] == ^b[0] { + return true + } + return memory_compare(^a[0], ^b[0], len(a)) == 0 +} + +__string_cmp :: proc(a, b : string) -> int { + min_len := len(a) + if len(b) < min_len { + min_len = len(b) + } + for i := 0; i < min_len; i++ { + x := a[i] + y := b[i] + if x < y { + return -1 + } else if x > y { + return +1 + } + } + + if len(a) < len(b) { + return -1 + } else if len(a) > len(b) { + return +1 + } + return 0 +} + +__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) } +__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 } +__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 } +__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 } +__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 } + + + + +Allocation_Mode :: type enum { + ALLOC, + DEALLOC, + DEALLOC_ALL, + RESIZE, +} + + + +Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr + +Allocator :: type struct { + procedure: Allocator_Proc; + data: rawptr +} + + +Context :: type struct { + thread_ptr: rawptr + + user_data: rawptr + user_index: int + + allocator: Allocator +} + +#thread_local context: Context + +DEFAULT_ALIGNMENT :: 2*size_of(int) + + +__check_context :: proc() { + if context.allocator.procedure == null { + context.allocator = __default_allocator() + } + if context.thread_ptr == null { + // TODO(bill): + // context.thread_ptr = current_thread_pointer() + } +} + + +alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) } + +alloc_align :: proc(size, alignment: int) -> rawptr #inline { + __check_context() + a := context.allocator + return a.procedure(a.data, Allocation_Mode.ALLOC, size, alignment, null, 0, 0) +} + +dealloc :: proc(ptr: rawptr) #inline { + __check_context() + a := context.allocator + _ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0) +} +dealloc_all :: proc(ptr: rawptr) #inline { + __check_context() + a := context.allocator + _ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 0, 0) +} + + +resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) } +resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline { + __check_context() + a := context.allocator + return a.procedure(a.data, Allocation_Mode.RESIZE, new_size, alignment, ptr, old_size, 0) +} + + + +default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr { + if old_memory == null { + return alloc_align(new_size, alignment) + } + + if new_size == 0 { + dealloc(old_memory) + return null + } + + if new_size == old_size { + return old_memory + } + + new_memory := alloc_align(new_size, alignment) + if new_memory == null { + return null + } + + memory_copy(new_memory, old_memory, min(old_size, new_size)); + dealloc(old_memory) + return new_memory +} + + +__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr { + using Allocation_Mode + match mode { + case ALLOC: + return heap_alloc(size) + case RESIZE: + return default_resize_align(old_memory, old_size, size, alignment) + case DEALLOC: + heap_dealloc(old_memory) + case DEALLOC_ALL: + // NOTE(bill): Does nothing + } + + return null +} + +__default_allocator :: proc() -> Allocator { + return Allocator{ + __default_allocator_proc, + null, + } +} + + + + +__assert :: proc(msg: string) { + file_write(file_get_standard(File_Standard.ERROR), msg as []byte) + // TODO(bill): Which is better? + // __trap() + __debug_trap() +} diff --git a/examples/runtime.odin b/examples/runtime.odin index 4aff161eb..a93480caf 100644 --- a/examples/runtime.odin +++ b/examples/runtime.odin @@ -68,9 +68,13 @@ byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" -// TODO(bill): make custom heap procedures -heap_alloc :: proc(len: int) -> rawptr #foreign "malloc" -heap_dealloc :: proc(ptr: rawptr) #foreign "free" +heap_alloc :: proc(len: int) -> rawptr { + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len) +} + +heap_dealloc :: proc(ptr: rawptr) { + _ = HeapFree(GetProcessHeap(), 0, ptr) +} memory_zero :: proc(data: rawptr, len: int) { llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64" @@ -258,6 +262,7 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode, return default_resize_align(old_memory, old_size, size, alignment) case DEALLOC: heap_dealloc(old_memory) + return null case DEALLOC_ALL: // NOTE(bill): Does nothing } diff --git a/examples/win32.odin b/examples/win32.odin index f7ddb003e..35c47ccba 100644 --- a/examples/win32.odin +++ b/examples/win32.odin @@ -242,160 +242,160 @@ wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign -is_key_down :: proc(key: int) -> bool { +is_key_down :: proc(key: Key_Code) -> bool { return GetAsyncKeyState(key as i32) < 0 } +Key_Code :: enum i32 { + LBUTTON = 0x01, + RBUTTON = 0x02, + CANCEL = 0x03, + MBUTTON = 0x04, -VK_LBUTTON :: 0x01 -VK_RBUTTON :: 0x02 -VK_CANCEL :: 0x03 -VK_MBUTTON :: 0x04 + BACK = 0x08, + TAB = 0x09, -VK_BACK :: 0x08 -VK_TAB :: 0x09 + CLEAR = 0x0C, + RETURN = 0x0D, -VK_CLEAR :: 0x0C -VK_RETURN :: 0x0D + SHIFT = 0x10, + CONTROL = 0x11, + MENU = 0x12, + PAUSE = 0x13, + CAPITAL = 0x14, -VK_SHIFT :: 0x10 -VK_CONTROL :: 0x11 -VK_MENU :: 0x12 -VK_PAUSE :: 0x13 -VK_CAPITAL :: 0x14 + KANA = 0x15, + HANGEUL = 0x15, + HANGUL = 0x15, + JUNJA = 0x17, + FINAL = 0x18, + HANJA = 0x19, + KANJI = 0x19, -VK_KANA :: 0x15 -VK_HANGEUL :: 0x15 -VK_HANGUL :: 0x15 -VK_JUNJA :: 0x17 -VK_FINAL :: 0x18 -VK_HANJA :: 0x19 -VK_KANJI :: 0x19 + ESCAPE = 0x1B, -VK_ESCAPE :: 0x1B + CONVERT = 0x1C, + NONCONVERT = 0x1D, + ACCEPT = 0x1E, + MODECHANGE = 0x1F, -VK_CONVERT :: 0x1C -VK_NONCONVERT :: 0x1D -VK_ACCEPT :: 0x1E -VK_MODECHANGE :: 0x1F + SPACE = 0x20, + PRIOR = 0x21, + NEXT = 0x22, + END = 0x23, + HOME = 0x24, + LEFT = 0x25, + UP = 0x26, + RIGHT = 0x27, + DOWN = 0x28, + SELECT = 0x29, + PRINT = 0x2A, + EXECUTE = 0x2B, + SNAPSHOT = 0x2C, + INSERT = 0x2D, + DELETE = 0x2E, + HELP = 0x2F, -VK_SPACE :: 0x20 -VK_PRIOR :: 0x21 -VK_NEXT :: 0x22 -VK_END :: 0x23 -VK_HOME :: 0x24 -VK_LEFT :: 0x25 -VK_UP :: 0x26 -VK_RIGHT :: 0x27 -VK_DOWN :: 0x28 -VK_SELECT :: 0x29 -VK_PRINT :: 0x2A -VK_EXECUTE :: 0x2B -VK_SNAPSHOT :: 0x2C -VK_INSERT :: 0x2D -VK_DELETE :: 0x2E -VK_HELP :: 0x2F + NUM0 = #rune "0", + NUM1 = #rune "1", + NUM2 = #rune "2", + NUM3 = #rune "3", + NUM4 = #rune "4", + NUM5 = #rune "5", + NUM6 = #rune "6", + NUM7 = #rune "7", + NUM8 = #rune "8", + NUM9 = #rune "9", -VK_0 :: #rune "0" -VK_1 :: #rune "1" -VK_2 :: #rune "2" -VK_3 :: #rune "3" -VK_4 :: #rune "4" -VK_5 :: #rune "5" -VK_6 :: #rune "6" -VK_7 :: #rune "7" -VK_8 :: #rune "8" -VK_9 :: #rune "9" + A = #rune "A", + B = #rune "B", + C = #rune "C", + D = #rune "D", + E = #rune "E", + F = #rune "F", + G = #rune "G", + H = #rune "H", + I = #rune "I", + J = #rune "J", + K = #rune "K", + L = #rune "L", + M = #rune "M", + N = #rune "N", + O = #rune "O", + P = #rune "P", + Q = #rune "Q", + R = #rune "R", + S = #rune "S", + T = #rune "T", + U = #rune "U", + V = #rune "V", + W = #rune "W", + X = #rune "X", + Y = #rune "Y", + Z = #rune "Z", -VK_A :: #rune "A" -VK_B :: #rune "B" -VK_C :: #rune "C" -VK_D :: #rune "D" -VK_E :: #rune "E" -VK_F :: #rune "F" -VK_G :: #rune "G" -VK_H :: #rune "H" -VK_I :: #rune "I" -VK_J :: #rune "J" -VK_K :: #rune "K" -VK_L :: #rune "L" -VK_M :: #rune "M" -VK_N :: #rune "N" -VK_O :: #rune "O" -VK_P :: #rune "P" -VK_Q :: #rune "Q" -VK_R :: #rune "R" -VK_S :: #rune "S" -VK_T :: #rune "T" -VK_U :: #rune "U" -VK_V :: #rune "V" -VK_W :: #rune "W" -VK_X :: #rune "X" -VK_Y :: #rune "Y" -VK_Z :: #rune "Z" + LWIN = 0x5B, + RWIN = 0x5C, + APPS = 0x5D, -VK_LWIN :: 0x5B -VK_RWIN :: 0x5C -VK_APPS :: 0x5D + 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, -VK_NUMPAD0 :: 0x60 -VK_NUMPAD1 :: 0x61 -VK_NUMPAD2 :: 0x62 -VK_NUMPAD3 :: 0x63 -VK_NUMPAD4 :: 0x64 -VK_NUMPAD5 :: 0x65 -VK_NUMPAD6 :: 0x66 -VK_NUMPAD7 :: 0x67 -VK_NUMPAD8 :: 0x68 -VK_NUMPAD9 :: 0x69 -VK_MULTIPLY :: 0x6A -VK_ADD :: 0x6B -VK_SEPARATOR :: 0x6C -VK_SUBTRACT :: 0x6D -VK_DECIMAL :: 0x6E -VK_DIVIDE :: 0x6F -VK_F1 :: 0x70 -VK_F2 :: 0x71 -VK_F3 :: 0x72 -VK_F4 :: 0x73 -VK_F5 :: 0x74 -VK_F6 :: 0x75 -VK_F7 :: 0x76 -VK_F8 :: 0x77 -VK_F9 :: 0x78 -VK_F10 :: 0x79 -VK_F11 :: 0x7A -VK_F12 :: 0x7B -VK_F13 :: 0x7C -VK_F14 :: 0x7D -VK_F15 :: 0x7E -VK_F16 :: 0x7F -VK_F17 :: 0x80 -VK_F18 :: 0x81 -VK_F19 :: 0x82 -VK_F20 :: 0x83 -VK_F21 :: 0x84 -VK_F22 :: 0x85 -VK_F23 :: 0x86 -VK_F24 :: 0x87 - -VK_NUMLOCK :: 0x90 -VK_SCROLL :: 0x91 - -VK_LSHIFT :: 0xA0 -VK_RSHIFT :: 0xA1 -VK_LCONTROL :: 0xA2 -VK_RCONTROL :: 0xA3 -VK_LMENU :: 0xA4 -VK_RMENU :: 0xA5 -VK_PROCESSKEY :: 0xE5 -VK_ATTN :: 0xF6 -VK_CRSEL :: 0xF7 -VK_EXSEL :: 0xF8 -VK_EREOF :: 0xF9 -VK_PLAY :: 0xFA -VK_ZOOM :: 0xFB -VK_NONAME :: 0xFC -VK_PA1 :: 0xFD -VK_OEM_CLEAR :: 0xFE + NUMLOCK = 0x90, + SCROLL = 0x91, + LSHIFT = 0xA0, + RSHIFT = 0xA1, + LCONTROL = 0xA2, + RCONTROL = 0xA3, + LMENU = 0xA4, + RMENU = 0xA5, + PROCESSKEY = 0xE5, + ATTN = 0xF6, + CRSEL = 0xF7, + EXSEL = 0xF8, + EREOF = 0xF9, + PLAY = 0xFA, + ZOOM = 0xFB, + NONAME = 0xFC, + PA1 = 0xFD, + OEM_CLEAR = 0xFE, +} diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 7bf131f05..df4c97f86 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -57,11 +57,31 @@ void add_type_info_type(Checker *c, Type *t) { } map_set(&c->info.type_info_types, hash_pointer(t), t); + + if (t->kind == Type_Named) { + // NOTE(bill): Just in case + add_type_info_type(c, t->Named.base); + return; + } + Type *bt = get_base_type(t); switch (bt->kind) { - case Type_Named: add_type_info_type(c, bt->Named.base); break; - case Type_Array: add_type_info_type(c, bt->Array.elem); break; - case Type_Slice: add_type_info_type(c, bt->Slice.elem); break; + case Type_Basic: { + if (bt->Basic.kind == Basic_string) { + add_type_info_type(c, make_type_pointer(c->allocator, t_u8)); + add_type_info_type(c, t_int); + } + } break; + case Type_Array: + add_type_info_type(c, bt->Array.elem); + add_type_info_type(c, make_type_pointer(c->allocator, bt->Array.elem)); + add_type_info_type(c, t_int); + break; + case Type_Slice: + add_type_info_type(c, bt->Slice.elem); + add_type_info_type(c, make_type_pointer(c->allocator, bt->Slice.elem)); + add_type_info_type(c, t_int); + break; case Type_Vector: add_type_info_type(c, bt->Vector.elem); break; case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break; case Type_Record: { @@ -1372,7 +1392,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { x->mode = Addressing_Value; } -b32 check_castable_to(Checker *c, Operand *operand, Type *y) { +b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) { if (check_is_assignable_to(c, operand, y)) return true; @@ -1387,20 +1407,20 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) { // Cast between booleans and integers - if (is_type_boolean(x) || is_type_integer(x)) { - if (is_type_boolean(y) || is_type_integer(y)) + if (is_type_boolean(xb) || is_type_integer(xb)) { + if (is_type_boolean(yb) || is_type_integer(yb)) return true; } // Cast between numbers - if (is_type_integer(x) || is_type_float(x)) { - if (is_type_integer(y) || is_type_float(y)) + if (is_type_integer(xb) || is_type_float(xb)) { + if (is_type_integer(yb) || is_type_float(yb)) return true; } // Cast between pointers - if (is_type_pointer(x)) { - if (is_type_pointer(y)) + if (is_type_pointer(xb)) { + if (is_type_pointer(yb)) return true; } @@ -1494,7 +1514,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { can_convert = true; } } - } else if (check_castable_to(c, x, type)) { + } else if (check_is_castable_to(c, x, type)) { x->mode = Addressing_Value; can_convert = true; } diff --git a/src/checker/type.cpp b/src/checker/type.cpp index f2db752a0..53944d3d6 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -706,8 +706,8 @@ void selection_add_index(Selection *s, isize index) { gb_array_append(s->index, index); } -gb_global Entity *entity_any_type_info = NULL; -gb_global Entity *entity_any_data = NULL; +gb_global Entity *entity__any_type_info = NULL; +gb_global Entity *entity__any_data = NULL; Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) { GB_ASSERT(type_ != NULL); @@ -721,29 +721,31 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se type = get_base_type(type); if (type->kind == Type_Basic) { - if (type->Basic.kind == Basic_any) { + switch (type->Basic.kind) { + case Basic_any: { String type_info_str = make_string("type_info"); String data_str = make_string("data"); - if (entity_any_type_info == NULL) { + if (entity__any_type_info == NULL) { Token token = {Token_Identifier}; token.string = type_info_str; - entity_any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false); + entity__any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false); } - if (entity_any_data == NULL) { + if (entity__any_data == NULL) { Token token = {Token_Identifier}; token.string = data_str; - entity_any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false); + entity__any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_rawptr, false); } if (are_strings_equal(field_name, type_info_str)) { selection_add_index(&sel, 0); - sel.entity = entity_any_type_info; + sel.entity = entity__any_type_info; return sel; } else if (are_strings_equal(field_name, data_str)) { selection_add_index(&sel, 1); - sel.entity = entity_any_data; + sel.entity = entity__any_data; return sel; } + } break; } return sel; @@ -916,8 +918,11 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { if (size > 0) return size; } - if (kind == Basic_string) + if (kind == Basic_string) { return 2 * s.word_size; + } else if (kind == Basic_any) { + return 2 * s.word_size; + } } break; case Type_Array: { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 0340cd322..a3e8c6b6b 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -3184,9 +3184,9 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { fall = ssa__make_block(proc, clause, make_string("match.fall.body")); } - if (gb_array_count(cc->list)) { + if (gb_array_count(cc->list) == 0) { // default case - default_stmts = cc->stmts; + default_stmts = cc->stmts; default_fall = fall; default_block = body; continue; diff --git a/src/parser.cpp b/src/parser.cpp index ec741ce1e..24810259d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -78,6 +78,7 @@ enum CallExprKind { AstNodeArray make_ast_node_array(AstFile *f) { AstNodeArray a; gb_array_init(a, gb_arena_allocator(&f->arena)); + GB_ASSERT(a != NULL); return a; } @@ -2220,7 +2221,7 @@ AstNode *parse_for_stmt(AstFile *f) { AstNode *parse_case_clause(AstFile *f) { Token token = f->cursor[0]; - AstNodeArray list = NULL; + AstNodeArray list = make_ast_node_array(f); if (allow_token(f, Token_case)) { list = parse_rhs_expr_list(f); } else { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 415352f33..eebdda765 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -323,6 +323,7 @@ TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) { char *c_str = gb_alloc_array(gb_heap_allocator(), char, fullpath.len+1); memcpy(c_str, fullpath.text, fullpath.len); c_str[fullpath.len] = '\0'; + defer (gb_free(gb_heap_allocator(), c_str)); gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);