From 11614c2649aa28a642e4d699cf447d6938057190 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Fri, 29 Sep 2017 21:11:16 +0100 Subject: [PATCH] Fix old_demos; Fix `when` bug; Fix enum `.names` --- build.bat | 2 +- examples/factorial.odin | 2 +- examples/game.odin | 24 ++--- examples/hello.odin | 2 +- examples/old_demos/demo001.odin | 40 ++++---- examples/old_demos/demo002.odin | 177 +++++++++++++++----------------- examples/old_demos/demo004.odin | 18 ++-- examples/old_demos/demo005.odin | 51 +++++---- examples/old_demos/demo006.odin | 128 +++++++++++------------ examples/punity.odin | 80 +++++++-------- src/check_expr.cpp | 3 + src/check_stmt.cpp | 1 - src/ir.cpp | 43 +++++--- 13 files changed, 285 insertions(+), 286 deletions(-) diff --git a/build.bat b/build.bat index ea9952610..c5ce5d350 100644 --- a/build.bat +++ b/build.bat @@ -43,7 +43,7 @@ del *.ilk > NUL 2> NUL cl %compiler_settings% "src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ - && odin run examples/demo.odin -opt=0 + && odin run examples/old_demos/demo006.odin -opt=0 rem && odin docs core/fmt.odin del *.obj > NUL 2> NUL diff --git a/examples/factorial.odin b/examples/factorial.odin index af39bbac1..dd9b6f6eb 100644 --- a/examples/factorial.odin +++ b/examples/factorial.odin @@ -1,4 +1,4 @@ -import "fmt.odin"; +import "core:fmt.odin"; main :: proc() { recursive_factorial :: proc(i: u64) -> u64 { diff --git a/examples/game.odin b/examples/game.odin index 1f09e9209..464c9d7d2 100644 --- a/examples/game.odin +++ b/examples/game.odin @@ -1,9 +1,9 @@ -import win32 "sys/windows.odin" when ODIN_OS == "windows"; -import wgl "sys/wgl.odin" when ODIN_OS == "windows"; -import "fmt.odin"; -import "math.odin"; -import "os.odin"; -import gl "opengl.odin"; +import win32 "core:sys/windows.odin" when ODIN_OS == "windows"; +import wgl "core:sys/wgl.odin" when ODIN_OS == "windows"; +import "core:fmt.odin"; +import "core:math.odin"; +import "core:os.odin"; +import gl "core:opengl.odin"; TWO_HEARTS :: '💕'; @@ -32,12 +32,12 @@ to_c_string :: proc(s: string) -> []u8 { Window :: struct { - width, height: int; - wc: win32.Wnd_Class_Ex_A; - dc: win32.Hdc; - hwnd: win32.Hwnd; - opengl_context, rc: wgl.Hglrc; - c_title: []u8; + width, height: int, + wc: win32.Wnd_Class_Ex_A, + dc: win32.Hdc, + hwnd: win32.Hwnd, + opengl_context, rc: wgl.Hglrc, + c_title: []u8, } make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) { diff --git a/examples/hello.odin b/examples/hello.odin index 96b7af0fa..95ff21670 100644 --- a/examples/hello.odin +++ b/examples/hello.odin @@ -1,4 +1,4 @@ -import "fmt.odin"; +import "core:fmt.odin"; main :: proc() { fmt.println("Hellope, world!"); diff --git a/examples/old_demos/demo001.odin b/examples/old_demos/demo001.odin index 5f30af8fe..0d5fb8926 100644 --- a/examples/old_demos/demo001.odin +++ b/examples/old_demos/demo001.odin @@ -1,9 +1,9 @@ -#import "fmt.odin"; -#import "os.odin"; -#import "mem.odin"; -// #import "http_test.odin" as ht; -// #import "game.odin" as game; -// #import "punity.odin" as pn; +import "core:fmt.odin"; +import "core:os.odin"; +import "core:mem.odin"; +// import "http_test.odin" as ht; +// import "game.odin" as game; +// import "punity.odin" as pn; main :: proc() { struct_padding(); @@ -160,21 +160,21 @@ type_introspection :: proc() { info: ^Type_Info; x: int; - info = type_info(int); // by type - info = type_info_of_val(x); // by value + info = type_info_of(int); // by type + info = type_info_of(x); // by value // See: runtime.odin - match i in info { - case Type_Info.Integer: + match i in info.variant { + case Type_Info_Integer: fmt.println("integer!"); - case Type_Info.Float: + case Type_Info_Float: fmt.println("float!"); - default: + case: fmt.println("potato!"); } // Unsafe cast - integer_info := cast(^Type_Info.Integer)cast(rawptr)info; + integer_info := cast(^Type_Info_Integer)cast(rawptr)info; } { @@ -185,9 +185,9 @@ type_introspection :: proc() { v2: Vector3; v3: Vector3; - t1 := type_info_of_val(v1); - t2 := type_info_of_val(v2); - t3 := type_info_of_val(v3); + t1 := type_info_of(v1); + t2 := type_info_of(v2); + t3 := type_info_of(v3); fmt.println(); fmt.print("Type of v1 is:\n\t", t1); @@ -262,12 +262,12 @@ crazy_introspection :: proc() { TOMATO, } - fruit_ti := type_info(Fruit); - name := (union_cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts - info, _ := union_cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts + fruit_ti := type_info_of(Fruit); + name := fruit_ti.variant.(Type_Info_Named).name; + info, _ := type_info_base(fruit_ti).variant.(Type_Info_Enum); fmt.printf("%s :: enum %T {\n", name, info.base); - for i := 0; i < len(info.values); i++ { + for _, i in info.values { fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]); } fmt.printf("}\n"); diff --git a/examples/old_demos/demo002.odin b/examples/old_demos/demo002.odin index 78cdb194a..e4640d125 100644 --- a/examples/old_demos/demo002.odin +++ b/examples/old_demos/demo002.odin @@ -1,7 +1,8 @@ // Demo 002 -#load "fmt.odin"; -#load "math.odin"; -// #load "game.odin" +export "core:fmt.odin"; +export "core:math.odin"; +export "core:mem.odin"; +// export "game.odin" #thread_local tls_int: int; @@ -94,11 +95,9 @@ enumerations :: proc() { } variadic_procedures :: proc() { - print_ints :: proc(args: ..int) { + print_ints :: proc(args: ...int) { for arg, i in args { - if i > 0 { - print(", "); - } + if i > 0 do print(", "); print(arg); } } @@ -107,13 +106,11 @@ variadic_procedures :: proc() { print_ints(1); nl(); print_ints(1, 2, 3); nl(); - print_prefix_f32s :: proc(prefix: string, args: ..f32) { + print_prefix_f32s :: proc(prefix: string, args: ...f32) { print(prefix); print(": "); for arg, i in args { - if i > 0 { - print(", "); - } + if i > 0 do print(", "); print(arg); } } @@ -147,13 +144,7 @@ new_builtins :: proc() { // Q: Should this be `free` rather than `free` 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(); - + push_allocator default_allocator() { a := new(int); defer free(a); @@ -164,7 +155,7 @@ new_builtins :: proc() { { a: int = 123; - b: type_of_val(a) = 321; + b: type_of(a) = 321; // NOTE(bill): This matches the current naming scheme // size_of @@ -205,7 +196,7 @@ new_builtins :: proc() { a: [16]int; a[1] = 1; - b := ^a; + b := &a; // Auto pointer deref // consistent with record members assert(b[1] == 1); @@ -255,7 +246,7 @@ match_statement :: proc() { print("5!\n"); fallthrough; // explicit fallthrough - default: + case: print("default!\n"); } @@ -267,7 +258,7 @@ match_statement :: proc() { // break by default case TAU: print("τ!\n"); - default: + case: print("default!\n"); } @@ -279,7 +270,7 @@ match_statement :: proc() { // break by default case "Goodbye": print("farewell\n"); - default: + case: print("???\n"); } @@ -302,7 +293,7 @@ match_statement :: proc() { print("dozens\n"); case a >= 100 && a < 1000: print("hundreds\n"); - default: + case: print("a fuck ton\n"); } @@ -332,11 +323,9 @@ match_statement :: proc() { Vector3 :: struct {x, y, z: f32} -print_floats :: proc(args: ..f32) { +print_floats :: proc(args: ...f32) { for arg, i in args { - if i > 0 { - print(", "); - } + if i > 0 do print(", "); print(arg); } println(); @@ -355,7 +344,7 @@ namespacing :: proc() { Thing :: #type struct { y: int, test: bool, - } + }; b: Thing; // Uses this scope's Thing b.test = true; @@ -473,10 +462,10 @@ namespacing :: proc() { } e := Entity{position = Vector3{1, 2, 3}}; - print_pos_1(^e); - print_pos_2(^e); - print_pos_3(^e); - print_pos_4(^e); + 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 } @@ -574,20 +563,20 @@ subtyping :: proc() { entity_count := 0; next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity { - e := ^entities[entity_count^]; - entity_count^++; + e := &entities[entity_count^]; + entity_count^ += 1; return e; } f: Frog; - f.entity = next_entity(entities[..], ^entity_count); + f.entity = next_entity(entities[..], &entity_count); f.position = Vector3{3, 4, 6}; using f.position; print_floats(x, y, z); } - { + /*{ // Down casting Entity :: struct { @@ -609,7 +598,7 @@ subtyping :: proc() { // 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 @@ -630,7 +619,7 @@ subtyping :: proc() { tagged_unions :: proc() { { - EntityKind :: enum { + Entity_Kind :: enum { INVALID, FROG, GIRAFFE, @@ -638,8 +627,8 @@ tagged_unions :: proc() { } Entity :: struct { - kind: EntityKind - using data: raw_union { + kind: Entity_Kind + using data: struct #raw_union { frog: struct { jump_height: f32, colour: u32, @@ -657,33 +646,31 @@ tagged_unions :: proc() { } e: Entity; - e.kind = EntityKind.FROG; + e.kind = Entity_Kind.FROG; e.frog.jump_height = 12; - f: type_of_val(e.frog); + f: type_of(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 :: union { - Frog{ - jump_height: f32, - colour: u32, - }, - Giraffe{ - neck_length: f32, - spot_count: int, - }, - Helicopter{ - blade_count: int, - weight: f32, - pilot_name: string, - }, + 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, + } + Entity :: union {Frog, Giraffe, Helicopter}; - using Entity; f1: Frog = Frog{12, 0xff9900}; f2: Entity = Frog{12, 0xff9900}; // Implicit cast f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast @@ -703,7 +690,7 @@ tagged_unions :: proc() { // Requires a pointer to the union // `x` will be a pointer to type of the case - match x in ^f { + match x in &f { case Frog: print("Frog!\n"); print(x.jump_height); nl(); @@ -713,7 +700,7 @@ tagged_unions :: proc() { print("Giraffe!\n"); case Helicopter: print("ROFLCOPTER!\n"); - default: + case: print("invalid entity\n"); } @@ -755,11 +742,11 @@ tagged_unions :: proc() { AstNode :: struct {}; ExactValue :: struct {}; - EntityKind :: enum { + Entity_Kind :: enum { Invalid, Constant, Variable, - UsingVariable, + Using_Variable, TypeName, Procedure, Builtin, @@ -769,14 +756,14 @@ tagged_unions :: proc() { Guid :: i64; Entity :: struct { - kind: EntityKind, + kind: Entity_Kind, guid: Guid, scope: ^Scope, token: Token, type_: ^Type, - using data: raw_union { + using data: struct #raw_union { Constant: struct { value: ExactValue, }, @@ -786,7 +773,7 @@ tagged_unions :: proc() { is_field: bool, // Is struct field anonymous: bool, // Variable is an anonymous }, - UsingVariable: struct { + Using_Variable: struct { }, TypeName: struct { }, @@ -813,44 +800,44 @@ tagged_unions :: proc() { Guid :: i64; Entity_Base :: struct { - } - Entity :: 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 + } + Using_Variable :: struct { + } + TypeName :: struct { + } + Procedure :: struct { + used: bool, + } + Builtin :: struct { + id: int, + } + + Entity :: struct { guid: Guid, scope: ^Scope, token: Token, type_: ^Type, - Constant{ - value: ExactValue, - }, - Variable{ - visited: bool, // Cycle detection - used: bool, // Variable is used - is_field: bool, // Is struct field - anonymous: bool, // Variable is an anonymous - }, - UsingVariable{ - }, - TypeName{ - }, - Procedure{ - used: bool, - }, - Builtin{ - id: int, - }, + variant: union {Constant, Variable, Using_Variable, TypeName, Procedure, Builtin}, } - using Entity; - - e: Entity; - - e = Variable{ - used = true, - anonymous = false, + e := Entity{ + variant = Variable{ + used = true, + anonymous = false, + }, }; @@ -863,13 +850,13 @@ tagged_unions :: proc() { { // `Raw` unions still have uses, especially for mathematic types - Vector2 :: raw_union { + Vector2 :: struct #raw_union { using xy_: struct { x, y: f32 }, e: [2]f32, v: [vector 2]f32, } - Vector3 :: raw_union { + Vector3 :: struct #raw_union { using xyz_: struct { x, y, z: f32 }, xy: Vector2, e: [3]f32, diff --git a/examples/old_demos/demo004.odin b/examples/old_demos/demo004.odin index 86588d60d..be88a1aa7 100644 --- a/examples/old_demos/demo004.odin +++ b/examples/old_demos/demo004.odin @@ -1,14 +1,14 @@ -#import "fmt.odin"; -#import "utf8.odin"; -#import "hash.odin"; -#import "mem.odin"; +import "core:fmt.odin"; +import "core:utf8.odin"; +import "core:hash.odin"; +import "core:mem.odin"; main :: proc() { { // New Standard Library stuff s := "Hello"; fmt.println(s, utf8.valid_string(s), - hash.murmur64(cast([]byte)s)); + hash.murmur64(cast([]u8)s)); // utf8.odin // hash.odin @@ -20,10 +20,10 @@ main :: proc() { { arena: mem.Arena; - mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator - defer mem.free_arena(^arena); + mem.init_arena_from_context(&arena, mem.megabytes(16)); // Uses default allocator + defer mem.destroy_arena(&arena); - push_allocator mem.arena_allocator(^arena) { + push_allocator mem.arena_allocator(&arena) { x := new(int); x^ = 1337; @@ -49,7 +49,7 @@ main :: proc() { // You can also "push" a context c := context; // Create copy of the allocator - c.allocator = mem.arena_allocator(^arena); + c.allocator = mem.arena_allocator(&arena); push_context c { x := new(int); diff --git a/examples/old_demos/demo005.odin b/examples/old_demos/demo005.odin index f9d1a4a4c..481b05155 100644 --- a/examples/old_demos/demo005.odin +++ b/examples/old_demos/demo005.odin @@ -1,13 +1,13 @@ -#import "fmt.odin"; -#import "utf8.odin"; -// #import "atomic.odin"; -// #import "hash.odin"; -// #import "math.odin"; -// #import "mem.odin"; -// #import "opengl.odin"; -// #import "os.odin"; -// #import "sync.odin"; -// #import win32 "sys/windows.odin"; +import "core:fmt.odin"; +import "core:utf8.odin"; +// import "core:atomic.odin"; +// import "core:hash.odin"; +// import "core:math.odin"; +// import "core:mem.odin"; +// import "core:opengl.odin"; +// import "core:os.odin"; +// import "core:sync.odin"; +// import win32 "core:sys/windows.odin"; main :: proc() { // syntax(); @@ -43,7 +43,7 @@ syntax :: proc() { Thing2 :: struct {x: f32, y: int, z: ^[]int}; // Slice interals are now just a `ptr+len+cap` - slice: []int; compile_assert(size_of_val(slice) == 3*size_of(int)); + slice: []int; compile_assert(size_of(slice) == 3*size_of(int)); // Helper type - Help the reader understand what it is quicker My_Int :: #type int; @@ -90,22 +90,17 @@ Prefix_Type :: struct {x: int, y: f32, z: rawptr}; prefixes :: proc() { using var: Prefix_Type; - immutable const := Prefix_Type{1, 2, nil}; var.x = 123; x = 123; - // const.x = 123; // const is immutable - - foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) { - // int_ptr = nil; // Not valid - // int_ptr^ = 123; // Not valid + foo :: proc(using pt: Prefix_Type) { } // Same as C99's `restrict` - bar :: proc(no_alias a, b: ^int) { + bar :: proc(#no_alias a, b: ^int) { // Assumes a never equals b so it can perform optimizations with that fact } @@ -138,14 +133,18 @@ when_statements :: proc() { foreign_procedures(); } -#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows"; +when ODIN_OS == "windows" { + foreign_system_library win32_user "user32.lib"; +} // NOTE: This is done on purpose for two reasons: // * Makes it clear where the platform specific stuff is // * Removes the need to solve the travelling salesman problem when importing files :P foreign_procedures :: proc() { - ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user; - show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow"; + foreign win32_user { + ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 ---; + show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #link_name "ShowWindow" ---; + } // NOTE: If that library doesn't get used, it doesn't get linked with // NOTE: There is not link checking yet to see if that procedure does come from that library @@ -203,14 +202,14 @@ loops :: proc() { fmt.println(val, idx); } - primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19}; + primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19}; for p in primes { fmt.println(p); } // Pointers to arrays, slices, or strings are allowed - for _ in ^primes { + for _ in &primes { // ignore the value and just iterate across it } @@ -219,7 +218,7 @@ loops :: proc() { name := "你好,世界"; fmt.println(name); for r in name { - compile_assert(type_of_val(r) == rune); + compile_assert(type_of(r) == rune); fmt.printf("%r\n", r); } @@ -270,8 +269,8 @@ procedure_overloading :: proc() { a: i32 = 123; b: f32; c: rawptr; - fmt.println(foo(^a)); - foo(^b); + fmt.println(foo(&a)); + foo(&b); foo(c); // foo(nil); // nil could go to numerous types thus the ambiguity diff --git a/examples/old_demos/demo006.odin b/examples/old_demos/demo006.odin index 2f4ffef66..209f31381 100644 --- a/examples/old_demos/demo006.odin +++ b/examples/old_demos/demo006.odin @@ -1,14 +1,14 @@ -#import "atomic.odin"; -#import "hash.odin"; -#import "mem.odin"; -#import "opengl.odin"; -#import "strconv.odin"; -#import "sync.odin"; -#import win32 "sys/windows.odin"; +// import "core:atomic.odin"; +import "core:hash.odin"; +import "core:mem.odin"; +import "core:opengl.odin"; +import "core:strconv.odin"; +import "core:sync.odin"; +import win32 "core:sys/windows.odin"; -#import "fmt.odin"; -#import "os.odin"; -#import "math.odin"; +import "core:fmt.odin"; +import "core:os.odin"; +import "core:math.odin"; main :: proc() { @@ -55,7 +55,7 @@ when true { for i in 0..16 { } // Is similar to - for _i := 0; _i < 16; _i++ { immutable i := _i; + for i := 0; i < 16; i += 1 { } } @@ -77,16 +77,15 @@ when true { } { - t := type_info(int); - using Type_Info; - match i in t { - case Integer, Float: + t := type_info_of(int); + match i in t.variant { + case Type_Info_Integer, Type_Info_Float: fmt.println("It's a number"); } x: any = 123; - foo match i in x { + foo: match i in x { case int, f32: fmt.println("It's an int or f32"); break foo; @@ -112,21 +111,20 @@ when true { { // Slices now store a capacity - buf: [256]byte; - s: []byte; + buf: [256]u8; + s: []u8; s = buf[..0]; // == buf[0..0]; - fmt.println("count =", s.count); - fmt.println("capacity =", s.capacity); - append(s, 1, 2, 3); + fmt.println("count =", len(s)); + fmt.println("capacity =", cap(s)); + append(&s, 1, 2, 3); fmt.println(s); s = buf[1..2..3]; - fmt.println("count =", s.count); - fmt.println("capacity =", s.capacity); + fmt.println("count =", len(s)); + fmt.println("capacity =", cap(s)); fmt.println(s); - clear(s); // Sets count to zero - s.count = 0; // Equivalent + clear(&s); // Sets count to zero } { @@ -136,11 +134,11 @@ when true { flags: u32, } foo_array: [256]Foo; - foo_as_bytes: []byte = slice_to_bytes(foo_array[..]); + foo_as_bytes: []u8 = mem.slice_to_bytes(foo_array[..]); // Useful for things like // os.write(handle, foo_as_bytes); - foo_slice := slice_ptr(cast(^Foo)foo_as_bytes.data, foo_as_bytes.count/size_of(Foo), foo_as_bytes.capacity/size_of(Foo)); + foo_slice := mem.slice_ptr(cast(^Foo)&foo_as_bytes[0], len(foo_as_bytes)/size_of(Foo), cap(foo_as_bytes)/size_of(Foo)); // Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone? // And if so what would the syntax be? // slice_transmute([]Foo, foo_as_bytes); @@ -161,33 +159,26 @@ when true { fmt.println(i); } - compile_assert(size_of([vector 7]bool) == size_of([7]bool)); - compile_assert(size_of([vector 7]i32) == size_of([7]i32)); + compile_assert(size_of([vector 7]bool) >= size_of([7]bool)); + compile_assert(size_of([vector 7]i32) >= size_of([7]i32)); // align_of([vector 7]i32) != align_of([7]i32) // this may be the case } { // fmt.* changes - // bprint* returns `int` (bytes written) - // sprint* returns `string` (bytes written as a string) + // bprint* returns `string` - data: [256]byte; - str := fmt.sprintf(data[..0], "Hellope %d %s %c", 123, "others", '!'); + data: [256]u8; + str := fmt.bprintf(data[..], "Hellope %d %s %c", 123, "others", '!'); fmt.println(str); - - buf := data[..0]; - count := fmt.bprintf(^buf, "Hellope %d %s %c", 321, "y'all", '!'); - fmt.println(cast(string)buf[..count]); - - // NOTE(bill): We may change this but because this is a library feature, I am not that bothered yet } { x: [dynamic]f64; - reserve(x, 16); + reserve(&x, 16); defer free(x); // `free` is overloaded for numerous types // Number literals can have underscores in them for readability - append(x, 2_000_000.500_000, 123, 5, 7); // variadic append + append(&x, 2_000_000.500_000, 123, 5, 7); // variadic append for p, i in x { if i > 0 { fmt.print(", "); } @@ -201,13 +192,13 @@ when true { x := [dynamic]f64{2_000_000.500_000, 3, 5, 7}; defer free(x); fmt.println(x); // fmt.print* supports printing of dynamic types - clear(x); + clear(&x); fmt.println(x); } { m: map[f32]int; - reserve(m, 16); + reserve(&m, 16); defer free(m); m[1.0] = 1278; @@ -241,12 +232,12 @@ when true { assert(ok && c == 7654); fmt.println(m); - delete(m, "c"); // deletes entry with key "c" + delete(&m, "c"); // deletes entry with key "c" _, found := m["c"]; assert(!found); fmt.println(m); - clear(m); + clear(&m); fmt.println(m); // NOTE: Fixed size maps are planned but we have not yet implemented @@ -257,7 +248,21 @@ when true { Vector3 :: struct{x, y, z: f32}; Quaternion :: struct{x, y, z, w: f32}; - Entity :: union { + // Variants + Frog :: struct { + ribbit_volume: f32, + jump_height: f32, + } + Door :: struct { + openness: f32, + } + Map :: struct { + width, height: f32, + place_positions: []Vector3, + place_names: []string, + } + + Entity :: struct { // Common Fields id: u64, name: string, @@ -265,25 +270,13 @@ when true { orientation: Quaternion, flags: u32, - // Variants - Frog{ - ribbit_volume: f32, - jump_height: f32, - }, - Door{ - openness: f32, - }, - Map{ - width, height: f32, - place_positions: []Vector3, - place_names: []string, - }, + variant: union { Frog, Door, Map }, } entity: Entity; + entity.id = 1337; // implicit conversion from variant to base type - entity = Entity.Frog{ - id = 1337, + entity.variant = Frog{ ribbit_volume = 0.5, jump_height = 2.1, /*other data */ @@ -292,26 +285,25 @@ when true { entity.name = "Frank"; entity.position = Vector3{1, 4, 9}; - using Entity; - match e in entity { + match e in entity.variant { case Frog: fmt.println("Ribbit"); case Door: fmt.println("Creak"); case Map: fmt.println("Rustle"); - default: + case: fmt.println("Just a normal entity"); } - if frog, ok := union_cast(Frog)entity; ok { - fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, frog.position); + if frog, ok := entity.variant.(Frog); ok { + fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, entity.position); } // Panics if not the correct type frog: Frog; - frog = union_cast(Frog)entity; - frog, _ = union_cast(Frog)entity; // ignore error and force cast + frog = entity.variant.(Frog); + frog, _ = entity.variant.(Frog); // ignore error and force cast } } } diff --git a/examples/punity.odin b/examples/punity.odin index 33b1aecdf..49d965360 100644 --- a/examples/punity.odin +++ b/examples/punity.odin @@ -1,7 +1,7 @@ -import win32 "sys/windows.odin"; -import "fmt.odin"; -import "os.odin"; -import "mem.odin"; +import win32 "core:sys/windows.odin"; +import "core:fmt.odin"; +import "core:os.odin"; +import "core:mem.odin"; CANVAS_WIDTH :: 128; @@ -25,13 +25,13 @@ DRAW_LIST_RESERVE :: 128; MAX_KEYS :: 256; Core :: struct { - stack: ^Bank; - storage: ^Bank; + stack: ^Bank, + storage: ^Bank, - running: bool; - key_modifiers: u32; - key_states: [MAX_KEYS]u8; - key_deltas: [MAX_KEYS]u8; + running: bool, + key_modifiers: u32, + key_states: [MAX_KEYS]u8, + key_deltas: [MAX_KEYS]u8, perf_frame, perf_frame_inner, @@ -39,66 +39,66 @@ Core :: struct { perf_audio, perf_blit, perf_blit_cvt, - perf_blit_gdi: Perf_Span; + perf_blit_gdi: Perf_Span, - frame: i64; + frame: i64, - canvas: Canvas; - draw_list: ^Draw_List; + canvas: Canvas, + draw_list: ^Draw_List, } Perf_Span :: struct { - stamp: f64; - delta: f32; + stamp: f64, + delta: f32, } Bank :: struct { - memory: []u8; - cursor: int; + memory: []u8, + cursor: int, } Bank_State :: struct { - state: Bank; - bank: ^Bank; + state: Bank, + bank: ^Bank, } Color :: struct #raw_union { - using channels: struct{a, b, g, r: u8}; - rgba: u32; + using channels: struct{a, b, g, r: u8}, + rgba: u32, } Palette :: struct { - colors: [256]Color; - colors_count: u8; + colors: [256]Color, + colors_count: u8, } Rect :: struct #raw_union { - using minmax: struct {min_x, min_y, max_x, max_y: int}; - using pos: struct {left, top, right, bottom: int}; - e: [4]int; + using minmax: struct {min_x, min_y, max_x, max_y: int}, + using pos: struct {left, top, right, bottom: int}, + e: [4]int, } Bitmap :: struct { - pixels: []u8; - width: int; - height: int; + pixels: []u8, + width: int, + height: int, } Font :: struct { - using bitmap: Bitmap; - char_width: int; - char_height: int; + using bitmap: Bitmap, + char_width: int, + char_height: int, } Canvas :: struct { - using bitmap: ^Bitmap; - palette: Palette; - translate_x: int; - translate_y: int; - clip: Rect; - font: ^Font; + using bitmap: ^Bitmap, + palette: Palette, + translate_x: int, + translate_y: int, + clip: Rect, + font: ^Font, } DrawFlag :: enum { @@ -110,7 +110,7 @@ DrawFlag :: enum { Draw_Item :: struct {} Draw_List :: struct { - items: []Draw_Item; + items: []Draw_Item, } Key :: enum { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bec444d2f..d28419ccf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4823,6 +4823,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) { add_type_info_type(c, operand->type); } + if (is_type_enum(operand->type)) { + add_type_info_type(c, operand->type); + } } if (entity == nullptr && selector->kind == AstNode_BasicLit) { if (is_type_struct(operand->type) || is_type_tuple(operand->type)) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 8eeab55ab..b4cb91025 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -393,7 +393,6 @@ struct TypeAndToken { }; void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) { - flags &= ~Stmt_CheckScopeDecls; Operand operand = {Addressing_Invalid}; check_expr(c, &operand, ws->cond); if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) { diff --git a/src/ir.cpp b/src/ir.cpp index 97b8f787d..2fbcee70a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -853,10 +853,19 @@ String ir_get_global_name(irModule *m, irValue *v) { String *found = map_get(&m->entity_names, hash_entity(e)); if (found != nullptr) { name = *found; + } else { + GB_ASSERT(name.len > 0); } return name; } +void ir_add_entity_name(irModule *m, Entity *e, String name) { + GB_ASSERT(name.len > 0); + map_set(&m->entity_names, hash_entity(e), name); +} + + + irValue *ir_instr_local(irProcedure *p, Entity *e, bool zero_initialized) { @@ -1153,14 +1162,21 @@ irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefi gbAllocator a = m->allocator; Token token = {Token_Ident}; isize name_len = prefix.len + 10; - token.string.text = gb_alloc_array(a, u8, name_len); - token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, - "%.*s-%llx", LIT(prefix), cast(unsigned long long)id)-1; - Entity *e = make_entity_variable(a, nullptr, token, make_type_array(a, elem_type, count), false); + + char *text = gb_alloc_array(a, char, name_len); + gb_snprintf(text, name_len, + "%.*s-%llx", LIT(prefix), cast(unsigned long long)id); + + String s = make_string_c(text); + + Entity *e = make_entity_variable(a, nullptr, + make_token_ident(s), + make_type_array(a, elem_type, count), + false); irValue *value = ir_value_global(a, e, nullptr); value->Global.is_private = true; ir_module_add_value(m, e, value); - map_set(&m->members, hash_string(token.string), value); + map_set(&m->members, hash_string(s), value); return value; } @@ -3436,6 +3452,7 @@ irValue *ir_type_info(irProcedure *proc, Type *type) { type = default_type(type); i32 entry_index = cast(i32)type_info_index(info, type); + GB_ASSERT(entry_index >= 0); // gb_printf_err("%d %s\n", entry_index, type_to_string(type)); @@ -3639,7 +3656,8 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) { "%.*s.%.*s", LIT(parent), LIT(cn)); String child = {text, new_name_len-1}; - map_set(&m->entity_names, hash_entity(field), child); + GB_ASSERT(child.len > 0); + ir_add_entity_name(m, field, child); ir_gen_global_type_name(m, field, child); } @@ -5148,15 +5166,16 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { String name = e->token.string; if (name == "names") { irValue *ti_ptr = ir_type_info(proc, type); + irValue *variant = ir_emit_struct_ep(proc, ti_ptr, 2); irValue *names_ptr = nullptr; if (is_type_enum(type)) { - irValue *enum_info = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); - names_ptr = ir_emit_struct_ep(proc, enum_info, 3); + irValue *enum_info = ir_emit_conv(proc, variant, t_type_info_enum_ptr); + names_ptr = ir_emit_struct_ep(proc, enum_info, 1); } else if (type->kind == Type_Struct) { - irValue *struct_info = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); - names_ptr = ir_emit_struct_ep(proc, struct_info, 3); + irValue *struct_info = ir_emit_conv(proc, variant, t_type_info_struct_ptr); + names_ptr = ir_emit_struct_ep(proc, struct_info, 1); } return ir_addr(names_ptr); } else { @@ -7641,7 +7660,7 @@ void ir_gen_tree(irGen *s) { if (!e->scope->is_global) { name = ir_mangle_name(s, e->token.pos.file, e); } - map_set(&m->entity_names, hash_entity(e), name); + ir_add_entity_name(m, e, name); irValue *g = ir_value_global(a, e, nullptr); g->Global.name = name; @@ -7716,7 +7735,7 @@ void ir_gen_tree(irGen *s) { } else if (check_is_entity_overloaded(e)) { name = ir_mangle_name(s, e->token.pos.file, e); } - map_set(&m->entity_names, hash_entity(e), name); + ir_add_entity_name(m, e, name); switch (e->kind) { case Entity_TypeName: