From b9e347ef5072ac3d1f8dcc1ba2d678109f9ff016 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 27 Aug 2017 17:03:27 +0100 Subject: [PATCH] Replace `import_load` with `using import .` --- build.bat | 4 +- code/demo.odin | 601 --------------------- code/demo_backup.odin | 430 --------------- code/game.odin | 222 -------- code/http_test.odin | 184 ------- code/old_demos/demo001.odin | 337 ------------ code/old_demos/demo002.odin | 892 -------------------------------- code/old_demos/demo004.odin | 66 --- code/old_demos/demo005.odin | 284 ---------- code/old_demos/old_runtime.odin | 412 --------------- code/punity.odin | 498 ------------------ core/_preload.odin | 11 +- core/fmt.odin | 14 +- core/mem.odin | 9 +- core/opengl.odin | 8 +- core/os.odin | 8 +- core/strconv.odin | 2 +- core/sync.odin | 6 +- core/sync_linux.odin | 6 +- core/sync_windows.odin | 6 +- core/sys/wgl.odin | 2 +- core/sys/windows.odin | 4 +- src/checker.cpp | 75 ++- src/docs.cpp | 1 - src/parser.cpp | 260 ++++++---- src/tokenizer.cpp | 1 - 26 files changed, 211 insertions(+), 4132 deletions(-) delete mode 100644 code/demo.odin delete mode 100644 code/demo_backup.odin delete mode 100644 code/game.odin delete mode 100644 code/http_test.odin delete mode 100644 code/old_demos/demo001.odin delete mode 100644 code/old_demos/demo002.odin delete mode 100644 code/old_demos/demo004.odin delete mode 100644 code/old_demos/demo005.odin delete mode 100644 code/old_demos/old_runtime.odin delete mode 100644 code/punity.odin 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"), \