diff options
| author | Ginger Bill <bill@gingerbill.org> | 2016-09-04 16:16:17 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2016-09-04 16:16:17 +0100 |
| commit | c2e3c3801acd8af32fcf6ea3ad2d3a2ddc94c870 (patch) | |
| tree | 4686866a14b65f9d9c4a37567c8593f7951b1881 /examples | |
| parent | cdd8eadda172b3ced7a774dfa1f22a976b3bdb7f (diff) | |
Type match statement for tagged unions
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/demo.odin | 748 |
1 files changed, 743 insertions, 5 deletions
diff --git a/examples/demo.odin b/examples/demo.odin index 969b958fc..a795e75ae 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -4,20 +4,758 @@ main :: proc() { Entity :: type union { - FROG: struct { + Frog: struct { jump_height: f32 } - HELICOPTER: struct { + Helicopter: struct { weight: f32 blade_code: int } } - e: Entity - f: Entity = Entity.FROG{1}; - h: Entity = Entity.HELICOPTER{123, 4}; + using Entity + f: Entity = Frog{137} + h: Entity = Helicopter{123, 4} + match type ^f -> e { + case Frog: + print_string("Frog!\n") + print_f32(e.jump_height); nl() + e.jump_height = 69 + print_f32(e.jump_height); nl() + case Helicopter: + print_string("Helicopter!\n") + e.weight = 1337 + default: + print_string("Unknown!\n") + } +} + +nl :: proc() { print_nl() } + +/* +// Demo 001 +#load "basic.odin" +#load "game.odin" + +main :: proc() { + // _ = hellope() + // procedures() + // variables() + // constants() + // types() + // data_control() + // using_fields() + + run_game() +} + + +hellope :: proc() -> int { + print_string("Hellope, 世界\n") + return 1 +} + + +// Line comment +/* + Block Comment +*/ +/* + Nested /* + Block /* + Comment + */ + */ +*/ + +apple, banana, carrot: bool +box, carboard: bool = true, false +// hellope_value: int = hellope() // The procedure is ran just before `main` + +variables :: proc() { + i: int // initialized with zero value + j: int = 1 + x, y: int = 1, 2 + + // Type inference + apple, banana, 世界 := true, 123, "world" + + + // Basic Types of the Language + // + // bool + // + // i8 i16 i32 i64 i128 + // u8 u16 u32 u64 u128 + // + // f32 f64 + // + // int uint (size_of(int) == size_of(uint) == size_of(rawptr)) + // + // rawptr (equivalent to void * in C/C++) + // + // string + // + // byte - alias for u8 + // rune - alias for i32 // Unicode Codepoint + // + // "untyped" types can implicitly convert to any of the "typed" types + // Default Type + // untyped bool - bool + // untyped integer - int + // untyped float - f64 + // untyped pointer - rawptr + // untyped string - string + // untyped rune - rune/i32 + + + // Zero values + zero_numeric := 0 + zero_boolean := false + zero_pointer := null + zero_string1 := "" // Escaped string + zero_string2 := `` // Raw string + // Compound types have a different kind of zero value + + // Unary operators + // +a + // -a + // ~a + // !a + + // Binary operators + // a + b add + // a - b sub + // a ~ b xor + // a | b or + + // a * b mul + // a / b quo + // a % b mod + // a & b and + // a &~ b bitclear == a & (~b) + // a << b shl + // a >> b shr + + // a as Type // Type cast + // a transmute Type // Bit cast + + // a == b eq + // a != b ne + // a < b lt + // a > b gt + // a <= b le + // a >= b ge + +} + +procedures :: proc() { + add :: proc(x: int, y: int) -> int { + return x + y + } + print_int(add(3, 4)) // 7 + print_nl() + + add_v2 :: proc(x, y: int) -> int { + return x + y + } + + fibonacci :: proc(n: int) -> int { + if n < 2 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) + } + print_int(fibonacci(12)); nl() + + + swap_strings :: proc(x, y: string) -> (string, string) { + return y, x + } + a, b := swap_strings("Hellope\n", "World\n") + print_string(a) + print_string(b) + + a, b = b, a // Quirk of grammar the of multiple assignments + // Swap variables + print_string(a) + print_string(b) + + // Not a hint like C/C++, it's mandatory (unless it cannot do it but it will warn) + proc1 :: proc(a, b: int) #inline { + print_int(a + b) + } + proc2 :: proc(a, b: int) #no_inline { + print_int(a + b) + } + + print_int(3 ''add 4) // Infix style + print_nl() + print_int(12 'fibonacci) // Postfix style + print_nl() +} + + +TAU :: 6.28318530718 + +constants :: proc() { + TAU :: 6.28318530718 // untyped float + WORLD_JAPANESE :: "世界" // untyped string + + TAU_32 : f32 : 6.28318530718 + TAU_AS_32 :: 6.28318530718 as f32 + + PI :: TAU / 2 + + CLOSE_TO_PI :: 3 + + DIFF :: (PI - CLOSE_TO_PI) / PI // Evaluated at compile time + + a := TAU // the constant's value becomes typed as f32 + b := CLOSE_TO_PI // the constant's value becomes typed as int + c := DIFF } nl :: proc() { print_nl() } +types :: proc() { + + x: int = 123 + y := x // y: int = x + // z: f32 = x // invalid + z: f32 = x as f32 + + + ptr_z := ^z // Pascal notation + ptr_z^ = 123 // Derefence Notation + w: f32 = ptr_z^ // 123 + print_f32(z); nl() + + // ^z - pointer to z + // z^ - z from pointer + + // Implicit conversion to and from rawptr + r_ptr: rawptr = ptr_z + ptr_z = r_ptr + + + + + f32_array: [12]f32 // Array of 12 f32 + f32_array[0] = 2 + f32_array[1] = 3 + // f32_array[-1] = 2 // Error - compile time check + // f32_array[13] = 2 // Error - compile time check + f32_array_len := len(f32_array) // builtin procedure + f32_array_cap := cap(f32_array) // == len(f32_array) + + + mda: [2][3][4]int // Column-major + // mda[x][y][z] + + + + api: [2]^f32 + papi: ^[2]^f32 + + + + + f32_slice: []f32 // Slice / Array reference + f32_slice = f32_array[0:5] + f32_slice = f32_array[:5] + f32_slice = f32_array[:] // f32_array[0:len(f32_array)-1] + + f32_slice = f32_array[1:5:7] // low:1, high:5, max:7 + // len: 5-1 == 4 + // cap: 7-1 == 6 + + + + append_success := append(^f32_slice, 1) + _ = append(^f32_slice, 2) + + _ = copy(f32_array[0:2], f32_array[2:4]) // You can use memcpy/memmove if you want + + + + + + + s := "Hellope World" + sub_string: string = s[5:10] + + + + + + v0: {4}f32 // Vector of 4 f32 + v0[0] = 1 + v0[1] = 3 + v0[2] = 6 + v0[3] = 10 + + v1 := v0 + v0 // Simd Arithmetic + v1 = v1 - v0 + v1 *= v0 // i.e. hadamard product + v1 /= v0 + + // builtin procedure + v2 := swizzle(v0, 3, 2, 1, 0) // {10, 6, 3, 1} + + v3: {4}bool = v0 == v2 + // LLVM rant? + + + + + + + + Vec4 :: type {4}f32 + Array3Int :: type [3]int + + Vec3 :: type struct { + x, y, z: f32 + } + + BinaryNode :: type struct { + left, right: ^BinaryNode // same format as procedure argument + data: rawptr + } + + AddProc :: type proc(a, b: int) -> int + + Packed :: type struct #packed { + a: u8 + b: u16 + c: u32 + } + assert(size_of(Packed) == 7) // builtin procedure + { + a, b: ^BinaryNode + a = alloc(size_of(BinaryNode)) as ^BinaryNode + b = alloc(size_of(BinaryNode)) as ^BinaryNode + + c := BinaryNode{a, b, null} + c.left^.data = null + c.left.data = null // No need to deference + + dealloc(a) + dealloc(b) + } + + { + MyInt :: type int + x: int = 1 + y: MyInt = 2 + // z := x + y // Failure - types cannot implicit convert* + z := x as MyInt + y // Type cast using `as` + } + + + { + // From: Quake III Arena + Q_rsqrt :: proc(number: f32) -> f32 { + i: i32 + x2, y: f32 + THREE_HALFS :: 1.5 + + x2 = number * 0.5 + y = number + i = (^y as ^i32)^ // evil floating point bit level hacking + i = 0x5f3759df - i>>1 // what the fuck? + y = (^i as ^f32)^ + y = y * (THREE_HALFS - (x2 * y *y)) // 1st iteration + // y = y * (THREE_HALFS - (x2 * y *y)) // 2nd iteration, this can be removed + return y + } + + Q_rsqrt_v2 :: proc(number: f32) -> f32 { + THREE_HALFS :: 1.5 + + x2 := number * 0.5 + y := number + i := y transmute i32 // evil floating point bit level hacking + i = 0x5f3759df - i>>1 // what the fuck? + y = i transmute f32 + y = y * (THREE_HALFS - (x2 * y *y)) // 1st iteration + // y = y * (THREE_HALFS - (x2 * y *y)) // 2nd iteration, this can be removed + return y + } + + // NOTE(bill): transmute only works if the size of the types are equal + + /* + // in C + union { + i32 i + f32 y + } + */ + } + + { // Enumeration + Thing :: type enum { + APPLE, + FROG, + TREE, + TOMB, + } + a := Thing.APPLE + + Sized :: type enum u64 { + APPLE, + FROG, + TREE, + TOMB, + } + assert(size_of(Sized) == size_of(u64)) + + Certain :: type enum { + APPLE = 3, + FROG, + TREE = 7, + TOMB, + } + assert(Certain.TOMB == 8) + } + + { // Untagged union + BitHack :: type raw_union { + i: i32 + f: f32 + } + b: BitHack + b.f = 123 + print_int(b.i as int); print_nl() + + + + // Manually tagged union + + EntityKind :: type enum { + Invalid, + Constant, + Variable, + TypeName, + Procedure, + Builtin, + Count, + } + + Entity :: type struct { + kind: EntityKind + guid: u64 + + // Other data + + /*using*/ + data: union { + constant: struct{} + variable: struct{ + visited, is_field, used, anonymous: bool + } + procedure: struct { used: bool } + buitlin: struct { id: i32 } + } + } + + + // NOTE(bill): Tagged unions are not added yet but are planned + } + + + + { // Compound Literals + a := [3]int{1, 2, 3} + b := [3]int{} + c := [..]int{1, 2, 3} + + d := []int{1, 2, 3} // slice + + e := {4}f32{1, 2, 3, 4} + f := {4}f32{1} // broadcasts to all + // g := {4}f32{1, 2} // require either 1 or 4 elements + + Vec2 :: type {2}f32 + + h := Vec2{1, 2} + + i := Vec2{5} * h // For strong type safety + // FORENOTE: 5 * h was originally allowed but it was an edge case in the + // compiler I didn't think it was enough to justify have it it. + + print_f32(i[0]); print_rune(#rune ",") + print_f32(i[1]); print_nl() + } + + + + { // First class procedures + + do_thing :: proc(p: proc(a, b: int) -> int) { + print_int(p(3, 4)); nl() + } + + add :: proc(a, b: int) -> int { + return a + b + } + + + add_lambda := proc(a, b: int) -> int { + return a - b + } // note semicolon + + do_thing(add) + do_thing(add_lambda) + do_thing(proc(a, b: int) -> int { // Anonymous + return a * b + }) + } + + + + { // strings and runes + escaped := "Hellope World\n" + raw := `Hellope World\n` + print_string(escaped) + print_string(raw); nl() + + // Crap shader example + shader_string := +`#version 410 + +layout (location = 0) in vec3 a_position +layout (location = 1) in vec3 a_normal; +layout (location = 2) in vec2 a_tex_coord; + +out vec3 v_position; +out vec3 v_normal; +out vec2 v_tex_coord; + +uniform mat4 u_model_view; +uniform mat3 u_normal; +uniform mat4 u_proj; +uniform mat4 u_mvp; + +void main() { + v_tex_coord = a_tex_coord; + v_normal = normalize(u_normal * a_normal); + v_position = vec3(u_model_view * vec4(a_position, 1.0)); + + gl_Position = u_mvp * vec4(a_position, 1.0); +}`; + + + hearts1 := #rune "💕"; + hearts2 := #rune "\U0001f495"; // 32 bit + hearts3 := #rune "\xf0\x9f\x92\x95"; + + 㐒 := #rune "㐒"; + 㐒16 := #rune "\u4db5"; // 16 bit but will be `rune` + // String ideas "nicked" from Go, so far. I think I might change how some of it works later. + } + + + { // size, align, offset + Thing :: type struct { + a: u8; + b: u16; + c, d, e: u32; + } + + s := size_of(Thing); + a := align_of(Thing); + o := offset_of(Thing, b); + + t: Thing; + + sv := size_of_val(t); + av := align_of_val(t); + ov := offset_of_val(t.b); + } +} + +data_control :: proc() { + sum := 0 + for i := 0; i < 12; i++ { + sum += 1 + } + print_string("sum = "); print_int(sum); nl() + + sum = 1 + for ; sum < 1000000; { + sum += sum + } + print_string("sum = "); print_int(sum); nl() + + sum = 1 + for sum < 1000000 { + sum += sum + } + print_string("sum = "); print_int(sum); nl() + + // loop + // for { } == for true {} + + // Question: Should I separate all these concepts and rename it? + // + // range - iterable + // for - c style + // while + // loop - while true + + // Notes: + // conditions _must_ a boolean expression + // i++ and i-- are statements, not expressions + + + x := 2 + if x < 3 { + print_string("x < 2\n") + } + + // Unified initializer syntax - same as for statements + if x := 2; x < 3 { + print_string("x < 2\n") + } + + if x := 4; x < 3 { + print_string("Never called\n") + } else { + print_string("This is called\n") + } + + { // String comparison + a := "Hellope" + b := "World" + if a < b { + print_string("a < b\n") + } + if a != b { + print_string("a != b\n") + } + + } + + + + + { // Defer statement + defer print_string("日本語\n") + print_string("Japanese\n") + } + + { + defer print_string("1\n") + defer print_string("2\n") + defer print_string("3\n") + } + + { + prev_allocator := context.allocator + context.allocator = __default_allocator() + defer context.allocator = prev_allocator + + File :: type struct { filename: string } + FileError :: type int; + open_file :: proc(filename: string) -> (File, FileError) { + return File{}, 0 + } + close_file :: proc(f: ^File) {} + f, err := open_file("Test") + if err != 0 { + // handle error + } + defer close_file(^f) + } + + for i := 0; i < 100; i++ { + blah := new_slice(int, 100) + defer { + defer print_string("!") + defer print_string("dealloc") + delete(blah) + } + + if i == 3 { + // defers called + continue + } + + if i == 5 { + // defers called + return // End of procedure + } + + if i == 8 { + // defers called + break // never happens + } + } + + defer print_string("It'll never happen, mate 1") + print_string("It'll never happen, mate 2") + print_string("It'll never happen, mate 3") +} + + +using_fields :: proc() { + { // Everyday stuff + Vec3 :: type struct { x, y, z: f32; } + + Entity :: type struct { + name: string; + using pos: Vec3; + vel: Vec3; + } + t: Entity; + t.y = 456; + print_f32(t.y); print_nl(); + print_f32(t.pos.y); print_nl(); + print_f32(t.vel.y); print_nl(); + + + Frog :: type struct { // Subtype (kind of) + using entity: Entity; + colour: u32; + jump_height: f32; + } + + f: Frog; + f.y = 1337; + print_f32(f.y); print_nl(); + print_f32(f.pos.y); print_nl(); + print_f32(f.vel.y); print_nl(); + + + Buffalo :: type struct { + using entity: Entity; + speed: f32; + noise_level: f32; + } + } + + + { // Crazy Shit + Vec2 :: type raw_union { + using _xy: struct {x, y: f32}; + e: [2]f32; + v: {2}f32; + } + + Entity :: type struct { + using pos: ^Vec2; + name: string; + } + t: Entity; + t.pos = alloc(size_of(Vec2)) as ^Vec2; // TODO(bill): make an alloc type? i.e. new(Type)? + t.x = 123; + print_f32(t._xy.x); print_nl(); + print_f32(t.pos.x); print_nl(); + print_f32(t.pos._xy.x); print_nl(); + } +} +*/ |