diff --git a/build.bat b/build.bat
index 73ff5f641..cedab964b 100644
--- a/build.bat
+++ b/build.bat
@@ -4,7 +4,7 @@
set exe_name=odin.exe
:: Debug = 0, Release = 1
-set release_mode=1
+set release_mode=0
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug
@@ -43,7 +43,7 @@ del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.cpp" ^
/link %linker_settings% -OUT:%exe_name% ^
- && odin run code/demo.odin -opt=0
+ && odin run examples/punity.odin -opt=0
rem && odin docs core/fmt.odin
del *.obj > NUL 2> NUL
diff --git a/code/demo.odin b/code/demo.odin
deleted file mode 100644
index 19869caac..000000000
--- a/code/demo.odin
+++ /dev/null
@@ -1,601 +0,0 @@
-
-import (
- "fmt.odin";
- "strconv.odin";
- "mem.odin";
- "thread.odin" when ODIN_OS == "windows";
- win32 "sys/windows.odin" when ODIN_OS == "windows";
-
-/*
- "atomics.odin";
- "bits.odin";
- "hash.odin";
- "math.odin";
- "opengl.odin";
- "os.odin";
- "raw.odin";
- "sort.odin";
- "strings.odin";
- "sync.odin";
- "types.odin";
- "utf8.odin";
- "utf16.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
- }
-}
-
-nested_struct_declarations :: proc() {
- {
- FooInteger :: int;
- Foo :: struct {
- i: FooInteger;
- };
- f := Foo{FooInteger(137)};
- }
- {
- Foo :: struct {
- Integer :: int;
-
- i: Integer;
- }
- f := Foo{Foo.Integer(137)};
-
- }
-}
-
-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;
-
- match 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;
-
- match 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);
-
- match 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);
-
- match 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 :: struct(Key, Value: type) {
- Slot :: struct {
- occupied: bool;
- hash: u32;
- key: Key;
- value: Value;
- }
- SIZE_MIN :: 32;
-
- count: int;
- allocator: Allocator;
- slots: []Slot;
- }
-
- // 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([]T.Slot, max(capacity, T.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), T.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 true {
- fmt.println("\n# general_stuff"); general_stuff();
- fmt.println("\n# nested_struct_declarations"); nested_struct_declarations();
- 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/code/demo_backup.odin b/code/demo_backup.odin
deleted file mode 100644
index 8eeaeb357..000000000
--- a/code/demo_backup.odin
+++ /dev/null
@@ -1,430 +0,0 @@
-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);
- compile_assert(type_of(x) == int);
- compile_assert(type_of(y) == f32);
- compile_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/code/game.odin b/code/game.odin
deleted file mode 100644
index 0404232d5..000000000
--- a/code/game.odin
+++ /dev/null
@@ -1,222 +0,0 @@
-import win32 "sys/windows.odin" when ODIN_OS == "windows";
-import wgl "sys/wgl.odin" when ODIN_OS == "windows";
-import "fmt.odin";
-import "math.odin";
-import "os.odin";
-import gl "opengl.odin";
-
-const TWO_HEARTS = '💕';
-
-var win32_perf_count_freq = win32.get_query_performance_frequency();
-proc time_now() -> f64 {
- assert(win32_perf_count_freq != 0);
-
- var counter: i64;
- win32.query_performance_counter(&counter);
- return f64(counter) / f64(win32_perf_count_freq);
-}
-proc win32_print_last_error() {
- var err_code = win32.get_last_error();
- if err_code != 0 {
- fmt.println("get_last_error: ", err_code);
- }
-}
-
-// Yuk!
-proc to_c_string(s: string) -> []u8 {
- var c_str = make([]u8, len(s)+1);
- copy(c_str, []u8(s));
- c_str[len(s)] = 0;
- return c_str;
-}
-
-
-type Window struct {
- width, height: int,
- wc: win32.WndClassExA,
- dc: win32.Hdc,
- hwnd: win32.Hwnd,
- opengl_context, rc: wgl.Hglrc,
- c_title: []u8,
-}
-
-proc make_window(title: string, msg, height: int, window_proc: win32.WndProc) -> (Window, bool) {
- using win32;
-
- var w: Window;
- w.width, w.height = msg, height;
-
- var class_name = "Win32-Odin-Window\x00";
- var c_class_name = &class_name[0];
- if title[len(title)-1] != 0 {
- w.c_title = to_c_string(title);
- } else {
- w.c_title = []u8(title);
- }
-
- var instance = get_module_handle_a(nil);
-
- w.wc = WndClassExA{
- size = size_of(WndClassExA),
- style = CS_VREDRAW | CS_HREDRAW,
- instance = Hinstance(instance),
- class_name = c_class_name,
- wnd_proc = window_proc,
- };
-
- if register_class_ex_a(&w.wc) == 0 {
- win32_print_last_error();
- return w, false;
- }
-
- w.hwnd = create_window_ex_a(0,
- c_class_name, &w.c_title[0],
- WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
- CW_USEDEFAULT, CW_USEDEFAULT,
- i32(w.width), i32(w.height),
- nil, nil, instance, nil);
-
- if w.hwnd == nil {
- win32_print_last_error();
- return w, false;
- }
-
- w.dc = get_dc(w.hwnd);
-
- {
- var pfd = PixelFormatDescriptor{
- size = size_of(PixelFormatDescriptor),
- version = 1,
- flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
- pixel_type = PFD_TYPE_RGBA,
- color_bits = 32,
- alpha_bits = 8,
- depth_bits = 24,
- stencil_bits = 8,
- layer_type = PFD_MAIN_PLANE,
- };
-
- set_pixel_format(w.dc, choose_pixel_format(w.dc, &pfd), nil);
- w.opengl_context = wgl.create_context(w.dc);
- wgl.make_current(w.dc, w.opengl_context);
-
- var attribs = [8]i32{
- wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
- wgl.CONTEXT_MINOR_VERSION_ARB, 1,
- wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
- 0, // NOTE(bill): tells the proc that this is the end of attribs
- };
-
- var wgl_str = "wglCreateContextAttribsARB\x00";
- var wglCreateContextAttribsARB = wgl.CreateContextAttribsARBType(wgl.get_proc_address(&wgl_str[0]));
- w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
- wgl.make_current(w.dc, w.rc);
- swap_buffers(w.dc);
- }
-
- return w, true;
-}
-
-proc destroy_window(w: ^Window) {
- free(w.c_title);
-}
-
-proc display_window(w: ^Window) {
- win32.swap_buffers(w.dc);
-}
-
-
-proc run() {
- using math;
-
- proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
- using win32;
- if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
- os.exit(0);
- return 0;
- }
- return def_window_proc_a(hwnd, msg, wparam, lparam);
- }
-
- var window, window_success = make_window("Odin Language Demo", 854, 480, win32.WndProc(win32_proc));
- if !window_success {
- return;
- }
- defer destroy_window(&window);
-
- gl.init();
-
- using win32;
-
- var prev_time = time_now();
- var running = true;
-
- var pos = Vec2{100, 100};
-
- for running {
- var curr_time = time_now();
- var dt = f32(curr_time - prev_time);
- prev_time = curr_time;
-
- var msg: Msg;
- for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
- if msg.message == WM_QUIT {
- running = false;
- }
- translate_message(&msg);
- dispatch_message_a(&msg);
- }
-
- if is_key_down(KeyCode.Escape) {
- running = false;
- }
-
- {
- const SPEED = 500;
- var v: Vec2;
-
- if is_key_down(KeyCode.Right) { v[0] += 1; }
- if is_key_down(KeyCode.Left) { v[0] -= 1; }
- if is_key_down(KeyCode.Up) { v[1] += 1; }
- if is_key_down(KeyCode.Down) { v[1] -= 1; }
-
- v = norm(v);
-
- pos += v * Vec2{SPEED * dt};
- }
-
-
- gl.ClearColor(0.5, 0.7, 1.0, 1.0);
- gl.Clear(gl.COLOR_BUFFER_BIT);
-
- gl.LoadIdentity();
- gl.Ortho(0, f64(window.width),
- 0, f64(window.height), 0, 1);
-
- proc draw_rect(x, y, w, h: f32) {
- gl.Begin(gl.TRIANGLES);
- defer gl.End();
-
- gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
- gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0);
- gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
-
- gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
- gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0);
- gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
- }
-
- draw_rect(pos.x, pos.y, 50, 50);
-
- display_window(&window);
- var ms_to_sleep = i32(16 - 1000*dt);
- if ms_to_sleep > 0 {
- win32.sleep(ms_to_sleep);
- }
- }
-}
-
-
-proc main() {
- run();
-}
diff --git a/code/http_test.odin b/code/http_test.odin
deleted file mode 100644
index f3359b1b8..000000000
--- a/code/http_test.odin
+++ /dev/null
@@ -1,184 +0,0 @@
-import "fmt.odin";
-
-foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
-
-
-type SOCKET uint;
-const INVALID_SOCKET = ~SOCKET(0);
-
-type AF enum i32 {
- UNSPEC = 0, // unspecified
- UNIX = 1, // local to host (pipes, portals)
- INET = 2, // internetwork: UDP, TCP, etc.
- IMPLINK = 3, // arpanet imp addresses
- PUP = 4, // pup protocols: e.g. BSP
- CHAOS = 5, // mit CHAOS protocols
- NS = 6, // XEROX NS protocols
- ISO = 7, // ISO protocols
- OSI = ISO, // OSI is ISO
- ECMA = 8, // european computer manufacturers
- DATAKIT = 9, // datakit protocols
- CCITT = 10, // CCITT protocols, X.25 etc
- SNA = 11, // IBM SNA
- DECnet = 12, // DECnet
- DLI = 13, // Direct data link interface
- LAT = 14, // LAT
- HYLINK = 15, // NSC Hyperchannel
- APPLETALK = 16, // AppleTalk
- ROUTE = 17, // Internal Routing Protocol
- LINK = 18, // Link layer interface
- XTP = 19, // eXpress Transfer Protocol (no AF)
- COIP = 20, // connection-oriented IP, aka ST II
- CNT = 21, // Computer Network Technology
- RTIP = 22, // Help Identify RTIP packets
- IPX = 23, // Novell Internet Protocol
- SIP = 24, // Simple Internet Protocol
- PIP = 25, // Help Identify PIP packets
- MAX = 26,
-};
-
-const (
- SOCK_STREAM = 1;
- SOCKET_ERROR = -1;
- IPPROTO_TCP = 6;
- AI_PASSIVE = 0x0020;
- SOMAXCONN = 128;
-)
-const (
- SD_RECEIVE = 0;
- SD_SEND = 1;
- SD_BOTH = 2;
-)
-
-const WSADESCRIPTION_LEN = 256;
-const WSASYS_STATUS_LEN = 128;
-type WSADATA struct #ordered {
- version: i16,
- high_version: i16,
-
-
-// NOTE(bill): This is x64 ordering
- max_sockets: u16,
- max_udp_dg: u16,
- vendor_info: ^u8,
- description: [WSADESCRIPTION_LEN+1]u8,
- system_status: [WSASYS_STATUS_LEN+1]u8,
-}
-
-type addrinfo struct #ordered {
- flags: i32,
- family: i32,
- socktype: i32,
- protocol: i32,
- addrlen: uint,
- canonname: ^u8,
- addr: ^sockaddr,
- next: ^addrinfo,
-}
-
-type sockaddr struct #ordered {
- family: u16,
- data: [14]u8,
-}
-
-foreign ws2 {
- proc WSAStartup (version_requested: i16, data: ^WSADATA) -> i32;
- proc WSACleanup () -> i32;
- proc getaddrinfo (node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32;
- proc freeaddrinfo (ai: ^addrinfo);
- proc socket (af, type_, protocol: i32) -> SOCKET;
- proc closesocket (s: SOCKET) -> i32;
- proc bind (s: SOCKET, name: ^sockaddr, name_len: i32) -> i32;
- proc listen (s: SOCKET, back_log: i32) -> i32;
- proc accept (s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET;
- proc recv (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
- proc send (s: SOCKET, buf: ^u8, len: i32, flags: i32) -> i32;
- proc shutdown (s: SOCKET, how: i32) -> i32;
- proc WSAGetLastError() -> i32;
-}
-proc to_c_string(s: string) -> ^u8 {
- var c_str = make([]u8, len(s)+1);
- copy(c_str, []u8(s));
- c_str[len(s)] = 0;
- return &c_str[0];
-}
-
-proc run() {
- var (
- wsa: WSADATA;
- res: ^addrinfo = nil;
- hints: addrinfo;
- s, client: SOCKET;
- )
-
- if WSAStartup(2 | (2 << 8), &wsa) != 0 {
- fmt.println("WSAStartup failed: ", WSAGetLastError());
- return;
- }
- defer WSACleanup();
-
- hints.family = i32(AF.INET);
- hints.socktype = SOCK_STREAM;
- hints.protocol = IPPROTO_TCP;
- hints.flags = AI_PASSIVE;
-
- if getaddrinfo(nil, to_c_string("8080"), &hints, &res) != 0 {
- fmt.println("getaddrinfo failed: ", WSAGetLastError());
- return;
- }
- defer freeaddrinfo(res);
-
- s = socket(res.family, res.socktype, res.protocol);
- if s == INVALID_SOCKET {
- fmt.println("socket failed: ", WSAGetLastError());
- return;
- }
- defer closesocket(s);
-
- bind(s, res.addr, i32(res.addrlen));
- listen(s, SOMAXCONN);
-
- client = accept(s, nil, 0);
- if client == INVALID_SOCKET {
- fmt.println("socket failed: ", WSAGetLastError());
- return;
- }
- defer closesocket(client);
-
- var html =
-`HTTP/1.1 200 OK
-Connection: close
-Content-type: text/html
-
-
-
- Demo Title
-
-
- Odin Server Demo
-
-
-`;
-
- var buf: [1024]u8;
- for {
- var bytes = recv(client, &buf[0], i32(len(buf)), 0);
- if bytes > 0 {
- // fmt.println(string(buf[0.. 0 {
- 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 {
- 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?
-
- {
- prev_context := context;
- defer __context = prev_context;
- // Q: Should I add a `push_context` feature to the language?
-
- __context.allocator = default_allocator();
-
- a := new(int);
- defer free(a);
-
- // Do whatever
-
- }
- }
-
- {
- a: int = 123;
- b: type_of_val(a) = 321;
-
- // NOTE(bill): This matches the current naming scheme
- // size_of
- // align_of
- // offset_of
- //
- // size_of_val
- // align_of_val
- // offset_of_val
- // type_of_val
- }
-
- {
- // Compile time assert
- COND :: true;
- compile_assert(COND);
- // compile_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
-
- default:
- print("default!\n");
- }
-
-
-
- match x := 1.5; x {
- case 1.5:
- print("1.5!\n");
- // break by default
- case TAU:
- print("τ!\n");
- default:
- print("default!\n");
- }
-
-
-
- match x := "Hello"; x {
- case "Hello":
- print("greeting\n");
- // break by default
- case "Goodbye":
- print("farewell\n");
- default:
- 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");
- default:
- 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 {
- 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^++;
- 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() {
- {
- EntityKind :: enum {
- INVALID,
- FROG,
- GIRAFFE,
- HELICOPTER,
- }
-
- Entity :: struct {
- kind: EntityKind
- using data: raw_union {
- frog: struct {
- jump_height: f32,
- colour: u32,
- },
- giraffe: struct {
- neck_length: f32,
- spot_count: int,
- },
- helicopter: struct {
- blade_count: int,
- weight: f32,
- pilot_name: string,
- },
- }
- }
-
- e: Entity;
- e.kind = EntityKind.FROG;
- e.frog.jump_height = 12;
-
- f: type_of_val(e.frog);
-
- // But this is very unsafe and extremely cumbersome to write
- // In C++, I use macros to alleviate this but it's not a solution
- }
-
- {
- Entity :: union {
- Frog{
- jump_height: f32,
- colour: u32,
- },
- Giraffe{
- neck_length: f32,
- spot_count: int,
- },
- Helicopter{
- blade_count: int,
- weight: f32,
- pilot_name: string,
- },
- }
-
- using Entity;
- 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");
- default:
- 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 {};
-
- EntityKind :: enum {
- Invalid,
- Constant,
- Variable,
- UsingVariable,
- TypeName,
- Procedure,
- Builtin,
- Count,
- }
-
- Guid :: i64;
- Entity :: struct {
-
- kind: EntityKind,
- guid: Guid,
-
- scope: ^Scope,
- token: Token,
- type_: ^Type,
-
- using data: raw_union {
- Constant: struct {
- value: ExactValue,
- },
- Variable: struct {
- visited: bool, // Cycle detection
- used: bool, // Variable is used
- is_field: bool, // Is struct field
- anonymous: bool, // Variable is an anonymous
- },
- UsingVariable: struct {
- },
- TypeName: struct {
- },
- Procedure: struct {
- used: bool,
- },
- Builtin: struct {
- id: int,
- },
- },
- }
-
- // Plus all the constructing procedures that go along with them!!!!
- // It's a nightmare
- }
-
- {
- Type :: struct {};
- Scope :: struct {};
- Token :: struct {};
- AstNode :: struct {};
- ExactValue :: struct {};
-
-
- Guid :: i64;
- Entity_Base :: struct {
-
- }
-
- Entity :: union {
- guid: Guid,
-
- scope: ^Scope,
- token: Token,
- type_: ^Type,
-
- Constant{
- value: ExactValue,
- },
- Variable{
- visited: bool, // Cycle detection
- used: bool, // Variable is used
- is_field: bool, // Is struct field
- anonymous: bool, // Variable is an anonymous
- },
- UsingVariable{
- },
- TypeName{
- },
- Procedure{
- used: bool,
- },
- Builtin{
- id: int,
- },
- }
-
- using Entity;
-
- e: Entity;
-
- e = 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 :: raw_union {
- using xy_: struct { x, y: f32 },
- e: [2]f32,
- v: [vector 2]f32,
- }
-
- Vector3 :: 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/code/old_demos/demo004.odin b/code/old_demos/demo004.odin
deleted file mode 100644
index 86588d60d..000000000
--- a/code/old_demos/demo004.odin
+++ /dev/null
@@ -1,66 +0,0 @@
-#import "fmt.odin";
-#import "utf8.odin";
-#import "hash.odin";
-#import "mem.odin";
-
-main :: proc() {
- { // New Standard Library stuff
- s := "Hello";
- fmt.println(s,
- utf8.valid_string(s),
- hash.murmur64(cast([]byte)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.free_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/code/old_demos/demo005.odin b/code/old_demos/demo005.odin
deleted file mode 100644
index f9d1a4a4c..000000000
--- a/code/old_demos/demo005.odin
+++ /dev/null
@@ -1,284 +0,0 @@
-#import "fmt.odin";
-#import "utf8.odin";
-// #import "atomic.odin";
-// #import "hash.odin";
-// #import "math.odin";
-// #import "mem.odin";
-// #import "opengl.odin";
-// #import "os.odin";
-// #import "sync.odin";
-// #import win32 "sys/windows.odin";
-
-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; compile_assert(size_of_val(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;
- immutable const := Prefix_Type{1, 2, nil};
- var.x = 123;
- x = 123;
- // const.x = 123; // const is immutable
-
-
-
- foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
- // int_ptr = nil; // Not valid
- // int_ptr^ = 123; // Not valid
- }
-
-
-
- // 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();
-}
-
-#foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
-// NOTE: This is done on purpose for two reasons:
-// * Makes it clear where the platform specific stuff is
-// * Removes the need to solve the travelling salesman problem when importing files :P
-
-foreign_procedures :: proc() {
- ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user;
- show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #foreign win32_user "ShowWindow";
- // 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 {
- compile_assert(type_of_val(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/code/old_demos/old_runtime.odin b/code/old_demos/old_runtime.odin
deleted file mode 100644
index 655058e0a..000000000
--- a/code/old_demos/old_runtime.odin
+++ /dev/null
@@ -1,412 +0,0 @@
-#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
- compile_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/code/punity.odin b/code/punity.odin
deleted file mode 100644
index 0c0fac786..000000000
--- a/code/punity.odin
+++ /dev/null
@@ -1,498 +0,0 @@
-import (
- win32 "sys/windows.odin";
- "fmt.odin";
- "os.odin";
- "mem.odin";
-)
-
-const (
- CANVAS_WIDTH = 128;
- CANVAS_HEIGHT = 128;
- CANVAS_SCALE = 3;
- FRAME_TIME = 1.0/30.0;
- WINDOW_TITLE = "Punity\x00";
-)
-
-const _ = compile_assert(CANVAS_WIDTH % 16 == 0);
-
-const (
- WINDOW_WIDTH = CANVAS_WIDTH * CANVAS_SCALE;
- WINDOW_HEIGHT = CANVAS_HEIGHT * CANVAS_SCALE;
-)
-
-const (
- STACK_CAPACITY = 1<<20;
- STORAGE_CAPACITY = 1<<20;
-
- DRAW_LIST_RESERVE = 128;
-
- MAX_KEYS = 256;
-)
-
-type Core struct {
- stack: ^Bank,
- storage: ^Bank,
-
- running: bool,
- key_modifiers: u32,
- key_states: [MAX_KEYS]u8,
- key_deltas: [MAX_KEYS]u8,
-
- perf_frame,
- perf_frame_inner,
- perf_step,
- perf_audio,
- perf_blit,
- perf_blit_cvt,
- perf_blit_gdi: Perf_Span,
-
- frame: i64,
-
- canvas: Canvas,
- draw_list: ^Draw_List,
-}
-
-type Perf_Span struct {
- stamp: f64,
- delta: f32,
-}
-
-type Bank struct {
- memory: []u8,
- cursor: int,
-}
-
-type Bank_State struct {
- state: Bank,
- bank: ^Bank,
-}
-
-
-type Color raw_union {
- using channels: struct{a, b, g, r: u8},
- rgba: u32,
-}
-
-type Palette struct {
- colors: [256]Color,
- colors_count: u8,
-}
-
-
-type Rect raw_union {
- using minmax: struct {min_x, min_y, max_x, max_y: int},
- using pos: struct {left, top, right, bottom: int},
- e: [4]int,
-}
-
-type Bitmap struct {
- pixels: []u8,
- width: int,
- height: int,
-}
-
-type Font struct {
- using bitmap: Bitmap,
- char_width: int,
- char_height: int,
-}
-
-type Canvas struct {
- using bitmap: ^Bitmap,
- palette: Palette,
- translate_x: int,
- translate_y: int,
- clip: Rect,
- font: ^Font,
-}
-
-type DrawFlag enum {
- NONE = 0,
- FLIP_H = 1<<0,
- FLIP_V = 1<<1,
- MASK = 1<<2,
-}
-
-type Draw_Item struct {}
-type Draw_List struct {
- items: []Draw_Item,
-}
-
-type Key enum {
- ModShift = 0x0001,
- ModControl = 0x0002,
- ModAlt = 0x0004,
- ModSuper = 0x0008,
-
-
- Unknown =-1,
- Invalid =-2,
-
-
- Lbutton = 1,
- Rbutton = 2,
- Cancel = 3,
- Mbutton = 4,
-
-
- Back = 8,
- Tab = 9,
- Clear = 12,
- Return = 13,
- Shift = 16,
- Control = 17,
- Menu = 18,
- Pause = 19,
- Capital = 20,
- Kana = 0x15,
- Hangeul = 0x15,
- Hangul = 0x15,
- Junja = 0x17,
- Final = 0x18,
- Hanja = 0x19,
- Kanji = 0x19,
- Escape = 0x1B,
- Convert = 0x1C,
- NonConvert = 0x1D,
- Accept = 0x1E,
- ModeChange = 0x1F,
- Space = 32,
- Prior = 33,
- Next = 34,
- End = 35,
- Home = 36,
- Left = 37,
- Up = 38,
- Right = 39,
- Down = 40,
- Select = 41,
- Print = 42,
- Exec = 43,
- Snapshot = 44,
- Insert = 45,
- Delete = 46,
- Help = 47,
- Lwin = 0x5B,
- Rwin = 0x5C,
- Apps = 0x5D,
- Sleep = 0x5F,
- Numpad0 = 0x60,
- Numpad1 = 0x61,
- Numpad2 = 0x62,
- Numpad3 = 0x63,
- Numpad4 = 0x64,
- Numpad5 = 0x65,
- Numpad6 = 0x66,
- Numpad7 = 0x67,
- Numpad8 = 0x68,
- Numpad9 = 0x69,
- Multiply = 0x6A,
- Add = 0x6B,
- Separator = 0x6C,
- Subtract = 0x6D,
- Decimal = 0x6E,
- Divide = 0x6F,
- F1 = 0x70,
- F2 = 0x71,
- F3 = 0x72,
- F4 = 0x73,
- F5 = 0x74,
- F6 = 0x75,
- F7 = 0x76,
- F8 = 0x77,
- F9 = 0x78,
- F10 = 0x79,
- F11 = 0x7A,
- F12 = 0x7B,
- F13 = 0x7C,
- F14 = 0x7D,
- F15 = 0x7E,
- F16 = 0x7F,
- F17 = 0x80,
- F18 = 0x81,
- F19 = 0x82,
- F20 = 0x83,
- F21 = 0x84,
- F22 = 0x85,
- F23 = 0x86,
- F24 = 0x87,
- Numlock = 0x90,
- Scroll = 0x91,
- Lshift = 0xA0,
- Rshift = 0xA1,
- Lcontrol = 0xA2,
- Rcontrol = 0xA3,
- Lmenu = 0xA4,
- Rmenu = 0xA5,
-
-
- Apostrophe = 39, /* ' */
- Comma = 44, /* , */
- Minus = 45, /* - */
- Period = 46, /* . */
- Slash = 47, /* / */
- Num0 = 48,
- Num1 = 49,
- Num2 = 50,
- Num3 = 51,
- Num4 = 52,
- Num5 = 53,
- Num6 = 54,
- Num7 = 55,
- Num8 = 56,
- Num9 = 57,
- Semicolon = 59, /* ; */
- Equal = 61, /* = */
- A = 65,
- B = 66,
- C = 67,
- D = 68,
- E = 69,
- F = 70,
- G = 71,
- H = 72,
- I = 73,
- J = 74,
- K = 75,
- L = 76,
- M = 77,
- N = 78,
- O = 79,
- P = 80,
- Q = 81,
- R = 82,
- S = 83,
- T = 84,
- U = 85,
- V = 86,
- W = 87,
- X = 88,
- Y = 89,
- Z = 90,
- LeftBracket = 91, /* [ */
- Backslash = 92, /* \ */
- RightBracket = 93, /* ] */
- GraveAccent = 96, /* ` */
-};
-
-
-proc key_down(k: Key) -> bool {
- return _core.key_states[k] != 0;
-}
-
-proc key_pressed(k: Key) -> bool {
- return (_core.key_deltas[k] != 0) && key_down(k);
-}
-
-
-
-
-let win32_perf_count_freq = win32.get_query_performance_frequency();
-proc time_now() -> f64 {
- assert(win32_perf_count_freq != 0);
-
- var counter: i64;
- win32.query_performance_counter(&counter);
- return f64(counter) / f64(win32_perf_count_freq);
-}
-
-var _core: Core;
-
-proc run(user_init, user_step: proc(c: ^Core)) {
- using win32;
-
- _core.running = true;
-
- proc win32_proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
- proc win32_app_key_mods() -> u32 {
- var mods: u32 = 0;
-
- if is_key_down(KeyCode.Shift) {
- mods |= u32(Key.ModShift);
- }
- if is_key_down(KeyCode.Control) {
- mods |= u32(Key.ModControl);
- }
- if is_key_down(KeyCode.Menu) {
- mods |= u32(Key.ModAlt);
- }
- if is_key_down(KeyCode.Lwin) || is_key_down(KeyCode.Rwin) {
- mods |= u32(Key.ModSuper);
- }
-
- return mods;
- }
-
- match msg {
- case WM_KEYDOWN:
- _core.key_modifiers = win32_app_key_mods();
- if wparam < MAX_KEYS {
- _core.key_states[wparam] = 1;
- _core.key_deltas[wparam] = 1;
- }
- return 0;
-
- case WM_KEYUP:
- _core.key_modifiers = win32_app_key_mods();
- if wparam < MAX_KEYS {
- _core.key_states[wparam] = 0;
- _core.key_deltas[wparam] = 1;
- }
- return 0;
-
- case WM_CLOSE:
- post_quit_message(0);
- _core.running = false;
- return 0;
- }
-
- return def_window_proc_a(hwnd, msg, wparam, lparam);
- }
-
-
- var class_name = "Punity\x00";
- var window_class = WndClassExA{
- class_name = &class_name[0],
- size = size_of(WndClassExA),
- style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
- instance = Hinstance(get_module_handle_a(nil)),
- wnd_proc = win32_proc,
- // wnd_proc = DefWindowProcA,
- background = Hbrush(get_stock_object(BLACK_BRUSH)),
- };
-
- if register_class_ex_a(&window_class) == 0 {
- fmt.fprintln(os.stderr, "register_class_ex_a failed");
- return;
- }
-
- var screen_width = get_system_metrics(SM_CXSCREEN);
- var screen_height = get_system_metrics(SM_CYSCREEN);
-
- var rc: Rect;
- rc.left = (screen_width - WINDOW_WIDTH) / 2;
- rc.top = (screen_height - WINDOW_HEIGHT) / 2;
- rc.right = rc.left + WINDOW_WIDTH;
- rc.bottom = rc.top + WINDOW_HEIGHT;
-
- var style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
- assert(adjust_window_rect(&rc, style, 0) != 0);
-
- var wt = WINDOW_TITLE;
-
- var win32_window = create_window_ex_a(0,
- window_class.class_name,
- &wt[0],
- style,
- rc.left, rc.top,
- rc.right-rc.left, rc.bottom-rc.top,
- nil, nil, window_class.instance,
- nil);
-
- if win32_window == nil {
- fmt.fprintln(os.stderr, "create_window_ex_a failed");
- return;
- }
-
-
- var window_bmi: BitmapInfo;
- window_bmi.size = size_of(BitmapInfoHeader);
- window_bmi.width = CANVAS_WIDTH;
- window_bmi.height = CANVAS_HEIGHT;
- window_bmi.planes = 1;
- window_bmi.bit_count = 32;
- window_bmi.compression = BI_RGB;
-
-
- user_init(&_core);
-
- show_window(win32_window, SW_SHOW);
-
- var window_buffer = make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
- defer free(window_buffer);
-
- for _, i in window_buffer {
- window_buffer[i] = 0xff00ff;
- }
-
- var (
- dt: f64;
- prev_time = time_now();
- curr_time = time_now();
- total_time : f64 = 0;
- offset_x = 0;
- offset_y = 0;
- )
-
- var message: Msg;
- for _core.running {
- curr_time = time_now();
- dt = curr_time - prev_time;
- prev_time = curr_time;
- total_time += dt;
-
- offset_x += 1;
- offset_y += 2;
-
- {
- var buf: [128]u8;
- var s = fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
- win32.set_window_text_a(win32_window, &s[0]);
- }
-
-
- for var y = 0; y < CANVAS_HEIGHT; y++ {
- for var x = 0; x < CANVAS_WIDTH; x++ {
- var g = (x % 32) * 8;
- var b = (y % 32) * 8;
- window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
- }
- }
-
- mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
-
- for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
- if message.message == WM_QUIT {
- _core.running = false;
- }
- translate_message(&message);
- dispatch_message_a(&message);
- }
-
- user_step(&_core);
-
- var dc = get_dc(win32_window);
- stretch_dibits(dc,
- 0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
- 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- &window_buffer[0],
- &window_bmi,
- DIB_RGB_COLORS,
- SRCCOPY);
- release_dc(win32_window, dc);
-
-
- {
- var delta = time_now() - prev_time;
- var ms = i32((FRAME_TIME - delta) * 1000);
- if ms > 0 {
- win32.sleep(ms);
- }
- }
-
- _core.frame++;
- }
-}
-
-
-proc main() {
- proc user_init(c: ^Core) {
-
- }
-
- proc user_step(c: ^Core) {
-
- }
-
- run(user_init, user_step);
-}
diff --git a/core/_preload.odin b/core/_preload.odin
index c7a4a9d33..f394ae0e5 100644
--- a/core/_preload.odin
+++ b/core/_preload.odin
@@ -1,11 +1,10 @@
#shared_global_scope;
-import (
- "os.odin";
- "fmt.odin"; // TODO(bill): Remove the need for `fmt` here
- "utf8.odin";
- "raw.odin";
-)
+import "os.odin";
+import "fmt.odin"; // TODO(bill): Remove the need for `fmt` here
+import "utf8.odin";
+import "raw.odin";
+
// Naming Conventions:
// In general, Ada_Case for types and snake_case for values
//
diff --git a/core/fmt.odin b/core/fmt.odin
index a14c9056a..f962b8a95 100644
--- a/core/fmt.odin
+++ b/core/fmt.odin
@@ -1,11 +1,9 @@
-import (
- "os.odin";
- "mem.odin";
- "utf8.odin";
- "types.odin";
- "strconv.odin";
- "raw.odin";
-)
+import "os.odin";
+import "mem.odin";
+import "utf8.odin";
+import "types.odin";
+import "strconv.odin";
+import "raw.odin";
_BUFFER_SIZE :: 1<<12;
diff --git a/core/mem.odin b/core/mem.odin
index bd1e6f6ed..cce8492f6 100644
--- a/core/mem.odin
+++ b/core/mem.odin
@@ -1,8 +1,7 @@
-import (
- "fmt.odin";
- "os.odin";
- "raw.odin";
-)
+import "fmt.odin";
+import "os.odin";
+import "raw.odin";
+
foreign __llvm_core {
swap :: proc(b: u16) -> u16 #link_name "llvm.bswap.i16" ---;
swap :: proc(b: u32) -> u32 #link_name "llvm.bswap.i32" ---;
diff --git a/core/opengl.odin b/core/opengl.odin
index 9ec29704f..a3c5217ce 100644
--- a/core/opengl.odin
+++ b/core/opengl.odin
@@ -2,11 +2,9 @@ foreign_system_library (
lib "opengl32.lib" when ODIN_OS == "windows";
lib "gl" when ODIN_OS == "linux";
)
-import (
- win32 "sys/windows.odin" when ODIN_OS == "windows";
- "sys/wgl.odin" when ODIN_OS == "windows";
-)
-import_load "opengl_constants.odin";
+import win32 "sys/windows.odin" when ODIN_OS == "windows";
+import "sys/wgl.odin" when ODIN_OS == "windows";
+using import . "opengl_constants.odin";
_ := compile_assert(ODIN_OS != "osx");
diff --git a/core/os.odin b/core/os.odin
index 1ae1c9e84..e9b854135 100644
--- a/core/os.odin
+++ b/core/os.odin
@@ -1,8 +1,6 @@
-import_load (
- "os_windows.odin" when ODIN_OS == "windows";
- "os_x.odin" when ODIN_OS == "osx";
- "os_linux.odin" when ODIN_OS == "linux";
-)
+using import . "os_windows.odin" when ODIN_OS == "windows";
+using import . "os_x.odin" when ODIN_OS == "osx";
+using import . "os_linux.odin" when ODIN_OS == "linux";
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
return write(fd, cast([]u8)str);
diff --git a/core/strconv.odin b/core/strconv.odin
index 789379a24..792835c8f 100644
--- a/core/strconv.odin
+++ b/core/strconv.odin
@@ -1,4 +1,4 @@
-import . "decimal.odin";
+using import "decimal.odin";
Int_Flag :: enum {
Prefix = 1<<0,
diff --git a/core/sync.odin b/core/sync.odin
index ad08f0b18..46f210e9d 100644
--- a/core/sync.odin
+++ b/core/sync.odin
@@ -1,4 +1,2 @@
-import_load (
- "sync_windows.odin" when ODIN_OS == "windows";
- "sync_linux.odin" when ODIN_OS == "linux";
-)
+using import . "sync_windows.odin" when ODIN_OS == "windows";
+using import . "sync_linux.odin" when ODIN_OS == "linux";
diff --git a/core/sync_linux.odin b/core/sync_linux.odin
index 9e7f20d51..e38c80111 100644
--- a/core/sync_linux.odin
+++ b/core/sync_linux.odin
@@ -1,7 +1,5 @@
-import (
- "atomics.odin";
- "os.odin";
-)
+import "atomics.odin";
+import "os.odin";
Semaphore :: struct {
// _handle: win32.Handle;
diff --git a/core/sync_windows.odin b/core/sync_windows.odin
index 0b7477bc2..fa270edfe 100644
--- a/core/sync_windows.odin
+++ b/core/sync_windows.odin
@@ -1,7 +1,5 @@
-import (
- win32 "sys/windows.odin" when ODIN_OS == "windows";
- "atomics.odin";
-)
+import win32 "sys/windows.odin" when ODIN_OS == "windows";
+import "atomics.odin";
Semaphore :: struct {
_handle: win32.Handle;
diff --git a/core/sys/wgl.odin b/core/sys/wgl.odin
index 44d0df1a9..46e388057 100644
--- a/core/sys/wgl.odin
+++ b/core/sys/wgl.odin
@@ -1,5 +1,5 @@
foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
-import . "windows.odin";
+using import "windows.odin";
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
diff --git a/core/sys/windows.odin b/core/sys/windows.odin
index 12b07ad63..53b8a1434 100644
--- a/core/sys/windows.odin
+++ b/core/sys/windows.odin
@@ -457,7 +457,7 @@ foreign gdi32 {
stretch_dibits :: proc(hdc: Hdc,
x_dst, y_dst, width_dst, height_dst: i32,
x_src, y_src, width_src, header_src: i32,
- bits: rawptr, bits_info: ^BitmapInfo,
+ bits: rawptr, bits_info: ^Bitmap_Info,
usage: u32,
rop: u32) -> i32 #cc_std #link_name "StretchDIBits" ---;
@@ -572,7 +572,7 @@ Bitmap_Info_Header :: struct #ordered {
clr_used: u32;
clr_important: u32;
}
-BitmapInfo :: struct #ordered {
+Bitmap_Info :: struct #ordered {
using header: Bitmap_Info_Header;
colors: [1]Rgb_Quad;
}
diff --git a/src/checker.cpp b/src/checker.cpp
index feab9669f..ab4de9a16 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1942,27 +1942,21 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco
}
case_end;
+ case_ast_node(id, ImportDecl, decl);
+ if (!c->context.scope->is_file) {
+ error(decl, "import declarations are only allowed in the file scope");
+ // NOTE(bill): _Should_ be caught by the parser
+ // TODO(bill): Better error handling if it isn't
+ continue;
+ }
+ DelayedDecl di = {c->context.scope, decl};
+ array_add(&c->delayed_imports, di);
+ case_end;
+
case_ast_node(gd, GenDecl, decl);
for_array(i, gd->specs) {
AstNode *spec = gd->specs[i];
switch (gd->token.kind) {
- case Token_import:
- case Token_import_load: {
- ast_node(ts, ImportSpec, spec);
- if (!c->context.scope->is_file) {
- if (ts->is_import) {
- error(decl, "import declarations are only allowed in the file scope");
- } else {
- error(decl, "import_load declarations are only allowed in the file scope");
- }
- // NOTE(bill): _Should_ be caught by the parser
- // TODO(bill): Better error handling if it isn't
- continue;
- }
- DelayedDecl di = {c->context.scope, spec};
- array_add(&c->delayed_imports, di);
- } break;
-
case Token_foreign_library:
case Token_foreign_system_library: {
ast_node(fl, ForeignLibrarySpec, spec);
@@ -2202,7 +2196,7 @@ void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) {
struct ImportGraphNode {
Scope * scope;
- Array specs;
+ Array decls; // AstNodeImportDecl *
String path;
isize file_id;
ImportGraphNodeSet pred;
@@ -2216,7 +2210,7 @@ ImportGraphNode *import_graph_node_create(gbAllocator a, Scope *scope) {
n->scope = scope;
n->path = scope->file->tokenizer.fullpath;
n->file_id = scope->file->id;
- array_init(&n->specs, heap_allocator());
+ array_init(&n->decls, heap_allocator());
return n;
}
@@ -2224,6 +2218,7 @@ ImportGraphNode *import_graph_node_create(gbAllocator a, Scope *scope) {
void import_graph_node_destroy(ImportGraphNode *n, gbAllocator a) {
import_graph_node_set_destroy(&n->pred);
import_graph_node_set_destroy(&n->succ);
+ array_free(&n->decls);
gb_free(a, n);
}
@@ -2282,7 +2277,7 @@ Array generate_import_dependency_graph(Checker *c, Mapdelayed_imports[i].decl;
GB_ASSERT(parent->is_file);
- ast_node(id, ImportSpec, decl);
+ ast_node(id, ImportDecl, decl);
String path = id->fullpath;
HashKey key = hash_string(path);
@@ -2310,10 +2305,9 @@ Array generate_import_dependency_graph(Checker *c, Mapspecs, decl);
+ array_add(&m->decls, decl);
- bool is_dot_or_load = id->import_name.string == ".";
- if (is_dot_or_load) {
+ if (id->is_using) {
import_graph_node_set_add(&n->pred, m);
import_graph_node_set_add(&m->succ, n);
ptr_set_add(&m->scope->imported, n->scope);
@@ -2326,7 +2320,7 @@ Array generate_import_dependency_graph(Checker *c, Mapvalue;
- gb_sort_array(n->specs.data, n->specs.count, ast_node_cmp);
+ gb_sort_array(n->decls.data, n->decls.count, ast_node_cmp);
array_add(&G, n);
}
@@ -2340,7 +2334,7 @@ Array generate_import_dependency_graph(Checker *c, Map find_import_path(Map *map, Scope *start, Scope *end, PtrSet *visited = nullptr) {
+Array find_import_path(Map *file_scopes, Scope *start, Scope *end, PtrSet *visited = nullptr) {
PtrSet visited_ = {};
bool made_visited = false;
if (visited == nullptr) {
@@ -2361,7 +2355,7 @@ Array find_import_path(Map *map, Scope *start, Scope *end, Ptr
String path = start->file->tokenizer.fullpath;
HashKey key = hash_string(path);
- Scope **found = map_get(map, key);
+ Scope **found = map_get(file_scopes, key);
if (found) {
Scope *scope = *found;
for_array(i, scope->imported.entries) {
@@ -2372,7 +2366,7 @@ Array find_import_path(Map *map, Scope *start, Scope *end, Ptr
array_add(&path, dep);
return path;
}
- Array next_path = find_import_path(map, dep, end, visited);
+ Array next_path = find_import_path(file_scopes, dep, end, visited);
if (next_path.count > 0) {
array_add(&next_path, dep);
return next_path;
@@ -2412,6 +2406,7 @@ void check_import_entities(Checker *c, Map *file_scopes) {
defer (array_free(&path));
if (path.count > 0) {
+ // TODO(bill): This needs better TokenPos finding
auto const mt = [](Scope *s) -> Token {
Token token = {};
token.pos = token_pos(s->file->tokenizer.fullpath, 1, 1);
@@ -2453,9 +2448,9 @@ void check_import_entities(Checker *c, Map *file_scopes) {
for_array(file_index, file_order) {
ImportGraphNode *node = file_order[file_index];
Scope *parent_scope = node->scope;
- for_array(i, node->specs) {
- AstNode *spec = node->specs[i];
- ast_node(id, ImportSpec, spec);
+ for_array(i, node->decls) {
+ AstNode *decl = node->decls[i];
+ ast_node(id, ImportDecl, decl);
Token token = id->relpath;
GB_ASSERT(parent_scope->is_file);
@@ -2496,34 +2491,30 @@ void check_import_entities(Checker *c, Map *file_scopes) {
scope->has_been_imported = true;
- if (id->import_name.string == ".") {
+ if (id->is_using) {
if (parent_scope->is_global) {
- error(id->import_name, "#shared_global_scope imports cannot use .");
+ error(id->import_name, "#shared_global_scope imports cannot use using");
} else {
// NOTE(bill): Add imported entities to this file's scope
for_array(elem_index, scope->elements.entries) {
Entity *e = scope->elements.entries[elem_index].value;
- if (e->scope == parent_scope) {
- continue;
- }
+ if (e->scope == parent_scope) continue;
if (!is_entity_kind_exported(e->kind)) {
continue;
}
- if (id->is_import) {
+ if (id->import_name.string == ".") {
+ add_entity(c, parent_scope, e->identifier, e);
+ } else {
if (is_entity_exported(e)) {
// TODO(bill): Should these entities be imported but cause an error when used?
bool ok = add_entity(c, parent_scope, e->identifier, e);
- if (ok) {
- map_set(&parent_scope->implicit, hash_entity(e), true);
- }
+ if (ok) map_set(&parent_scope->implicit, hash_entity(e), true);
}
- } else {
- add_entity(c, parent_scope, e->identifier, e);
}
}
}
- } else {
+ } else if (id->import_name.string != ".") {
String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
if (is_blank_ident(import_name)) {
error(token, "File name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
diff --git a/src/docs.cpp b/src/docs.cpp
index 44c969181..8890d7ccc 100644
--- a/src/docs.cpp
+++ b/src/docs.cpp
@@ -96,7 +96,6 @@ void print_declaration(AstNode *decl) {
AstNode *spec = gd->specs[spec_index];
switch(gd->token.kind) {
case Token_import:
- case Token_import_load:
break;
case Token_foreign_library:
case Token_foreign_system_library:
diff --git a/src/parser.cpp b/src/parser.cpp
index cc6837a9f..1045f75fb 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -20,8 +20,8 @@ struct CommentGroup {
};
-enum ImportedFileKind {
- ImportedFile_Normal,
+enum ImportedFileKind
+{ ImportedFile_Normal,
ImportedFile_Shared,
ImportedFile_Init,
};
@@ -352,8 +352,9 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
CommentGroup docs; \
CommentGroup comment; \
}) \
- AST_NODE_KIND(ImportSpec, "import specification", struct { \
- bool is_import; \
+ AST_NODE_KIND(ImportDecl, "import declaration", struct { \
+ Token token; \
+ bool is_using; \
Token relpath; \
String fullpath; \
Token import_name; \
@@ -582,7 +583,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_GenDecl: return node->GenDecl.token;
case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names[0]);
- case AstNode_ImportSpec: return node->ImportSpec.import_name;
+ case AstNode_ImportDecl: return node->ImportDecl.token;
case AstNode_ForeignBlockDecl: return node->ForeignBlockDecl.token;
@@ -1547,15 +1548,16 @@ AstNode *ast_value_decl(AstFile *f, Array names, AstNode *type, Array
return result;
}
-AstNode *ast_import_spec(AstFile *f, bool is_import, Token relpath, Token import_name, AstNode *cond,
+AstNode *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Token import_name, AstNode *cond,
CommentGroup docs, CommentGroup comment) {
- AstNode *result = make_ast_node(f, AstNode_ImportSpec);
- result->ImportSpec.is_import = is_import;
- result->ImportSpec.relpath = relpath;
- result->ImportSpec.import_name = import_name;
- result->ImportSpec.cond = cond;
- result->ImportSpec.docs = docs;
- result->ImportSpec.comment = comment;
+ AstNode *result = make_ast_node(f, AstNode_ImportDecl);
+ result->ImportDecl.token = token;
+ result->ImportDecl.is_using = is_using;
+ result->ImportDecl.relpath = relpath;
+ result->ImportDecl.import_name = import_name;
+ result->ImportDecl.cond = cond;
+ result->ImportDecl.docs = docs;
+ result->ImportDecl.comment = comment;
return result;
}
@@ -1899,7 +1901,6 @@ void expect_semicolon(AstFile *f, AstNode *s) {
if (s->kind == AstNode_GenDecl) {
switch (s->GenDecl.token.kind) {
case Token_import:
- case Token_import_load:
node_string = str_lit("import declaration");
break;
case Token_foreign_library:
@@ -3060,61 +3061,61 @@ AstNode *parse_gen_decl(AstFile *f, Token token, ParseSpecFunc *func) {
return ast_gen_decl(f, token, open, close, specs, docs);
}
-PARSE_SPEC_FUNC(parse_import_spec) {
- AstNode *spec = nullptr;
- if (token.kind == Token_import) {
- AstNode *cond = nullptr;
- Token import_name = {};
+// PARSE_SPEC_FUNC(parse_import_spec) {
+// AstNode *spec = nullptr;
+// if (token.kind == Token_import) {
+// AstNode *cond = nullptr;
+// Token import_name = {};
- switch (f->curr_token.kind) {
- case Token_Period:
- import_name = advance_token(f);
- import_name.kind = Token_Ident;
- break;
- case Token_Ident:
- import_name = advance_token(f);
- break;
- default:
- import_name.pos = f->curr_token.pos;
- break;
- }
+// switch (f->curr_token.kind) {
+// case Token_Period:
+// import_name = advance_token(f);
+// import_name.kind = Token_Ident;
+// break;
+// case Token_Ident:
+// import_name = advance_token(f);
+// break;
+// default:
+// import_name.pos = f->curr_token.pos;
+// break;
+// }
- if (is_blank_ident(import_name)) {
- syntax_error(import_name, "Illegal import name: `_`");
- }
+// if (is_blank_ident(import_name)) {
+// syntax_error(import_name, "Illegal import name: `_`");
+// }
- Token file_path = expect_token_after(f, Token_String, "import");
- if (allow_token(f, Token_when)) {
- cond = parse_expr(f, false);
- }
+// Token file_path = expect_token_after(f, Token_String, "import");
+// if (allow_token(f, Token_when)) {
+// cond = parse_expr(f, false);
+// }
- expect_semicolon(f, nullptr);
- if (f->curr_proc != nullptr) {
- syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope");
- spec = ast_bad_decl(f, import_name, file_path);
- } else {
- spec = ast_import_spec(f, true, file_path, import_name, cond, docs, f->line_comment);
- }
- } else {
- AstNode *cond = nullptr;
- Token file_path = expect_token_after(f, Token_String, "import_load");
- Token import_name = file_path;
- import_name.string = str_lit(".");
+// expect_semicolon(f, nullptr);
+// if (f->curr_proc != nullptr) {
+// syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope");
+// spec = ast_bad_decl(f, import_name, file_path);
+// } else {
+// spec = ast_import_decl(f, true, file_path, import_name, cond, docs, f->line_comment);
+// }
+// } else {
+// AstNode *cond = nullptr;
+// Token file_path = expect_token_after(f, Token_String, "import_load");
+// Token import_name = file_path;
+// import_name.string = str_lit(".");
- if (allow_token(f, Token_when)) {
- cond = parse_expr(f, false);
- }
+// if (allow_token(f, Token_when)) {
+// cond = parse_expr(f, false);
+// }
- expect_semicolon(f, nullptr);
- if (f->curr_proc != nullptr) {
- syntax_error(import_name, "You cannot use `import_load` within a procedure. This must be done at the file scope");
- spec = ast_bad_decl(f, import_name, file_path);
- } else {
- spec = ast_import_spec(f, false, file_path, import_name, cond, docs, f->line_comment);
- }
- }
- return spec;
-}
+// expect_semicolon(f, nullptr);
+// if (f->curr_proc != nullptr) {
+// syntax_error(import_name, "You cannot use `import_load` within a procedure. This must be done at the file scope");
+// spec = ast_bad_decl(f, import_name, file_path);
+// } else {
+// spec = ast_import_decl(f, false, file_path, import_name, cond, docs, f->line_comment);
+// }
+// }
+// return spec;
+// }
PARSE_SPEC_FUNC(parse_foreign_library_spec) {
AstNode *spec = nullptr;
@@ -3205,10 +3206,9 @@ void parse_foreign_block_decl(AstFile *f, Array *decls) {
AstNode *parse_decl(AstFile *f) {
ParseSpecFunc *func = nullptr;
switch (f->curr_token.kind) {
- case Token_import:
- case Token_import_load:
- func = parse_import_spec;
- break;
+ // case Token_import:
+ // func = parse_import_spec;
+ // break;
case Token_foreign_library:
case Token_foreign_system_library:
@@ -4524,7 +4524,45 @@ AstNode *parse_asm_stmt(AstFile *f) {
return ast_asm_stmt(f, token, is_volatile, open, close, code_string,
output_list, input_list, clobber_list,
output_count, input_count, clobber_count);
+}
+
+AstNode *parse_import_decl(AstFile *f, bool is_using) {
+ CommentGroup docs = f->lead_comment;
+ Token token = expect_token(f, Token_import);
+ AstNode *cond = nullptr;
+ Token import_name = {};
+
+ switch (f->curr_token.kind) {
+ case Token_Ident:
+ import_name = advance_token(f);
+ break;
+ case Token_Period:
+ import_name = advance_token(f);
+ import_name.kind = Token_Ident;
+ if (is_using) break;
+ syntax_error(import_name, "`import .` is not allowed. Did you mean `using import`?");
+ /* fallthrough */
+ default:
+ import_name.pos = f->curr_token.pos;
+ break;
+ }
+
+ if (is_blank_ident(import_name)) {
+ syntax_error(import_name, "Illegal import name: `_`");
+ }
+
+ Token file_path = expect_token_after(f, Token_String, "import");
+ if (allow_token(f, Token_when)) {
+ cond = parse_expr(f, false);
+ }
+
+ expect_semicolon(f, nullptr);
+ if (f->curr_proc != nullptr) {
+ syntax_error(import_name, "You cannot use `import` within a procedure. This must be done at the file scope");
+ return ast_bad_decl(f, import_name, file_path);
+ }
+ return ast_import_decl(f, token, is_using, file_path, import_name, cond, docs, f->line_comment);
}
@@ -4552,12 +4590,7 @@ AstNode *parse_stmt(AstFile *f) {
expect_semicolon(f, s);
return s;
- // case Token_var:
- // case Token_const:
- // case Token_proc:
- // case Token_type:
- case Token_import:
- case Token_import_load:
+
case Token_foreign:
case Token_foreign_library:
case Token_foreign_system_library:
@@ -4565,6 +4598,8 @@ AstNode *parse_stmt(AstFile *f) {
expect_semicolon(f, s);
return s;
+ case Token_import:
+ return parse_import_decl(f, false);
case Token_if: return parse_if_stmt(f);
case Token_when: return parse_when_stmt(f);
@@ -4573,7 +4608,6 @@ AstNode *parse_stmt(AstFile *f) {
case Token_defer: return parse_defer_stmt(f);
case Token_asm: return parse_asm_stmt(f);
case Token_return: return parse_return_stmt(f);
- // case Token_give: return parse_give_stmt(f);
case Token_break:
case Token_continue:
@@ -4592,6 +4626,10 @@ AstNode *parse_stmt(AstFile *f) {
case Token_using: {
CommentGroup docs = f->lead_comment;
Token token = expect_token(f, Token_using);
+ if (f->curr_token.kind == Token_import) {
+ return parse_import_decl(f, true);
+ }
+
AstNode *decl = nullptr;
Array list = parse_lhs_expr_list(f);
if (list.count == 0) {
@@ -4909,49 +4947,41 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Arraykind != AstNode_EmptyStmt) {
// NOTE(bill): Sanity check
syntax_error(node, "Only declarations are allowed at file scope %.*s", LIT(ast_node_strings[node->kind]));
+ } else if (node->kind == AstNode_ImportDecl) {
+ ast_node(id, ImportDecl, node);
+ String collection_name = {};
+ String oirignal_string = id->relpath.string;
+ String file_str = id->relpath.string;
+ gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
+ String import_file = {};
+ String rel_path = {};
+
+ if (!is_import_path_valid(file_str)) {
+ syntax_error(node, "Invalid import path: `%.*s`", LIT(file_str));
+ // NOTE(bill): It's a naughty name
+ decls[i] = ast_bad_decl(f, id->relpath, id->relpath);
+ continue;
+ }
+
+ gb_mutex_lock(&p->file_decl_mutex);
+ defer (gb_mutex_unlock(&p->file_decl_mutex));
+
+ rel_path = get_fullpath_relative(a, base_dir, file_str);
+ import_file = rel_path;
+ if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
+ String abs_path = get_fullpath_core(a, file_str);
+ if (gb_file_exists(cast(char *)abs_path.text)) {
+ import_file = abs_path;
+ }
+ }
+
+ import_file = string_trim_whitespace(import_file);
+
+ id->fullpath = import_file;
+ try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
} else if (node->kind == AstNode_GenDecl) {
ast_node(gd, GenDecl, node);
- if (gd->token.kind == Token_import ||
- gd->token.kind == Token_import_load) {
- for_array(spec_index, gd->specs) {
- AstNode *spec = gd->specs[spec_index];
- ast_node(id, ImportSpec, spec);
- String collection_name = {};
- String oirignal_string = id->relpath.string;
- String file_str = id->relpath.string;
- gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
- String import_file = {};
- String rel_path = {};
-
- if (!is_import_path_valid(file_str)) {
- if (id->is_import) {
- syntax_error(node, "Invalid import path: `%.*s`", LIT(file_str));
- } else {
- syntax_error(node, "Invalid include path: `%.*s`", LIT(file_str));
- }
- // NOTE(bill): It's a naughty name
- decls[i] = ast_bad_decl(f, id->relpath, id->relpath);
- continue;
- }
-
- gb_mutex_lock(&p->file_decl_mutex);
- defer (gb_mutex_unlock(&p->file_decl_mutex));
-
- rel_path = get_fullpath_relative(a, base_dir, file_str);
- import_file = rel_path;
- if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
- String abs_path = get_fullpath_core(a, file_str);
- if (gb_file_exists(cast(char *)abs_path.text)) {
- import_file = abs_path;
- }
- }
-
- import_file = string_trim_whitespace(import_file);
-
- id->fullpath = import_file;
- try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
- }
- } else if (gd->token.kind == Token_foreign_library ||
+ if (gd->token.kind == Token_foreign_library ||
gd->token.kind == Token_foreign_system_library) {
for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs[spec_index];
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index c4acc4c9a..cf3a09304 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -85,7 +85,6 @@ TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_import, "import"), \
- TOKEN_KIND(Token_import_load, "import_load"), \
TOKEN_KIND(Token_foreign, "foreign"), \
TOKEN_KIND(Token_foreign_library, "foreign_library"), \
TOKEN_KIND(Token_foreign_system_library, "foreign_system_library"), \