aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-09-04 16:16:17 +0100
committerGinger Bill <bill@gingerbill.org>2016-09-04 16:16:17 +0100
commitc2e3c3801acd8af32fcf6ea3ad2d3a2ddc94c870 (patch)
tree4686866a14b65f9d9c4a37567c8593f7951b1881 /examples
parentcdd8eadda172b3ced7a774dfa1f22a976b3bdb7f (diff)
Type match statement for tagged unions
Diffstat (limited to 'examples')
-rw-r--r--examples/demo.odin748
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();
+ }
+}
+*/