aboutsummaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-10-26 10:40:17 +0100
committergingerBill <bill@gingerbill.org>2019-10-26 10:40:17 +0100
commitc60fb10a6a0b668e9dab7e4cb899664f5e32419e (patch)
tree35f59e5242c9a21c20b00c30402239460fb2c4ae /misc
parent7140f4291546748adf2ddb977f3605f7aab31856 (diff)
Move old demos and old stuff to /misc
Diffstat (limited to 'misc')
-rw-r--r--misc/old_demos/demo001.odin337
-rw-r--r--misc/old_demos/demo002.odin879
-rw-r--r--misc/old_demos/demo004.odin66
-rw-r--r--misc/old_demos/demo005.odin283
-rw-r--r--misc/old_demos/demo006.odin310
-rw-r--r--misc/old_demos/demo007.odin570
-rw-r--r--misc/old_demos/demo008.odin778
-rw-r--r--misc/old_demos/old_runtime.odin412
-rw-r--r--misc/old_stuff/demo_backup.odin430
-rw-r--r--misc/shell.bat4
10 files changed, 4067 insertions, 2 deletions
diff --git a/misc/old_demos/demo001.odin b/misc/old_demos/demo001.odin
new file mode 100644
index 000000000..a3aea1cb7
--- /dev/null
+++ b/misc/old_demos/demo001.odin
@@ -0,0 +1,337 @@
+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();
+ bounds_checking();
+ type_introspection();
+ any_type();
+ crazy_introspection();
+ namespaces_and_files();
+ miscellany();
+
+ /*
+ ht.run();
+ game.run();
+ {
+ init :: proc(c: ^pn.Core) {}
+ step :: proc(c: ^pn.Core) {}
+
+ pn.run(init, step);
+ }
+ */
+}
+
+struct_padding :: proc() {
+ {
+ A :: struct {
+ a: u8,
+ b: u32,
+ c: u16,
+ }
+
+ B :: struct {
+ a: [7]u8,
+ b: [3]u16,
+ c: u8,
+ d: u16,
+ }
+
+ fmt.println("size_of(A):", size_of(A));
+ fmt.println("size_of(B):", size_of(B));
+
+ // n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html
+ }
+ {
+ A :: struct #ordered {
+ a: u8,
+ b: u32,
+ c: u16,
+ }
+
+ B :: struct #ordered {
+ a: [7]u8,
+ b: [3]u16,
+ c: u8,
+ d: u16,
+ }
+
+ fmt.println("size_of(A):", size_of(A));
+ fmt.println("size_of(B):", size_of(B));
+
+ // C-style structure layout
+ }
+ {
+ A :: struct #packed {
+ a: u8,
+ b: u32,
+ c: u16,
+ }
+
+ B :: struct #packed {
+ a: [7]u8,
+ b: [3]u16,
+ c: u8,
+ d: u16,
+ }
+
+ fmt.println("size_of(A):", size_of(A));
+ fmt.println("size_of(B):", size_of(B));
+
+ // Useful for explicit layout
+ }
+
+ // Member sorting by priority
+ // Alignment desc.
+ // Size desc.
+ // source order asc.
+
+ /*
+ A :: struct {
+ a: u8
+ b: u32
+ c: u16
+ }
+
+ B :: struct {
+ a: [7]u8
+ b: [3]u16
+ c: u8
+ d: u16
+ }
+
+ Equivalent too
+
+ A :: struct #ordered {
+ b: u32
+ c: u16
+ a: u8
+ }
+
+ B :: struct #ordered {
+ b: [3]u16
+ d: u16
+ a: [7]u8
+ c: u8
+ }
+ */
+}
+
+bounds_checking :: proc() {
+ x: [4]int;
+ // x[-1] = 0; // Compile Time
+ // x[4] = 0; // Compile Time
+
+ {
+ a, b := -1, 4;
+ // x[a] = 0; // Runtime Time
+ // x[b] = 0; // Runtime Time
+ }
+
+ // Works for arrays, strings, slices, and related procedures & operations
+
+ {
+ base: [10]int;
+ s := base[2..6];
+ a, b := -1, 6;
+
+ #no_bounds_check {
+ s[a] = 0;
+ // #bounds_check s[b] = 0;
+ }
+
+ #no_bounds_check
+ if s[a] == 0 {
+ // Do whatever
+ }
+
+ // Bounds checking can be toggled explicit
+ // on a per statement basis.
+ // _any statement_
+ }
+}
+
+type_introspection :: proc() {
+ {
+ info: ^Type_Info;
+ x: int;
+
+ info = type_info_of(int); // by type
+ info = type_info_of(x); // by value
+ // See: runtime.odin
+
+ match i in info.variant {
+ case Type_Info_Integer:
+ fmt.println("integer!");
+ case Type_Info_Float:
+ fmt.println("float!");
+ case:
+ fmt.println("potato!");
+ }
+
+ // Unsafe cast
+ integer_info := cast(^Type_Info_Integer)cast(rawptr)info;
+ }
+
+ {
+ Vector2 :: struct { x, y: f32 }
+ Vector3 :: struct { x, y, z: f32 }
+
+ v1: Vector2;
+ v2: Vector3;
+ v3: Vector3;
+
+ 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);
+
+ fmt.println();
+ fmt.print("Type of v2 is:\n\t", t2);
+
+ fmt.println("\n");
+ fmt.println("t1 == t2:", t1 == t2);
+ fmt.println("t2 == t3:", t2 == t3);
+ }
+}
+
+any_type :: proc() {
+ a: any;
+
+ x: int = 123;
+ y: f64 = 6.28;
+ z: string = "Yo-Yo Ma";
+ // All types can be implicit cast to `any`
+ a = x;
+ a = y;
+ a = z;
+ a = a; // This the "identity" type, it doesn't get converted
+
+ a = 123; // Literals are copied onto the stack first
+
+ // any has two members
+ // data - rawptr to the data
+ // type_info - pointer to the type info
+
+ fmt.println(x, y, z);
+ // See: fmt.odin
+ // For variadic any procedures in action
+}
+
+crazy_introspection :: proc() {
+ {
+ Fruit :: enum {
+ APPLE,
+ BANANA,
+ GRAPE,
+ MELON,
+ PEACH,
+ TOMATO,
+ }
+
+ s: string;
+ // s = enum_to_string(Fruit.PEACH);
+ fmt.println(s);
+
+ f := Fruit.GRAPE;
+ // s = enum_to_string(f);
+ fmt.println(s);
+
+ fmt.println(f);
+ // See: runtime.odin
+ }
+
+
+ {
+ // NOTE(bill): This is not safe code and I would not recommend this at all
+ // I'd recommend you use `match type` to get the subtype rather than
+ // casting pointers
+
+ Fruit :: enum {
+ APPLE,
+ BANANA,
+ GRAPE,
+ MELON,
+ PEACH,
+ TOMATO,
+ }
+
+ 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 in info.values {
+ fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
+ }
+ fmt.printf("}\n");
+
+ // NOTE(bill): look at that type-safe printf!
+ }
+
+ {
+ Vector3 :: struct {x, y, z: f32}
+
+ a := Vector3{x = 1, y = 4, z = 9};
+ fmt.println(a);
+ b := Vector3{x = 9, y = 3, z = 1};
+ fmt.println(b);
+
+ // NOTE(bill): See fmt.odin
+ }
+
+ // n.b. This pretty much "solves" serialization (to strings)
+}
+
+// #import "test.odin"
+
+namespaces_and_files :: proc() {
+
+ // test.thing()
+ // test.format.println()
+ // test.println()
+ /*
+ // Non-exporting import
+ #import "file.odin"
+ #import "file.odin" as file
+ #import "file.odin" as .
+ #import "file.odin" as _
+
+ // Exporting import
+ #include "file.odin"
+ */
+
+ // Talk about scope rules and diagram
+}
+
+miscellany :: proc() {
+ /*
+ win32 `__imp__` prefix
+ #dll_import
+ #dll_export
+
+ Change exported name/symbol for linking
+ #link_name
+
+ Custom calling conventions
+ #stdcall
+ #fastcall
+
+ Runtime stuff
+ #shared_global_scope
+ */
+
+ // assert(false)
+ // #assert(false)
+ // panic("Panic message goes here")
+}
+
+
+
+
diff --git a/misc/old_demos/demo002.odin b/misc/old_demos/demo002.odin
new file mode 100644
index 000000000..a790aadf3
--- /dev/null
+++ b/misc/old_demos/demo002.odin
@@ -0,0 +1,879 @@
+// Demo 002
+export "core:fmt.odin";
+export "core:math.odin";
+export "core:mem.odin";
+// export "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 :: 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 :: enum {
+ APPLE, // 0
+ BANANA, // 1
+ PEAR, // 2
+ };
+
+ f := Fruit.APPLE;
+ // g12: int = Fruit.BANANA
+ g: int = cast(int)Fruit.BANANA;
+ // However, you can use enums are index values as _any_ integer allowed
+ }
+ {
+ Fruit1 :: enum int {
+ APPLE,
+ BANANA,
+ PEAR,
+ }
+
+ Fruit2 :: enum u8 {
+ APPLE,
+ BANANA,
+ PEAR,
+ }
+
+ Fruit3 :: 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 arg, i in args {
+ if i > 0 do print(", ");
+ print(arg);
+ }
+ }
+
+ print_ints(); // nl()
+ print_ints(1); nl();
+ print_ints(1, 2, 3); nl();
+
+ print_prefix_f32s :: proc(prefix: string, args: ..f32) {
+ print(prefix);
+ print(": ");
+ for arg, i in args {
+ if i > 0 do print(", ");
+ print(arg);
+ }
+ }
+
+ 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 := make([]int, 12);
+ c := make([]int, 12, 16);
+
+ defer free(a);
+ defer free(b);
+ defer free(c);
+
+ // NOTE(bill): These use the current context's allocator not the default allocator
+ // see runtime.odin
+
+ // Q: Should this be `free` rather than `free` and should I overload it for slices too?
+
+ push_allocator default_allocator() {
+ a := new(int);
+ defer free(a);
+
+ // Do whatever
+
+ }
+ }
+
+ {
+ a: int = 123;
+ b: type_of(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 = nil;
+ y := x+100;
+ z := 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(min(a, b)); nl();
+ print(max(a, b)); nl();
+ print(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(C); nl();
+ print(D); nl();
+ print(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("1!\n");
+ // break by default
+
+ case 2:
+ s := "2!\n"; // Each case has its own scope
+ print(s);
+ break; // explicit break
+
+ case 3, 4: // multiple cases
+ print("3 or 4!\n");
+
+ case 5:
+ print("5!\n");
+ fallthrough; // explicit fallthrough
+
+ case:
+ print("default!\n");
+ }
+
+
+
+ match x := 1.5; x {
+ case 1.5:
+ print("1.5!\n");
+ // break by default
+ case TAU:
+ print("τ!\n");
+ case:
+ print("default!\n");
+ }
+
+
+
+ match x := "Hello"; x {
+ case "Hello":
+ print("greeting\n");
+ // break by default
+ case "Goodbye":
+ print("farewell\n");
+ case:
+ print("???\n");
+ }
+
+
+
+
+
+
+ a := 53;
+ match {
+ case a == 1:
+ print("one\n");
+ case a == 2:
+ print("a couple\n");
+ case a < 7, a == 7:
+ print("a few\n");
+ case a < 12: // intentional bug
+ print("several\n");
+ case a >= 12 && a < 100:
+ print("dozens\n");
+ case a >= 100 && a < 1000:
+ print("hundreds\n");
+ case:
+ print("a fuck ton\n");
+ }
+
+ // Identical to this
+
+ b := 53;
+ if b == 1 {
+ print("one\n");
+ } else if b == 2 {
+ print("a couple\n");
+ } else if b < 7 || b == 7 {
+ print("a few\n");
+ } else if b < 12 { // intentional bug
+ print("several\n");
+ } else if b >= 12 && b < 100 {
+ print("dozens\n");
+ } else if b >= 100 && b < 1000 {
+ print("hundreds\n");
+ } else {
+ print("a fuck ton\n");
+ }
+
+ // However, match statements allow for `break` and `fallthrough` unlike
+ // an if statement
+ }
+}
+
+Vector3 :: struct {x, y, z: f32}
+
+print_floats :: proc(args: ..f32) {
+ for arg, i in args {
+ if i > 0 do print(", ");
+ print(arg);
+ }
+ println();
+}
+
+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 :: struct {
+ Guid :: int
+ Nested :: struct {
+ MyInt :: 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(e.guid as int); nl()
+ print(e.name); nl()
+ }
+
+ {
+ using e: Entity
+ guid = 78456
+ name = "Thing"
+
+ print(e.guid as int); nl()
+ print(e.name); nl()
+ }
+ }
+
+ {
+ Entity :: struct {
+ Guid :: int
+ Nested :: struct {
+ MyInt :: 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 :: struct {
+ position: Vector3
+ }
+
+ print_pos_1 :: proc(entity: ^Entity) {
+ print("print_pos_1: ");
+ print_floats(entity.position.x, entity.position.y, entity.position.z);
+ }
+
+ print_pos_2 :: proc(entity: ^Entity) {
+ using entity;
+ print("print_pos_2: ");
+ print_floats(position.x, position.y, position.z);
+ }
+
+ print_pos_3 :: proc(using entity: ^Entity) {
+ print("print_pos_3: ");
+ print_floats(position.x, position.y, position.z);
+ }
+
+ print_pos_4 :: proc(using entity: ^Entity) {
+ using position;
+ print("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 :: struct {
+ position: Vector3,
+ }
+
+ Frog :: 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 :: struct {
+ position: Vector3
+ }
+
+ Frog :: struct {
+ using entity: Entity,
+ jump_height: f32,
+ }
+
+ f: Frog;
+ f.position = Vector3{1, 2, 3};
+
+
+ print_pos :: proc(using entity: Entity) {
+ print("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 :: struct {
+ position: Vector3,
+ }
+
+ Frog :: 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("print_pos: ");
+ print_floats(position.x, position.y, position.z);
+ }
+
+ print_pos(f.entity);
+ // print_pos(^f);
+ // print_pos(f);
+ }
+
+ {
+ // More efficient subtyping
+
+ Entity :: struct {
+ position: Vector3,
+ }
+
+ Frog :: 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^ += 1;
+ 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 :: struct {
+ position: Vector3,
+ }
+
+ Frog :: struct {
+ jump_height: f32,
+ using entity: Entity,
+ }
+
+ f: Frog;
+ f.jump_height = 564;
+ e := ^f.entity;
+
+ frog := down_cast(^Frog)e;
+ print("down_cast: ");
+ print(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 :: struct {
+ position: Vector3,
+ }
+ Climber :: struct {
+ speed: f32,
+ }
+
+ Frog :: struct {
+ using entity: Entity,
+ using climber: Climber,
+ }
+ }
+}
+
+tagged_unions :: proc() {
+ {
+ Entity_Kind :: enum {
+ INVALID,
+ FROG,
+ GIRAFFE,
+ HELICOPTER,
+ }
+
+ Entity :: struct {
+ kind: Entity_Kind
+ using data: struct #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 = Entity_Kind.FROG;
+ e.frog.jump_height = 12;
+
+ 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
+ }
+
+ {
+ 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};
+
+ f1: Frog = Frog{12, 0xff9900};
+ f2: Entity = Frog{12, 0xff9900}; // Implicit cast
+ f3 := cast(Entity)Frog{12, 0xff9900}; // 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 x in &f {
+ case Frog:
+ print("Frog!\n");
+ print(x.jump_height); nl();
+ // x.jump_height = 3;
+ print(x.jump_height); nl();
+ case Giraffe:
+ print("Giraffe!\n");
+ case Helicopter:
+ print("ROFLCOPTER!\n");
+ case:
+ print("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 := cast(^Frog)^f; // Unsafe
+ // print(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 :: struct {};
+ Scope :: struct {};
+ Token :: struct {};
+ AstNode :: struct {};
+ ExactValue :: struct {};
+
+ Entity_Kind :: enum {
+ Invalid,
+ Constant,
+ Variable,
+ Using_Variable,
+ TypeName,
+ Procedure,
+ Builtin,
+ Count,
+ }
+
+ Guid :: i64;
+ Entity :: struct {
+
+ kind: Entity_Kind,
+ guid: Guid,
+
+ scope: ^Scope,
+ token: Token,
+ type_: ^Type,
+
+ using data: struct #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
+ },
+ Using_Variable: 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 :: struct {};
+ Scope :: struct {};
+ Token :: struct {};
+ AstNode :: struct {};
+ ExactValue :: struct {};
+
+
+ Guid :: i64;
+ Entity_Base :: struct {
+ }
+
+
+ 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,
+
+ variant: union {Constant, Variable, Using_Variable, TypeName, Procedure, Builtin},
+ }
+
+ e := Entity{
+ variant = Variable{
+ 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 :: struct #raw_union {
+ using xy_: struct { x, y: f32 },
+ e: [2]f32,
+ v: [vector 2]f32,
+ }
+
+ Vector3 :: struct #raw_union {
+ using xyz_: struct { x, y, z: f32 },
+ xy: Vector2,
+ e: [3]f32,
+ v: [vector 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() { println(); }
diff --git a/misc/old_demos/demo004.odin b/misc/old_demos/demo004.odin
new file mode 100644
index 000000000..c9acc9a15
--- /dev/null
+++ b/misc/old_demos/demo004.odin
@@ -0,0 +1,66 @@
+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([]u8)s));
+
+ // utf8.odin
+ // hash.odin
+ // - crc, fnv, fnva, murmur
+ // mem.odin
+ // - Custom allocators
+ // - Helpers
+ }
+
+ {
+ arena: mem.Arena;
+ mem.init_arena_from_context(&arena, mem.megabytes(16)); // Uses default allocator
+ defer mem.destroy_arena(&arena);
+
+ push_allocator mem.arena_allocator(&arena) {
+ x := new(int);
+ x^ = 1337;
+
+ fmt.println(x^);
+ }
+
+ /*
+ push_allocator x {
+ ..
+ }
+
+ is equivalent to:
+
+ {
+ prev_allocator := __context.allocator
+ __context.allocator = x
+ defer __context.allocator = prev_allocator
+
+ ..
+ }
+ */
+
+ // You can also "push" a context
+
+ c := context; // Create copy of the allocator
+ c.allocator = mem.arena_allocator(&arena);
+
+ push_context c {
+ x := new(int);
+ x^ = 365;
+
+ fmt.println(x^);
+ }
+ }
+
+ // Backend improvements
+ // - Minimal dependency building (only build what is needed)
+ // - Numerous bugs fixed
+ // - Mild parsing recovery after bad syntax error
+}
diff --git a/misc/old_demos/demo005.odin b/misc/old_demos/demo005.odin
new file mode 100644
index 000000000..c8273b03b
--- /dev/null
+++ b/misc/old_demos/demo005.odin
@@ -0,0 +1,283 @@
+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();
+ procedure_overloading();
+}
+
+syntax :: proc() {
+ // Cyclic type checking
+ // Uncomment to see the error
+ // A :: struct {b: B};
+ // B :: struct {a: A};
+
+ x: int;
+ y := cast(f32)x;
+ z := transmute(u32)y;
+ // down_cast, union_cast are similar too
+
+
+
+ // Basic directives
+ fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure);
+ // NOTE: new and improved `printf`
+ // TODO: It does need accurate float printing
+
+
+
+ // record fields use the same syntax a procedure signatures
+ Thing1 :: struct {
+ x: f32,
+ y: int,
+ z: ^[]int,
+ };
+ Thing2 :: struct {x: f32, y: int, z: ^[]int};
+
+ // Slice interals are now just a `ptr+len+cap`
+ slice: []int; #assert(size_of(slice) == 3*size_of(int));
+
+ // Helper type - Help the reader understand what it is quicker
+ My_Int :: #type int;
+ My_Proc :: #type proc(int) -> f32;
+
+
+ // All declarations with : are either variable or constant
+ // To make these declarations syntactically consistent
+ v_variable := 123;
+ c_constant :: 123;
+ c_type1 :: int;
+ c_type2 :: []int;
+ c_proc :: proc() { /* code here */ };
+
+
+/*
+ x += 1;
+ x -= 1;
+ // ++ and -- have been removed
+ // x++;
+ // x--;
+ // Question: Should they be added again?
+ // They were removed as they are redundant and statements, not expressions
+ // like in C/C++
+*/
+
+ // You can now build files as a `.dll`
+ // `odin build_dll demo.odin`
+
+
+ // New vector syntax
+ u, v: [vector 3]f32;
+ v[0] = 123;
+ v.x = 123; // valid for all vectors with count 1 to 4
+
+ // Next part
+ prefixes();
+}
+
+
+Prefix_Type :: struct {x: int, y: f32, z: rawptr};
+
+#thread_local my_tls: Prefix_Type;
+
+prefixes :: proc() {
+ using var: Prefix_Type;
+ var.x = 123;
+ x = 123;
+
+
+ foo :: proc(using pt: Prefix_Type) {
+ }
+
+
+
+ // Same as C99's `restrict`
+ bar :: proc(#no_alias a, b: ^int) {
+ // Assumes a never equals b so it can perform optimizations with that fact
+ }
+
+
+ when_statements();
+}
+
+
+
+
+
+when_statements :: proc() {
+ X :: 123 + 12;
+ Y :: X/5;
+ COND :: Y > 0;
+
+ when COND {
+ fmt.println("Y > 0");
+ } else {
+ fmt.println("Y <= 0");
+ }
+
+
+ when false {
+ this_code_does_not_exist(123, 321);
+ but_its_syntax_is_valid();
+ x :: ^^^^int;
+ }
+
+ foreign_procedures();
+}
+
+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() {
+ 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
+
+ // See sys/windows.odin for more examples
+
+ special_expressions();
+}
+
+special_expressions :: proc() {
+/*
+ // Block expression
+ x := {
+ a: f32 = 123;
+ b := a-123;
+ c := b/a;
+ give c;
+ }; // semicolon is required as it's an expression
+
+ y := if x < 50 {
+ give x;
+ } else {
+ // TODO: Type cohesion is not yet finished
+ give 123;
+ }; // semicolon is required as it's an expression
+*/
+
+ // This is allows for inline blocks of code and will be a useful feature to have when
+ // macros will be implemented into the language
+
+ loops();
+}
+
+loops :: proc() {
+ // The C-style for loop
+ for i := 0; i < 123; i += 1 {
+ break;
+ }
+ for i := 0; i < 123; {
+ break;
+ }
+ for false {
+ break;
+ }
+ for {
+ break;
+ }
+
+ for i in 0..123 { // 123 exclusive
+ }
+
+ for i in 0..123-1 { // 122 inclusive
+ }
+
+ for val, idx in 12..16 {
+ fmt.println(val, idx);
+ }
+
+ 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 {
+ // ignore the value and just iterate across it
+ }
+
+
+
+ name := "你好,世界";
+ fmt.println(name);
+ for r in name {
+ #assert(type_of(r) == rune);
+ fmt.printf("%r\n", r);
+ }
+
+ when false {
+ for i, size := 0; i < name.count; i += size {
+ r: rune;
+ r, size = utf8.decode_rune(name[i..]);
+ fmt.printf("%r\n", r);
+ }
+ }
+
+ procedure_overloading();
+}
+
+
+procedure_overloading :: proc() {
+ THINGF :: 14451.1;
+ THINGI :: 14451;
+
+ foo :: proc() {
+ fmt.printf("Zero args\n");
+ }
+ foo :: proc(i: int) {
+ fmt.printf("int arg, i=%d\n", i);
+ }
+ foo :: proc(f: f64) {
+ i := cast(int)f;
+ fmt.printf("f64 arg, f=%d\n", i);
+ }
+
+ foo();
+ foo(THINGF);
+ // foo(THINGI); // 14451 is just a number so it could go to either procedures
+ foo(cast(int)THINGI);
+
+
+
+
+ foo :: proc(x: ^i32) -> (int, int) {
+ fmt.println("^int");
+ return 123, cast(int)(x^);
+ }
+ foo :: proc(x: rawptr) {
+ fmt.println("rawptr");
+ }
+
+
+ a: i32 = 123;
+ b: f32;
+ c: rawptr;
+ fmt.println(foo(&a));
+ foo(&b);
+ foo(c);
+ // foo(nil); // nil could go to numerous types thus the ambiguity
+
+ f: proc();
+ f = foo; // The correct `foo` to chosen
+ f();
+
+
+ // See math.odin and atomic.odin for more examples
+}
diff --git a/misc/old_demos/demo006.odin b/misc/old_demos/demo006.odin
new file mode 100644
index 000000000..c2f64151b
--- /dev/null
+++ b/misc/old_demos/demo006.odin
@@ -0,0 +1,310 @@
+// 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 "core:fmt.odin";
+import "core:os.odin";
+import "core:math.odin";
+
+
+main :: proc() {
+when true {
+/*
+ Added:
+ * Unexported entities and fields using an underscore prefix
+ - See `sync.odin` and explain
+
+ Removed:
+ * Maybe/option types
+ * Remove `type` keyword and other "reserved" keywords
+ * ..< and .. removed and replace with .. (half-closed range)
+
+ Changed:
+ * `#assert` and `assert` return the value of the condition for semantic reasons
+ * thread_local -> #thread_local
+ * #include -> #load
+ * Files only get checked if they are actually used
+ * match x in y {} // For type match statements
+ * Version numbering now starts from 0.1.0 and uses the convention:
+ - major.minor.patch
+ * Core library additions to Windows specific stuff
+ */
+
+ {
+ Fruit :: enum {
+ APPLE,
+ BANANA,
+ COCONUT,
+ }
+ fmt.println(Fruit.names);
+ }
+
+ {
+ A :: struct {x, y: f32};
+ B :: struct #align 16 {x, y: f32};
+ fmt.println("align_of(A) =", align_of(A));
+ fmt.println("align_of(B) =", align_of(B));
+ }
+
+ {
+ // Removal of ..< and ..
+ for i in 0..16 {
+ }
+ // Is similar to
+ for i := 0; i < 16; i += 1 {
+ }
+ }
+
+ {
+ thing: for i in 0..10 {
+ for j in i+1..10 {
+ if j == 2 {
+ fmt.println(i, j);
+ continue thing;
+ }
+ if j == 3 {
+ break thing;
+ }
+ }
+ }
+
+ // Works with, `for`, `for in`, `match`, `match in`
+ // NOTE(bill): This solves most of the problems I need `goto` for
+ }
+
+ {
+ 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 {
+ case int, f32:
+ fmt.println("It's an int or f32");
+ break foo;
+ }
+ }
+
+ {
+ cond := true;
+ x: int;
+ if cond {
+ x = 3;
+ } else {
+ x = 4;
+ }
+
+
+ // Ternary operator
+ y := cond ? 3 : 4;
+
+ FOO :: true ? 123 : 432; // Constant ternary expression
+ fmt.println("Ternary values:", y, FOO);
+ }
+
+ {
+ // Slices now store a capacity
+ buf: [256]u8;
+ s: []u8;
+ s = buf[..0]; // == buf[0..0];
+ 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 =", len(s));
+ fmt.println("capacity =", cap(s));
+ fmt.println(s);
+
+ clear(&s); // Sets count to zero
+ }
+
+ {
+ Foo :: struct {
+ x, y, z: f32,
+ ok: bool,
+ flags: u32,
+ }
+ foo_array: [256]Foo;
+ foo_as_bytes: []u8 = mem.slice_to_bytes(foo_array[..]);
+ // Useful for things like
+ // os.write(handle, foo_as_bytes);
+
+ 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);
+ }
+
+ {
+ Vec3 :: [vector 3]f32;
+
+ x := Vec3{1, 2, 3};
+ y := Vec3{4, 5, 6};
+ fmt.println(x < y);
+ fmt.println(x + y);
+ fmt.println(x - y);
+ fmt.println(x * y);
+ fmt.println(x / y);
+
+ for i in x {
+ fmt.println(i);
+ }
+
+ #assert(size_of([vector 7]bool) >= size_of([7]bool));
+ #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 `string`
+
+ data: [256]u8;
+ str := fmt.bprintf(data[..], "Hellope %d %s %c", 123, "others", '!');
+ fmt.println(str);
+ }
+
+ {
+ x: [dynamic]f64;
+ 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
+
+ for p, i in x {
+ if i > 0 { fmt.print(", "); }
+ fmt.print(p);
+ }
+ fmt.println();
+ }
+
+ {
+ // Dynamic array "literals"
+ 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);
+ fmt.println(x);
+ }
+
+ {
+ m: map[f32]int;
+ reserve(&m, 16);
+ defer free(m);
+
+ m[1.0] = 1278;
+ m[2.0] = 7643;
+ m[3.0] = 564;
+ _, ok := m[3.0];
+ c := m[3.0];
+ assert(ok && c == 564);
+
+ fmt.print("map[");
+ i := 0;
+ for val, key in m {
+ if i > 0 {
+ fmt.print(", ");
+ }
+ fmt.printf("%v=%v", key, val);
+ i += 1;
+ }
+ fmt.println("]");
+ }
+ {
+ m := map[string]u32{
+ "a" = 56,
+ "b" = 13453,
+ "c" = 7654,
+ };
+ defer free(m);
+
+ c := m["c"];
+ _, ok := m["c"];
+ assert(ok && c == 7654);
+ fmt.println(m);
+
+ delete(&m, "c"); // deletes entry with key "c"
+ _, found := m["c"];
+ assert(!found);
+
+ fmt.println(m);
+ clear(&m);
+ fmt.println(m);
+
+ // NOTE: Fixed size maps are planned but we have not yet implemented
+ // them as we have had no need for them as of yet
+ }
+
+ {
+ Vector3 :: struct{x, y, z: f32};
+ Quaternion :: struct{x, y, z, w: f32};
+
+ // 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,
+ using position: Vector3,
+ orientation: Quaternion,
+ flags: u32,
+
+ variant: union { Frog, Door, Map },
+ }
+
+ entity: Entity;
+ entity.id = 1337;
+ // implicit conversion from variant to base type
+ entity.variant = Frog{
+ ribbit_volume = 0.5,
+ jump_height = 2.1,
+ /*other data */
+ };
+
+ entity.name = "Frank";
+ entity.position = Vector3{1, 4, 9};
+
+ match e in entity.variant {
+ case Frog:
+ fmt.println("Ribbit");
+ case Door:
+ fmt.println("Creak");
+ case Map:
+ fmt.println("Rustle");
+ case:
+ fmt.println("Just a normal entity");
+ }
+
+ 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 = entity.variant.(Frog);
+ frog, _ = entity.variant.(Frog); // ignore error and force cast
+ }
+}
+}
+
diff --git a/misc/old_demos/demo007.odin b/misc/old_demos/demo007.odin
new file mode 100644
index 000000000..d19446ecb
--- /dev/null
+++ b/misc/old_demos/demo007.odin
@@ -0,0 +1,570 @@
+import "core:fmt.odin"
+import "core:strconv.odin"
+import "core:mem.odin"
+import "core:bits.odin"
+import "core:hash.odin"
+import "core:math.odin"
+import "core:os.odin"
+import "core:raw.odin"
+import "core:sort.odin"
+import "core:strings.odin"
+import "core:types.odin"
+import "core:utf16.odin"
+import "core:utf8.odin"
+
+when ODIN_OS == "windows" {
+ import "core:atomics.odin"
+ import "core:opengl.odin"
+ import "core:thread.odin"
+ import win32 "core:sys/windows.odin"
+}
+
+general_stuff :: proc() {
+ { // `do` for inline statmes rather than block
+ foo :: proc() do fmt.println("Foo!");
+ if false do foo();
+ for false do foo();
+ when false do foo();
+
+ if false do foo();
+ else do foo();
+ }
+
+ { // Removal of `++` and `--` (again)
+ x: int;
+ x += 1;
+ x -= 1;
+ }
+ { // Casting syntaxes
+ i := i32(137);
+ ptr := &i;
+
+ fp1 := (^f32)(ptr);
+ // ^f32(ptr) == ^(f32(ptr))
+ fp2 := cast(^f32)ptr;
+
+ f1 := (^f32)(ptr)^;
+ f2 := (cast(^f32)ptr)^;
+
+ // Questions: Should there be two ways to do it?
+ }
+
+ /*
+ * Remove *_val_of built-in procedures
+ * size_of, align_of, offset_of
+ * type_of, type_info_of
+ */
+
+ { // `expand_to_tuple` built-in procedure
+ Foo :: struct {
+ x: int,
+ b: bool,
+ }
+ f := Foo{137, true};
+ x, b := expand_to_tuple(f);
+ fmt.println(f);
+ fmt.println(x, b);
+ fmt.println(expand_to_tuple(f));
+ }
+
+ {
+ // .. half-closed range
+ // .. open range
+
+ for in 0..2 {} // 0, 1
+ for in 0..2 {} // 0, 1, 2
+ }
+}
+
+default_struct_values :: proc() {
+ {
+ Vector3 :: struct {
+ x: f32,
+ y: f32,
+ z: f32,
+ }
+ v: Vector3;
+ fmt.println(v);
+ }
+ {
+ // Default values must be constants
+ Vector3 :: struct {
+ x: f32 = 1,
+ y: f32 = 4,
+ z: f32 = 9,
+ }
+ v: Vector3;
+ fmt.println(v);
+
+ v = Vector3{};
+ fmt.println(v);
+
+ // Uses the same semantics as a default values in a procedure
+ v = Vector3{137};
+ fmt.println(v);
+
+ v = Vector3{z = 137};
+ fmt.println(v);
+ }
+
+ {
+ Vector3 :: struct {
+ x := 1.0,
+ y := 4.0,
+ z := 9.0,
+ }
+ stack_default: Vector3;
+ stack_literal := Vector3{};
+ heap_one := new(Vector3); defer free(heap_one);
+ heap_two := new_clone(Vector3{}); defer free(heap_two);
+
+ fmt.println("stack_default - ", stack_default);
+ fmt.println("stack_literal - ", stack_literal);
+ fmt.println("heap_one - ", heap_one^);
+ fmt.println("heap_two - ", heap_two^);
+
+
+ N :: 4;
+ stack_array: [N]Vector3;
+ heap_array := new([N]Vector3); defer free(heap_array);
+ heap_slice := make([]Vector3, N); defer free(heap_slice);
+ fmt.println("stack_array[1] - ", stack_array[1]);
+ fmt.println("heap_array[1] - ", heap_array[1]);
+ fmt.println("heap_slice[1] - ", heap_slice[1]);
+ }
+}
+
+
+
+
+union_type :: proc() {
+ {
+ val: union{int, bool};
+ val = 137;
+ if i, ok := val.(int); ok {
+ fmt.println(i);
+ }
+ val = true;
+ fmt.println(val);
+
+ val = nil;
+
+ switch v in val {
+ case int: fmt.println("int", v);
+ case bool: fmt.println("bool", v);
+ case: fmt.println("nil");
+ }
+ }
+ {
+ // There is a duality between `any` and `union`
+ // An `any` has a pointer to the data and allows for any type (open)
+ // A `union` has as binary blob to store the data and allows only certain types (closed)
+ // The following code is with `any` but has the same syntax
+ val: any;
+ val = 137;
+ if i, ok := val.(int); ok {
+ fmt.println(i);
+ }
+ val = true;
+ fmt.println(val);
+
+ val = nil;
+
+ switch v in val {
+ case int: fmt.println("int", v);
+ case bool: fmt.println("bool", v);
+ case: fmt.println("nil");
+ }
+ }
+
+ Vector3 :: struct {x, y, z: f32};
+ Quaternion :: struct {x, y, z: f32, w: f32 = 1};
+
+ // More realistic examples
+ {
+ // NOTE(bill): For the above basic examples, you may not have any
+ // particular use for it. However, my main use for them is not for these
+ // simple cases. My main use is for hierarchical types. Many prefer
+ // subtyping, embedding the base data into the derived types. Below is
+ // an example of this for a basic game Entity.
+
+ Entity :: struct {
+ id: u64,
+ name: string,
+ position: Vector3,
+ orientation: Quaternion,
+
+ derived: any,
+ }
+
+ Frog :: struct {
+ using entity: Entity,
+ jump_height: f32,
+ }
+
+ Monster :: struct {
+ using entity: Entity,
+ is_robot: bool,
+ is_zombie: bool,
+ }
+
+ // See `parametric_polymorphism` procedure for details
+ new_entity :: proc(T: type) -> ^Entity {
+ t := new(T);
+ t.derived = t^;
+ return t;
+ }
+
+ entity := new_entity(Monster);
+
+ switch e in entity.derived {
+ case Frog:
+ fmt.println("Ribbit");
+ case Monster:
+ if e.is_robot do fmt.println("Robotic");
+ if e.is_zombie do fmt.println("Grrrr!");
+ }
+ }
+
+ {
+ // NOTE(bill): A union can be used to achieve something similar. Instead
+ // of embedding the base data into the derived types, the derived data
+ // in embedded into the base type. Below is the same example of the
+ // basic game Entity but using an union.
+
+ Entity :: struct {
+ id: u64,
+ name: string,
+ position: Vector3,
+ orientation: Quaternion,
+
+ derived: union {Frog, Monster},
+ }
+
+ Frog :: struct {
+ using entity: ^Entity,
+ jump_height: f32,
+ }
+
+ Monster :: struct {
+ using entity: ^Entity,
+ is_robot: bool,
+ is_zombie: bool,
+ }
+
+ // See `parametric_polymorphism` procedure for details
+ new_entity :: proc(T: type) -> ^Entity {
+ t := new(Entity);
+ t.derived = T{entity = t};
+ return t;
+ }
+
+ entity := new_entity(Monster);
+
+ switch e in entity.derived {
+ case Frog:
+ fmt.println("Ribbit");
+ case Monster:
+ if e.is_robot do fmt.println("Robotic");
+ if e.is_zombie do fmt.println("Grrrr!");
+ }
+
+ // NOTE(bill): As you can see, the usage code has not changed, only its
+ // memory layout. Both approaches have their own advantages but they can
+ // be used together to achieve different results. The subtyping approach
+ // can allow for a greater control of the memory layout and memory
+ // allocation, e.g. storing the derivatives together. However, this is
+ // also its disadvantage. You must either preallocate arrays for each
+ // derivative separation (which can be easily missed) or preallocate a
+ // bunch of "raw" memory; determining the maximum size of the derived
+ // types would require the aid of metaprogramming. Unions solve this
+ // particular problem as the data is stored with the base data.
+ // Therefore, it is possible to preallocate, e.g. [100]Entity.
+
+ // It should be noted that the union approach can have the same memory
+ // layout as the any and with the same type restrictions by using a
+ // pointer type for the derivatives.
+
+ /*
+ Entity :: struct {
+ ..
+ derived: union{^Frog, ^Monster};
+ }
+
+ Frog :: struct {
+ using entity: Entity;
+ ..
+ }
+ Monster :: struct {
+ using entity: Entity;
+ ..
+
+ }
+ new_entity :: proc(T: type) -> ^Entity {
+ t := new(T);
+ t.derived = t;
+ return t;
+ }
+ */
+ }
+}
+
+parametric_polymorphism :: proc() {
+ print_value :: proc(value: $T) {
+ fmt.printf("print_value: %T %v\n", value, value);
+ }
+
+ v1: int = 1;
+ v2: f32 = 2.1;
+ v3: f64 = 3.14;
+ v4: string = "message";
+
+ print_value(v1);
+ print_value(v2);
+ print_value(v3);
+ print_value(v4);
+
+ fmt.println();
+
+ add :: proc(p, q: $T) -> T {
+ x: T = p + q;
+ return x;
+ }
+
+ a := add(3, 4);
+ fmt.printf("a: %T = %v\n", a, a);
+
+ b := add(3.2, 4.3);
+ fmt.printf("b: %T = %v\n", b, b);
+
+ // This is how `new` is implemented
+ alloc_type :: proc(T: type) -> ^T {
+ t := cast(^T)alloc(size_of(T), align_of(T));
+ t^ = T{}; // Use default initialization value
+ return t;
+ }
+
+ copy_slice :: proc(dst, src: []$T) -> int {
+ n := min(len(dst), len(src));
+ if n > 0 {
+ mem.copy(&dst[0], &src[0], n*size_of(T));
+ }
+ return n;
+ }
+
+ double_params :: proc(a: $A, b: $B) -> A {
+ return a + A(b);
+ }
+
+ fmt.println(double_params(12, 1.345));
+
+
+
+ { // Polymorphic Types and Type Specialization
+ Table_Slot :: struct(Key, Value: type) {
+ occupied: bool,
+ hash: u32,
+ key: Key,
+ value: Value,
+ }
+ TABLE_SIZE_MIN :: 32;
+ Table :: struct(Key, Value: type) {
+ count: int,
+ allocator: Allocator,
+ slots: []Table_Slot(Key, Value),
+ }
+
+ // Only allow types that are specializations of a (polymorphic) slice
+ make_slice :: proc(T: type/[]$E, len: int) -> T {
+ return make(T, len);
+ }
+
+
+ // Only allow types that are specializations of `Table`
+ allocate :: proc(table: ^$T/Table, capacity: int) {
+ c := context;
+ if table.allocator.procedure != nil do c.allocator = table.allocator;
+
+ push_context c {
+ table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
+ }
+ }
+
+ expand :: proc(table: ^$T/Table) {
+ c := context;
+ if table.allocator.procedure != nil do c.allocator = table.allocator;
+
+ push_context c {
+ old_slots := table.slots;
+
+ cap := max(2*cap(table.slots), TABLE_SIZE_MIN);
+ allocate(table, cap);
+
+ for s in old_slots do if s.occupied {
+ put(table, s.key, s.value);
+ }
+
+ free(old_slots);
+ }
+ }
+
+ // Polymorphic determination of a polymorphic struct
+ // put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
+ put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
+ hash := get_hash(key); // Ad-hoc method which would fail in a different scope
+ index := find_index(table, key, hash);
+ if index < 0 {
+ if f64(table.count) >= 0.75*f64(cap(table.slots)) {
+ expand(table);
+ }
+ assert(table.count <= cap(table.slots));
+
+ hash := get_hash(key);
+ index = int(hash % u32(cap(table.slots)));
+
+ for table.slots[index].occupied {
+ if index += 1; index >= cap(table.slots) {
+ index = 0;
+ }
+ }
+
+ table.count += 1;
+ }
+
+ slot := &table.slots[index];
+ slot.occupied = true;
+ slot.hash = hash;
+ slot.key = key;
+ slot.value = value;
+ }
+
+
+ // find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
+ find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
+ hash := get_hash(key);
+ index := find_index(table, key, hash);
+ if index < 0 {
+ return Value{}, false;
+ }
+ return table.slots[index].value, true;
+ }
+
+ find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
+ if cap(table.slots) <= 0 do return -1;
+
+ index := int(hash % u32(cap(table.slots)));
+ for table.slots[index].occupied {
+ if table.slots[index].hash == hash {
+ if table.slots[index].key == key {
+ return index;
+ }
+ }
+
+ if index += 1; index >= cap(table.slots) {
+ index = 0;
+ }
+ }
+
+ return -1;
+ }
+
+ get_hash :: proc(s: string) -> u32 { // fnv32a
+ h: u32 = 0x811c9dc5;
+ for i in 0..len(s) {
+ h = (h ~ u32(s[i])) * 0x01000193;
+ }
+ return h;
+ }
+
+
+ table: Table(string, int);
+
+ for i in 0..36 do put(&table, "Hellope", i);
+ for i in 0..42 do put(&table, "World!", i);
+
+ found, _ := find(&table, "Hellope");
+ fmt.printf("`found` is %v\n", found);
+
+ found, _ = find(&table, "World!");
+ fmt.printf("`found` is %v\n", found);
+
+ // I would not personally design a hash table like this in production
+ // but this is a nice basic example
+ // A better approach would either use a `u64` or equivalent for the key
+ // and let the user specify the hashing function or make the user store
+ // the hashing procedure with the table
+ }
+}
+
+
+
+
+prefix_table := [?]string{
+ "White",
+ "Red",
+ "Green",
+ "Blue",
+ "Octarine",
+ "Black",
+};
+
+threading_example :: proc() {
+ when ODIN_OS == "windows" {
+ unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
+ __bounds_check_error_loc(loc, index, len(array));
+ array[index] = array[len(array)-1];
+ pop(array);
+ }
+ ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
+ __bounds_check_error_loc(loc, index, len(array));
+ copy(array[index..], array[index+1..]);
+ pop(array);
+ }
+
+ worker_proc :: proc(t: ^thread.Thread) -> int {
+ for iteration in 1..5 {
+ fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
+ fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
+ // win32.sleep(1);
+ }
+ return 0;
+ }
+
+ threads := make([]^thread.Thread, 0, len(prefix_table));
+ defer free(threads);
+
+ for i in 0..len(prefix_table) {
+ if t := thread.create(worker_proc); t != nil {
+ t.init_context = context;
+ t.use_init_context = true;
+ t.user_index = len(threads);
+ append(&threads, t);
+ thread.start(t);
+ }
+ }
+
+ for len(threads) > 0 {
+ for i := 0; i < len(threads); /**/ {
+ if t := threads[i]; thread.is_done(t) {
+ fmt.printf("Thread %d is done\n", t.user_index);
+ thread.destroy(t);
+
+ ordered_remove(&threads, i);
+ } else {
+ i += 1;
+ }
+ }
+ }
+ }
+}
+
+main :: proc() {
+ when false {
+ fmt.println("\n# general_stuff"); general_stuff();
+ fmt.println("\n# default_struct_values"); default_struct_values();
+ fmt.println("\n# union_type"); union_type();
+ fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
+ fmt.println("\n# threading_example"); threading_example();
+ }
+}
+
diff --git a/misc/old_demos/demo008.odin b/misc/old_demos/demo008.odin
new file mode 100644
index 000000000..7916cd5e9
--- /dev/null
+++ b/misc/old_demos/demo008.odin
@@ -0,0 +1,778 @@
+import "core:fmt.odin"
+import "core:strconv.odin"
+import "core:mem.odin"
+import "core:bits.odin"
+import "core:hash.odin"
+import "core:math.odin"
+import "core:math/rand.odin"
+import "core:os.odin"
+import "core:raw.odin"
+import "core:sort.odin"
+import "core:strings.odin"
+import "core:types.odin"
+import "core:utf16.odin"
+import "core:utf8.odin"
+
+// File scope `when` statements
+when ODIN_OS == "windows" {
+ import "core:atomics.odin"
+ import "core:thread.odin"
+ import win32 "core:sys/windows.odin"
+}
+
+@(link_name="general_stuff")
+general_stuff :: proc() {
+ fmt.println("# general_stuff");
+ { // `do` for inline statements rather than block
+ foo :: proc() do fmt.println("Foo!");
+ if false do foo();
+ for false do foo();
+ when false do foo();
+
+ if false do foo();
+ else do foo();
+ }
+
+ { // Removal of `++` and `--` (again)
+ x: int;
+ x += 1;
+ x -= 1;
+ }
+ { // Casting syntaxes
+ i := i32(137);
+ ptr := &i;
+
+ _ = (^f32)(ptr);
+ // ^f32(ptr) == ^(f32(ptr))
+ _ = cast(^f32)ptr;
+
+ _ = (^f32)(ptr)^;
+ _ = (cast(^f32)ptr)^;
+
+ // Questions: Should there be two ways to do it?
+ }
+
+ /*
+ * Remove *_val_of built-in procedures
+ * size_of, align_of, offset_of
+ * type_of, type_info_of
+ */
+
+ { // `expand_to_tuple` built-in procedure
+ Foo :: struct {
+ x: int,
+ b: bool,
+ }
+ f := Foo{137, true};
+ x, b := expand_to_tuple(f);
+ fmt.println(f);
+ fmt.println(x, b);
+ fmt.println(expand_to_tuple(f));
+ }
+
+ {
+ // .. half-closed range
+ // .. open range
+
+ for in 0..2 {} // 0, 1
+ for in 0..2 {} // 0, 1, 2
+ }
+
+ { // Multiple sized booleans
+
+ x0: bool; // default
+ x1: b8 = true;
+ x2: b16 = false;
+ x3: b32 = true;
+ x4: b64 = false;
+
+ fmt.printf("x1: %T = %v;\n", x1, x1);
+ fmt.printf("x2: %T = %v;\n", x2, x2);
+ fmt.printf("x3: %T = %v;\n", x3, x3);
+ fmt.printf("x4: %T = %v;\n", x4, x4);
+
+ // Having specific sized booleans is very useful when dealing with foreign code
+ // and to enforce specific alignment for a boolean, especially within a struct
+ }
+
+ { // `distinct` types
+ // Originally, all type declarations would create a distinct type unless #type_alias was present.
+ // Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present.
+ // If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct.
+
+ Int32 :: i32;
+ #assert(Int32 == i32);
+
+ My_Int32 :: distinct i32;
+ #assert(My_Int32 != i32);
+
+ My_Struct :: struct{x: int};
+ #assert(My_Struct != struct{x: int});
+ }
+}
+
+default_struct_values :: proc() {
+ fmt.println("# default_struct_values");
+ {
+ Vector3 :: struct {
+ x: f32,
+ y: f32,
+ z: f32,
+ }
+ v: Vector3;
+ fmt.println(v);
+ }
+ {
+ // Default values must be constants
+ Vector3 :: struct {
+ x: f32 = 1,
+ y: f32 = 4,
+ z: f32 = 9,
+ }
+ v: Vector3;
+ fmt.println(v);
+
+ v = Vector3{};
+ fmt.println(v);
+
+ // Uses the same semantics as a default values in a procedure
+ v = Vector3{137};
+ fmt.println(v);
+
+ v = Vector3{z = 137};
+ fmt.println(v);
+ }
+
+ {
+ Vector3 :: struct {
+ x := 1.0,
+ y := 4.0,
+ z := 9.0,
+ }
+ stack_default: Vector3;
+ stack_literal := Vector3{};
+ heap_one := new(Vector3); defer free(heap_one);
+ heap_two := new_clone(Vector3{}); defer free(heap_two);
+
+ fmt.println("stack_default - ", stack_default);
+ fmt.println("stack_literal - ", stack_literal);
+ fmt.println("heap_one - ", heap_one^);
+ fmt.println("heap_two - ", heap_two^);
+
+
+ N :: 4;
+ stack_array: [N]Vector3;
+ heap_array := new([N]Vector3); defer free(heap_array);
+ heap_slice := make([]Vector3, N); defer free(heap_slice);
+ fmt.println("stack_array[1] - ", stack_array[1]);
+ fmt.println("heap_array[1] - ", heap_array[1]);
+ fmt.println("heap_slice[1] - ", heap_slice[1]);
+ }
+}
+
+
+
+
+union_type :: proc() {
+ fmt.println("\n# union_type");
+ {
+ val: union{int, bool};
+ val = 137;
+ if i, ok := val.(int); ok {
+ fmt.println(i);
+ }
+ val = true;
+ fmt.println(val);
+
+ val = nil;
+
+ switch v in val {
+ case int: fmt.println("int", v);
+ case bool: fmt.println("bool", v);
+ case: fmt.println("nil");
+ }
+ }
+ {
+ // There is a duality between `any` and `union`
+ // An `any` has a pointer to the data and allows for any type (open)
+ // A `union` has as binary blob to store the data and allows only certain types (closed)
+ // The following code is with `any` but has the same syntax
+ val: any;
+ val = 137;
+ if i, ok := val.(int); ok {
+ fmt.println(i);
+ }
+ val = true;
+ fmt.println(val);
+
+ val = nil;
+
+ switch v in val {
+ case int: fmt.println("int", v);
+ case bool: fmt.println("bool", v);
+ case: fmt.println("nil");
+ }
+ }
+
+ Vector3 :: struct {x, y, z: f32};
+ Quaternion :: struct {x, y, z: f32, w: f32 = 1};
+
+ // More realistic examples
+ {
+ // NOTE(bill): For the above basic examples, you may not have any
+ // particular use for it. However, my main use for them is not for these
+ // simple cases. My main use is for hierarchical types. Many prefer
+ // subtyping, embedding the base data into the derived types. Below is
+ // an example of this for a basic game Entity.
+
+ Entity :: struct {
+ id: u64,
+ name: string,
+ position: Vector3,
+ orientation: Quaternion,
+
+ derived: any,
+ }
+
+ Frog :: struct {
+ using entity: Entity,
+ jump_height: f32,
+ }
+
+ Monster :: struct {
+ using entity: Entity,
+ is_robot: bool,
+ is_zombie: bool,
+ }
+
+ // See `parametric_polymorphism` procedure for details
+ new_entity :: proc(T: type) -> ^Entity {
+ t := new(T);
+ t.derived = t^;
+ return t;
+ }
+
+ entity := new_entity(Monster);
+
+ switch e in entity.derived {
+ case Frog:
+ fmt.println("Ribbit");
+ case Monster:
+ if e.is_robot do fmt.println("Robotic");
+ if e.is_zombie do fmt.println("Grrrr!");
+ }
+ }
+
+ {
+ // NOTE(bill): A union can be used to achieve something similar. Instead
+ // of embedding the base data into the derived types, the derived data
+ // in embedded into the base type. Below is the same example of the
+ // basic game Entity but using an union.
+
+ Entity :: struct {
+ id: u64,
+ name: string,
+ position: Vector3,
+ orientation: Quaternion,
+
+ derived: union {Frog, Monster},
+ }
+
+ Frog :: struct {
+ using entity: ^Entity,
+ jump_height: f32,
+ }
+
+ Monster :: struct {
+ using entity: ^Entity,
+ is_robot: bool,
+ is_zombie: bool,
+ }
+
+ // See `parametric_polymorphism` procedure for details
+ new_entity :: proc(T: type) -> ^Entity {
+ t := new(Entity);
+ t.derived = T{entity = t};
+ return t;
+ }
+
+ entity := new_entity(Monster);
+
+ switch e in entity.derived {
+ case Frog:
+ fmt.println("Ribbit");
+ case Monster:
+ if e.is_robot do fmt.println("Robotic");
+ if e.is_zombie do fmt.println("Grrrr!");
+ }
+
+ // NOTE(bill): As you can see, the usage code has not changed, only its
+ // memory layout. Both approaches have their own advantages but they can
+ // be used together to achieve different results. The subtyping approach
+ // can allow for a greater control of the memory layout and memory
+ // allocation, e.g. storing the derivatives together. However, this is
+ // also its disadvantage. You must either preallocate arrays for each
+ // derivative separation (which can be easily missed) or preallocate a
+ // bunch of "raw" memory; determining the maximum size of the derived
+ // types would require the aid of metaprogramming. Unions solve this
+ // particular problem as the data is stored with the base data.
+ // Therefore, it is possible to preallocate, e.g. [100]Entity.
+
+ // It should be noted that the union approach can have the same memory
+ // layout as the any and with the same type restrictions by using a
+ // pointer type for the derivatives.
+
+ /*
+ Entity :: struct {
+ ..
+ derived: union{^Frog, ^Monster},
+ }
+
+ Frog :: struct {
+ using entity: Entity,
+ ..
+ }
+ Monster :: struct {
+ using entity: Entity,
+ ..
+
+ }
+ new_entity :: proc(T: type) -> ^Entity {
+ t := new(T);
+ t.derived = t;
+ return t;
+ }
+ */
+ }
+}
+
+parametric_polymorphism :: proc() {
+ fmt.println("# parametric_polymorphism");
+
+ print_value :: proc(value: $T) {
+ fmt.printf("print_value: %T %v\n", value, value);
+ }
+
+ v1: int = 1;
+ v2: f32 = 2.1;
+ v3: f64 = 3.14;
+ v4: string = "message";
+
+ print_value(v1);
+ print_value(v2);
+ print_value(v3);
+ print_value(v4);
+
+ fmt.println();
+
+ add :: proc(p, q: $T) -> T {
+ x: T = p + q;
+ return x;
+ }
+
+ a := add(3, 4);
+ fmt.printf("a: %T = %v\n", a, a);
+
+ b := add(3.2, 4.3);
+ fmt.printf("b: %T = %v\n", b, b);
+
+ // This is how `new` is implemented
+ alloc_type :: proc(T: type) -> ^T {
+ t := cast(^T)alloc(size_of(T), align_of(T));
+ t^ = T{}; // Use default initialization value
+ return t;
+ }
+
+ copy_slice :: proc(dst, src: []$T) -> int {
+ return mem.copy(&dst[0], &src[0], n*size_of(T));
+ }
+
+ double_params :: proc(a: $A, b: $B) -> A {
+ return a + A(b);
+ }
+
+ fmt.println(double_params(12, 1.345));
+
+
+
+ { // Polymorphic Types and Type Specialization
+ Table_Slot :: struct(Key, Value: type) {
+ occupied: bool,
+ hash: u32,
+ key: Key,
+ value: Value,
+ }
+ TABLE_SIZE_MIN :: 32;
+ Table :: struct(Key, Value: type) {
+ count: int,
+ allocator: Allocator,
+ slots: []Table_Slot(Key, Value),
+ }
+
+ // Only allow types that are specializations of a (polymorphic) slice
+ make_slice :: proc(T: type/[]$E, len: int) -> T {
+ return make(T, len);
+ }
+
+
+ // Only allow types that are specializations of `Table`
+ allocate :: proc(table: ^$T/Table, capacity: int) {
+ c := context;
+ if table.allocator.procedure != nil do c.allocator = table.allocator;
+
+ context <- c {
+ table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
+ }
+ }
+
+ expand :: proc(table: ^$T/Table) {
+ c := context;
+ if table.allocator.procedure != nil do c.allocator = table.allocator;
+
+ context <- c {
+ old_slots := table.slots;
+
+ cap := max(2*len(table.slots), TABLE_SIZE_MIN);
+ allocate(table, cap);
+
+ for s in old_slots do if s.occupied {
+ put(table, s.key, s.value);
+ }
+
+ free(old_slots);
+ }
+ }
+
+ // Polymorphic determination of a polymorphic struct
+ // put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
+ put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
+ hash := get_hash(key); // Ad-hoc method which would fail in a different scope
+ index := find_index(table, key, hash);
+ if index < 0 {
+ if f64(table.count) >= 0.75*f64(len(table.slots)) {
+ expand(table);
+ }
+ assert(table.count <= len(table.slots));
+
+ hash := get_hash(key);
+ index = int(hash % u32(len(table.slots)));
+
+ for table.slots[index].occupied {
+ if index += 1; index >= len(table.slots) {
+ index = 0;
+ }
+ }
+
+ table.count += 1;
+ }
+
+ slot := &table.slots[index];
+ slot.occupied = true;
+ slot.hash = hash;
+ slot.key = key;
+ slot.value = value;
+ }
+
+
+ // find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
+ find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
+ hash := get_hash(key);
+ index := find_index(table, key, hash);
+ if index < 0 {
+ return Value{}, false;
+ }
+ return table.slots[index].value, true;
+ }
+
+ find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
+ if len(table.slots) <= 0 do return -1;
+
+ index := int(hash % u32(len(table.slots)));
+ for table.slots[index].occupied {
+ if table.slots[index].hash == hash {
+ if table.slots[index].key == key {
+ return index;
+ }
+ }
+
+ if index += 1; index >= len(table.slots) {
+ index = 0;
+ }
+ }
+
+ return -1;
+ }
+
+ get_hash :: proc(s: string) -> u32 { // fnv32a
+ h: u32 = 0x811c9dc5;
+ for i in 0..len(s) {
+ h = (h ~ u32(s[i])) * 0x01000193;
+ }
+ return h;
+ }
+
+
+ table: Table(string, int);
+
+ for i in 0..36 do put(&table, "Hellope", i);
+ for i in 0..42 do put(&table, "World!", i);
+
+ found, _ := find(&table, "Hellope");
+ fmt.printf("`found` is %v\n", found);
+
+ found, _ = find(&table, "World!");
+ fmt.printf("`found` is %v\n", found);
+
+ // I would not personally design a hash table like this in production
+ // but this is a nice basic example
+ // A better approach would either use a `u64` or equivalent for the key
+ // and let the user specify the hashing function or make the user store
+ // the hashing procedure with the table
+ }
+}
+
+
+
+
+prefix_table := [?]string{
+ "White",
+ "Red",
+ "Green",
+ "Blue",
+ "Octarine",
+ "Black",
+};
+
+threading_example :: proc() {
+ when ODIN_OS == "windows" {
+ fmt.println("# threading_example");
+
+ unordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
+ __bounds_check_error_loc(loc, index, len(array));
+ array[index] = array[len(array)-1];
+ pop(array);
+ }
+ ordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
+ __bounds_check_error_loc(loc, index, len(array));
+ copy(array[index..], array[index+1..]);
+ pop(array);
+ }
+
+ worker_proc :: proc(t: ^thread.Thread) -> int {
+ for iteration in 1..5 {
+ fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
+ fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
+ // win32.sleep(1);
+ }
+ return 0;
+ }
+
+ threads := make([dynamic]^thread.Thread, 0, len(prefix_table));
+ defer free(threads);
+
+ for in prefix_table {
+ if t := thread.create(worker_proc); t != nil {
+ t.init_context = context;
+ t.use_init_context = true;
+ t.user_index = len(threads);
+ append(&threads, t);
+ thread.start(t);
+ }
+ }
+
+ for len(threads) > 0 {
+ for i := 0; i < len(threads); /**/ {
+ if t := threads[i]; thread.is_done(t) {
+ fmt.printf("Thread %d is done\n", t.user_index);
+ thread.destroy(t);
+
+ ordered_remove(&threads, i);
+ } else {
+ i += 1;
+ }
+ }
+ }
+ }
+}
+
+array_programming :: proc() {
+ fmt.println("# array_programming");
+ {
+ a := [3]f32{1, 2, 3};
+ b := [3]f32{5, 6, 7};
+ c := a * b;
+ d := a + b;
+ e := 1 + (c - d) / 2;
+ fmt.printf("%.1f\n", e); // [0.5, 3.0, 6.5]
+ }
+
+ {
+ a := [3]f32{1, 2, 3};
+ b := swizzle(a, 2, 1, 0);
+ assert(b == [3]f32{3, 2, 1});
+
+ c := swizzle(a, 0, 0);
+ assert(c == [2]f32{1, 1});
+ assert(c == 1);
+ }
+
+ {
+ Vector3 :: distinct [3]f32;
+ a := Vector3{1, 2, 3};
+ b := Vector3{5, 6, 7};
+ c := (a * b)/2 + 1;
+ d := c.x + c.y + c.z;
+ fmt.printf("%.1f\n", d); // 22.0
+
+ cross :: proc(a, b: Vector3) -> Vector3 {
+ i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
+ j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
+ return i - j;
+ }
+
+ blah :: proc(a: Vector3) -> f32 {
+ return a.x + a.y + a.z;
+ }
+
+ x := cross(a, b);
+ fmt.println(x);
+ fmt.println(blah(x));
+ }
+}
+
+
+using println in import "core:fmt.odin"
+
+using_in :: proc() {
+ fmt.println("# using in");
+ using print in fmt;
+
+ println("Hellope1");
+ print("Hellope2\n");
+
+ Foo :: struct {
+ x, y: int,
+ b: bool,
+ }
+ f: Foo;
+ f.x, f.y = 123, 321;
+ println(f);
+ using x, y in f;
+ x, y = 456, 654;
+ println(f);
+}
+
+named_proc_return_parameters :: proc() {
+ fmt.println("# named proc return parameters");
+
+ foo0 :: proc() -> int {
+ return 123;
+ }
+ foo1 :: proc() -> (a: int) {
+ a = 123;
+ return;
+ }
+ foo2 :: proc() -> (a, b: int) {
+ // Named return values act like variables within the scope
+ a = 321;
+ b = 567;
+ return b, a;
+ }
+ fmt.println("foo0 =", foo0()); // 123
+ fmt.println("foo1 =", foo1()); // 123
+ fmt.println("foo2 =", foo2()); // 567 321
+}
+
+
+enum_export :: proc() {
+ fmt.println("# enum #export");
+
+ Foo :: enum #export {A, B, C};
+
+ f0 := A;
+ f1 := B;
+ f2 := C;
+ fmt.println(f0, f1, f2);
+}
+
+explicit_procedure_overloading :: proc() {
+ fmt.println("# explicit procedure overloading");
+
+ add_ints :: proc(a, b: int) -> int {
+ x := a + b;
+ fmt.println("add_ints", x);
+ return x;
+ }
+ add_floats :: proc(a, b: f32) -> f32 {
+ x := a + b;
+ fmt.println("add_floats", x);
+ return x;
+ }
+ add_numbers :: proc(a: int, b: f32, c: u8) -> int {
+ x := int(a) + int(b) + int(c);
+ fmt.println("add_numbers", x);
+ return x;
+ }
+
+ add :: proc[add_ints, add_floats, add_numbers];
+
+ add(int(1), int(2));
+ add(f32(1), f32(2));
+ add(int(1), f32(2), u8(3));
+
+ add(1, 2); // untyped ints coerce to int tighter than f32
+ add(1.0, 2.0); // untyped floats coerce to f32 tighter than int
+ add(1, 2, 3); // three parameters
+
+ // Ambiguous answers
+ // add(1.0, 2);
+ // add(1, 2.0);
+}
+
+complete_switch :: proc() {
+ fmt.println("# complete_switch");
+ { // enum
+ Foo :: enum #export {
+ A,
+ B,
+ C,
+ D,
+ }
+
+ b := Foo.B;
+ f := Foo.A;
+ #complete switch f {
+ case A: fmt.println("A");
+ case B: fmt.println("B");
+ case C: fmt.println("C");
+ case D: fmt.println("D");
+ case: fmt.println("?");
+ }
+ }
+ { // union
+ Foo :: union {int, bool};
+ f: Foo = 123;
+ #complete switch in f {
+ case int: fmt.println("int");
+ case bool: fmt.println("bool");
+ case:
+ }
+ }
+}
+
+
+main :: proc() {
+ when true {
+ general_stuff();
+ default_struct_values();
+ union_type();
+ parametric_polymorphism();
+ threading_example();
+ array_programming();
+ using_in();
+ named_proc_return_parameters();
+ enum_export();
+ explicit_procedure_overloading();
+ complete_switch();
+ }
+}
diff --git a/misc/old_demos/old_runtime.odin b/misc/old_demos/old_runtime.odin
new file mode 100644
index 000000000..e605e7820
--- /dev/null
+++ b/misc/old_demos/old_runtime.odin
@@ -0,0 +1,412 @@
+#include "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/misc/old_stuff/demo_backup.odin b/misc/old_stuff/demo_backup.odin
new file mode 100644
index 000000000..b8bbbb02d
--- /dev/null
+++ b/misc/old_stuff/demo_backup.odin
@@ -0,0 +1,430 @@
+import (
+ "fmt.odin";
+ "atomics.odin";
+ "bits.odin";
+ "decimal.odin";
+ "hash.odin";
+ "math.odin";
+ "mem.odin";
+ "opengl.odin";
+ "os.odin";
+ "raw.odin";
+ "strconv.odin";
+ "strings.odin";
+ "sync.odin";
+ "sort.odin";
+ "types.odin";
+ "utf8.odin";
+ "utf16.odin";
+/*
+*/
+)
+
+
+general_stuff :: proc() {
+ // Complex numbers
+ a := 3 + 4i;
+ b: complex64 = 3 + 4i;
+ c: complex128 = 3 + 4i;
+ d := complex(2, 3);
+
+ e := a / conj(a);
+ fmt.println("(3+4i)/(3-4i) =", e);
+ fmt.println(real(e), "+", imag(e), "i");
+
+
+ // C-style variadic procedures
+ foreign __llvm_core {
+ // The variadic part allows for extra type checking too which C does not provide
+ c_printf :: proc(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf" ---;
+ }
+ str := "%d\n\x00";
+ // c_printf(&str[0], i32(789456123));
+
+
+ Foo :: struct {
+ x: int;
+ y: f32;
+ z: string;
+ }
+ foo := Foo{123, 0.513, "A string"};
+ x, y, z := expand_to_tuple(foo);
+ fmt.println(x, y, z);
+ #assert(type_of(x) == int);
+ #assert(type_of(y) == f32);
+ #assert(type_of(z) == string);
+
+
+ // By default, all variables are zeroed
+ // This can be overridden with the "uninitialized value"
+ // This is similar to `nil` but applied to everything
+ undef_int: int = ---;
+
+
+ // Context system is now implemented using Implicit Parameter Passing (IPP)
+ // The previous implementation was Thread Local Storage (TLS)
+ // IPP has the advantage that it works on systems without TLS and that you can
+ // link the context to the stack frame and thus look at previous contexts
+ //
+ // It does mean that a pointer is implicitly passed procedures with the default
+ // Odin calling convention (#cc_odin)
+ // This can be overridden with something like #cc_contextless or #cc_c if performance
+ // is worried about
+
+}
+
+foreign_blocks :: proc() {
+ // See sys/windows.odin
+}
+
+default_arguments :: proc() {
+ hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b);
+ fmt.println("\nTesting default arguments:");
+ hello(1, 2);
+ hello(1);
+ hello();
+}
+
+named_arguments :: proc() {
+ Colour :: enum {
+ Red,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Octarine,
+ };
+ using Colour;
+
+ make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) {
+ fmt.println();
+ fmt.printf("My name is %v and I like %v. %v\n", name, favourite_colour, catch_phrase);
+ }
+
+ make_character("Frank", "¡Ay, caramba!", Blue, Green);
+
+
+ // As the procedures have more and more parameters, it is very easy
+ // to get many of the arguments in the wrong order especialy if the
+ // types are the same
+ make_character("¡Ay, caramba!", "Frank", Green, Blue);
+
+ // Named arguments help to disambiguate this problem
+ make_character(catch_phrase = "¡Ay, caramba!", name = "Frank",
+ least_favourite_colour = Green, favourite_colour = Blue);
+
+
+ // The named arguments can be specifed in any order.
+ make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!",
+ least_favourite_colour = Green, name = "Dennis");
+
+
+ // NOTE: You cannot mix named arguments with normal values
+ /*
+ make_character("Dennis",
+ favourite_colour = Octarine, catch_phrase = "U wot m8!",
+ least_favourite_colour = Green);
+ */
+
+
+ // Named arguments can also aid with default arguments
+ numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14,
+ d := "The Best String!", e := false, f := 10.3/3.1, g := false) {
+ g_str := g ? "true" : "false";
+ fmt.printf("How many?! %s: %v\n", s, g_str);
+ }
+
+ numerous_things("First");
+ numerous_things(s = "Second", g = true);
+
+
+ // Default values can be placed anywhere, not just at the end like in other languages
+ weird :: proc(pre: string, mid: int = 0, post: string) {
+ fmt.println(pre, mid, post);
+ }
+
+ weird("How many things", 42, "huh?");
+ weird(pre = "Prefix", post = "Pat");
+
+}
+
+
+default_return_values :: proc() {
+ foo :: proc(x: int) -> (first: string = "Hellope", second := "world!") {
+ match x {
+ case 0: return;
+ case 1: return "Goodbye";
+ case 2: return "Goodbye", "cruel world..";
+ case 3: return second = "cruel world..", first = "Goodbye";
+ }
+
+ return second = "my old friend.";
+ }
+
+ fmt.printf("%s %s\n", foo(0));
+ fmt.printf("%s %s\n", foo(1));
+ fmt.printf("%s %s\n", foo(2));
+ fmt.printf("%s %s\n", foo(3));
+ fmt.printf("%s %s\n", foo(4));
+ fmt.println();
+
+
+ // A more "real" example
+ Error :: enum {
+ None,
+ WhyTheNumberThree,
+ TenIsTooBig,
+ };
+
+ Entity :: struct {
+ name: string;
+ id: u32;
+ }
+
+ some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) {
+ match {
+ case input == 3: return err = Error.WhyTheNumberThree;
+ case input >= 10: return err = Error.TenIsTooBig;
+ }
+
+ e := new(Entity);
+ e.id = u32(input);
+
+ return result = e;
+ }
+}
+
+call_location :: proc() {
+ amazing :: proc(n: int, using loc := #caller_location) {
+ fmt.printf("%s(%d:%d) just asked to do something amazing.\n",
+ fully_pathed_filename, line, column);
+ fmt.printf("Normal -> %d\n", n);
+ fmt.printf("Amazing -> %d\n", n+1);
+ fmt.println();
+ }
+
+ loc := #location(main);
+ fmt.println("`main` is located at", loc);
+
+ fmt.println("This line is located at", #location());
+ fmt.println();
+
+ amazing(3);
+ amazing(4, #location(call_location));
+
+ // See _preload.odin for the implementations of `assert` and `panic`
+
+}
+
+
+explicit_parametric_polymorphic_procedures :: proc() {
+ // This is how `new` is actually implemented, see _preload.odin
+ alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T));
+
+ int_ptr := alloc_type(int);
+ defer free(int_ptr);
+ int_ptr^ = 137;
+ fmt.println(int_ptr, int_ptr^);
+
+ // Named arguments work too!
+ another_ptr := alloc_type(T = f32);
+ defer free(another_ptr);
+
+
+ add :: proc(T: type, args: ..T) -> T {
+ res: T;
+ for arg in args do res += arg;
+ return res;
+ }
+
+ fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6));
+
+ swap :: proc(T: type, a, b: ^T) {
+ tmp := a^;
+ a^ = b^;
+ b^ = tmp;
+ }
+
+ a, b: int = 3, 4;
+ fmt.println("Pre-swap:", a, b);
+ swap(int, &a, &b);
+ fmt.println("Post-swap:", a, b);
+ a, b = b, a; // Or use this syntax for this silly example case
+
+
+ Vector2 :: struct {x, y: f32;};
+ {
+ // A more complicated example using subtyping
+ // Something like this could be used in a game
+
+ Entity :: struct {
+ using position: Vector2;
+ flags: u64;
+ id: u64;
+ derived: any;
+ }
+
+ Rock :: struct {
+ using entity: Entity;
+ heavy: bool;
+ }
+ Door :: struct {
+ using entity: Entity;
+ open: bool;
+ }
+ Monster :: struct {
+ using entity: Entity;
+ is_robot: bool;
+ is_zombie: bool;
+ }
+
+ new_entity :: proc(T: type, x, y: f32) -> ^T {
+ result := new(T);
+ result.derived = result^;
+ result.x = x;
+ result.y = y;
+
+ return result;
+ }
+
+ entities: [dynamic]^Entity;
+
+ rock := new_entity(Rock, 3, 5);
+
+ // Named arguments work too!
+ door := new_entity(T = Door, x = 3, y = 6);
+
+ // And named arguments can be any order
+ monster := new_entity(
+ y = 1,
+ x = 2,
+ T = Monster,
+ );
+
+ append(&entities, rock, door, monster);
+
+ fmt.println("Subtyping");
+ for entity in entities {
+ match e in entity.derived {
+ case Rock: fmt.println("Rock", e.x, e.y);
+ case Door: fmt.println("Door", e.x, e.y);
+ case Monster: fmt.println("Monster", e.x, e.y);
+ }
+ }
+ }
+ {
+ Entity :: struct {
+ using position: Vector2;
+ flags: u64;
+ id: u64;
+ variant: union { Rock, Door, Monster };
+ }
+
+ Rock :: struct {
+ using entity: ^Entity;
+ heavy: bool;
+ }
+ Door :: struct {
+ using entity: ^Entity;
+ open: bool;
+ }
+ Monster :: struct {
+ using entity: ^Entity;
+ is_robot: bool;
+ is_zombie: bool;
+ }
+
+ new_entity :: proc(T: type, x, y: f32) -> ^T {
+ result := new(Entity);
+ result.variant = T{entity = result};
+ result.x = x;
+ result.y = y;
+
+ return cast(^T)&result.variant;
+ }
+
+ entities: [dynamic]^Entity;
+
+ rock := new_entity(Rock, 3, 5);
+
+ // Named arguments work too!
+ door := new_entity(T = Door, x = 3, y = 6);
+
+ // And named arguments can be any order
+ monster := new_entity(
+ y = 1,
+ x = 2,
+ T = Monster,
+ );
+
+ append(&entities, rock, door, monster);
+
+ fmt.println("Union");
+ for entity in entities {
+ match e in entity.variant {
+ case Rock: fmt.println("Rock", e.x, e.y);
+ case Door: fmt.println("Door", e.x, e.y);
+ case Monster: fmt.println("Monster", e.x, e.y);
+ }
+ }
+ }
+}
+
+
+implicit_polymorphic_assignment :: proc() {
+ yep :: proc(p: proc(x: int)) {
+ p(123);
+ }
+
+ frank :: proc(x: $T) do fmt.println("frank ->", x);
+ tim :: proc(x, y: $T) do fmt.println("tim ->", x, y);
+ yep(frank);
+ // yep(tim);
+}
+
+
+
+
+main :: proc() {
+/*
+ foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y);
+ foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
+ foo :: proc(x: type) do fmt.println("#3", type_info(x));
+
+ f :: foo;
+
+ f(y = 3785.1546, x = 123);
+ f(x = int, y = 897.513);
+ f(x = f32);
+
+ general_stuff();
+ foreign_blocks();
+ default_arguments();
+ named_arguments();
+ default_return_values();
+ call_location();
+ explicit_parametric_polymorphic_procedures();
+ implicit_polymorphic_assignment();
+
+
+ // Command line argument(s)!
+ // -opt=0,1,2,3
+*/
+/*
+ program := "+ + * - /";
+ accumulator := 0;
+
+ for token in program {
+ match token {
+ case '+': accumulator += 1;
+ case '-': accumulator -= 1;
+ case '*': accumulator *= 2;
+ case '/': accumulator /= 2;
+ case: // Ignore everything else
+ }
+ }
+
+ fmt.printf("The program \"%s\" calculates the value %d\n",
+ program, accumulator);
+*/
+}
diff --git a/misc/shell.bat b/misc/shell.bat
index 36db84570..85a7949c6 100644
--- a/misc/shell.bat
+++ b/misc/shell.bat
@@ -1,8 +1,8 @@
@echo off
rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL
-call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
-rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
+rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL
set _NO_DEBUG_HEAP=1