much refactoring; changed passing structs by value; stack frame management; added...
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 12 Aug 2020 16:03:29 +0000 (11:03 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 12 Aug 2020 16:03:29 +0000 (11:03 -0500)
15 files changed:
Makefile
docs/plan
include/bh.h
include/onyxastnodes.h
include/onyxwasm.h
onyx
progs/heap_resize_test.onyx
progs/stack_based.onyx
src/onyx.c
src/onyxbuiltins.c [new file with mode: 0644]
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxwasm.c

index 6a575b282e20f57fc1e2e7133d374497dbadb4ff..f88f1fecc91a608f684d4ad1d541b6deb226b89c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ OBJ_FILES=\
        build/onyxlex.o \
        build/onyxparser.o \
        build/onyxtypes.o \
+       build/onyxbuiltins.o \
        build/onyxsempass.o \
        build/onyxsymres.o \
        build/onyxchecker.o \
index d0424cfebf3a7783a7f8311685987b62ab7dfcd3..fe7948b1118e6d1d9c0c1783e525ccede32b7b43 100644 (file)
--- a/docs/plan
+++ b/docs/plan
@@ -95,9 +95,6 @@ HOW:
 
         [X] Output 'drop' instruction for functions whose return value isn't used
 
-        [ ] Devise and implement a simple set of implicit type casting rules.
-            - Numeric literals always type cast to whatever type is needed (very flexible).
-
         [X] Strings should work as pointers to data.
             - Literals should be placed in data section with pointers to the start.
             - Should strings be null-terminated or a length at the start of the string?
@@ -161,13 +158,43 @@ HOW:
 
         [X] Include other directories to search for files
 
+        [X] remove struct splatting at parameters
+            - structs can still be passed by value however
+            - removed the implicit splatting feature
+
+        [ ] package builtin
+            - Place to store builtin types and values
+                __heap_start
+                __stack_base
+                __stack_top
+                etc
+
+        [ ] multiple return values
+
+        [ ] multiple lvals and compound assignment
+            a := 2
+            b := 5
+            a, b = b, a;
+
+        [ ] 'use' enums and packages at an arbitrary scope
+
+        [ ] All code paths return correct value
+
+        [ ] Add slices
+            - Arrays without a size
+            - Converted to a struct that looks like:    
+                []T :: struct {
+                    count : u32;
+                    data  : ^T;
+                }
+
         [ ] Arrays need to be much better
             - Currently, they are basically just a pointer.
             - The length should be stored with the pointer
             - Dynamic resizing?
             - They are just very hard to use at the moment
 
-        [ ] 'use' enums and packages at an arbitrary scope
+        [ ] Type parameterized structs
 
         [ ] Array literals
 
@@ -176,17 +203,15 @@ HOW:
         [ ] Top level variable initialization
             - Works for numeric literals
 
-        [ ] Better checking for casts
-            - Checking which things are allowed to cast to/from should be checked in the checker,
-                not in the wasm generatation
-
         [X] Start work on evaluating compile time known values.
             - An expression marked COMPTIME will be reduced to its value in the parse tree.
 
-        [ ] All code paths return correct value
-
         [ ] #initialize structs
 
+        [ ] Better checking for casts
+            - Checking which things are allowed to cast to/from should be checked in the checker,
+                not in the wasm generatation
+
         [ ] Variadic arguments
 
         [ ] Switch statements
index 6dbf7d1b7d36fa12df0919eaf619aef260e41876..da64fb1e366b96e9afdfb2d6e4417c8052e8b5a4 100644 (file)
@@ -545,6 +545,7 @@ typedef struct bh__arr {
 #define bh_arr_pop(arr)              ((arr)[--bh__arrhead(arr)->length])
 #define bh_arr_last(arr)             ((arr)[bh__arrhead(arr)->length - 1])
 #define bh_arr_end(arr, i)           ((i) >= &(arr)[bh_arr_length(arr)])
+#define bh_arr_start(arr, i)         ((i) < (arr))
 
 #define bh_arr_new(allocator_, arr, cap)    (bh__arr_grow((allocator_), (void**) &(arr), sizeof(*(arr)), cap))
 #define bh_arr_free(arr)                    (bh__arr_free((void**) &(arr)))
@@ -573,6 +574,7 @@ typedef struct bh__arr {
 #define bh_arr_fastdelete(arr, i)     (arr[i] = arr[--bh__arrhead(arr)->length])
 
 #define bh_arr_each(T, var, arr)      for (T* var = (arr); !bh_arr_end((arr), var); var++)
+#define bh_arr_rev_each(T, var, arr)  for (T* var = &bh_arr_last((arr)); !bh_arr_start((arr), var); var--)
 
 b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap);
 b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap);
index 52032a45c0da95d025da82ab40788c41c5169d15..ebb99d5e05700a649333f155645f871b9fd115b5 100644 (file)
@@ -149,7 +149,6 @@ typedef enum AstFlags {
 
     // Expression flags
     Ast_Flag_Expr_Ignored      = BH_BIT(8),
-    Ast_Flag_Param_Splatted    = BH_BIT(9),
     Ast_Flag_Param_Use         = BH_BIT(10),
     Ast_Flag_Address_Taken     = BH_BIT(11),
 
@@ -485,7 +484,6 @@ extern AstBasicType basic_type_f64;
 extern AstBasicType basic_type_rawptr;
 
 extern AstNumLit builtin_heap_start;
-extern AstGlobal builtin_stack_base;
 extern AstGlobal builtin_stack_top;
 
 typedef struct BuiltinSymbol {
@@ -495,6 +493,8 @@ typedef struct BuiltinSymbol {
 
 extern const BuiltinSymbol builtin_symbols[];
 
+void initialize_builtins();
+
 
 // NOTE: Useful not inlined functions
 AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
index 911b63a7f0aea73bee186984b115ff9b729c82b0..b7998c8262f99d58f77e4bd99661656d6d0802da 100644 (file)
@@ -334,7 +334,8 @@ typedef struct OnyxWasmModule {
     u32 next_datum_offset;
     u32 next_elem_idx;
 
-    u32 *stack_top_ptr, *stack_base_ptr;
+    i32 *stack_top_ptr;
+    u32 stack_base_idx;
 
     b32 has_stack_locals : 1;
 } OnyxWasmModule;
diff --git a/onyx b/onyx
index bbd03345cb0c3d908e34606a373e3a9eb141acd4..efe6385a6d6f79bcef1cf9f49774e6ecc66e3de8 100755 (executable)
Binary files a/onyx and b/onyx differ
index 75e3783f2520a45f0482ceba5004bac9672b4cc0..a81de58068bbd7f05f98e2f84727fb50734f2421 100644 (file)
@@ -6,40 +6,63 @@
 use package memory
 use package printing
 
-proc #export "start" {
-    heap_init();
-
-    print("Creating initial memories");
-    arr1 := cast(^u32) malloc(sizeof [10] u32);
-    print_hex(cast(u64) arr1);
-
-    arr2 := cast(^u32) malloc(sizeof [40] u32);
-    print_hex(cast(u64) arr2);
+Vec2 :: struct {
+    x : i32;
+    y : i32; 
+}
 
-    print("Freeing arr1");
-    mfree(arr1);
+other :: proc (use v: ^Vec2) -> i32 {
+    o : Vec2;
+    o.x = -100;
+    o.y = -10;
 
-    print("Resizing arr2 (shouldn't change location)");
-    arr2 = cast(^u32) mresize(arr2, sizeof [60] u32);
-    print_hex(cast(u64) arr2);
+    return x * o.x + y * o.y;
+}
 
-    print("Allocating arr3 (should be bigger than arr2)");
-    arr3 := cast(^u32) malloc(sizeof [30] u32);
-    print_hex(cast(u64) arr3);
-
-    print("Allocating arr1 (should be in the same place as before)");
-    arr1 = cast(^u32) malloc(sizeof [5] u32);
-    print_hex(cast(u64) arr1);
-    for i: 0, 5 do arr1[i] = i;
+proc #export "start" {
+    heap_init();
 
-    print("Resizing arr1 (should be in the same place as before)");
-    arr1 = cast(^u32) mresize(arr1, sizeof[10] u32);
-    print_hex(cast(u64) arr1);
+    v : Vec2;
+    v.x = 10;
+    v.y = 100;
 
-    print("Resizing arr1 (should have moved to after arr3)");
-    arr1 = cast(^u32) mresize(arr1, sizeof[100] u32);
-    print_hex(cast(u64) arr1);
+    other(^v) |> print();
+}
 
-    print("Testing if the data was copied.");
-    for i: 0, 5 do print(arr1[i]);
-}
\ No newline at end of file
+// proc #export "start2" {
+//     heap_init();
+// 
+//     print("Creating initial memories");
+//     arr1 := cast(^u32) malloc(sizeof [10] u32);
+//     print_hex(cast(u64) arr1);
+// 
+//     arr2 := cast(^u32) malloc(sizeof [40] u32);
+//     print_hex(cast(u64) arr2);
+// 
+//     print("Freeing arr1");
+//     mfree(arr1);
+// 
+//     print("Resizing arr2 (shouldn't change location)");
+//     arr2 = cast(^u32) mresize(arr2, sizeof [60] u32);
+//     print_hex(cast(u64) arr2);
+// 
+//     print("Allocating arr3 (should be bigger than arr2)");
+//     arr3 := cast(^u32) malloc(sizeof [30] u32);
+//     print_hex(cast(u64) arr3);
+// 
+//     print("Allocating arr1 (should be in the same place as before)");
+//     arr1 = cast(^u32) malloc(sizeof [5] u32);
+//     print_hex(cast(u64) arr1);
+//     for i: 0, 5 do arr1[i] = i;
+// 
+//     print("Resizing arr1 (should be in the same place as before)");
+//     arr1 = cast(^u32) mresize(arr1, sizeof[10] u32);
+//     print_hex(cast(u64) arr1);
+// 
+//     print("Resizing arr1 (should have moved to after arr3)");
+//     arr1 = cast(^u32) mresize(arr1, sizeof[100] u32);
+//     print_hex(cast(u64) arr1);
+// 
+//     print("Testing if the data was copied.");
+//     for i: 0, 5 do print(arr1[i]);
+// }// 
\ No newline at end of file
index a0643841353ba93282b99820ae2e6a4ec156dd24..df4699c7a2e103b34f0e70cb9043dadc9fd31e2d 100644 (file)
@@ -8,7 +8,7 @@ package main
 use package printing
 use package memory
 
-sort :: proc (arr: [N]i32, cmp: proc (i32, i32) -> i32) -> [N]i32 {
+sort :: proc (arr: [N]i32, cmp: proc (i32, i32) -> i32) -> [N] i32 {
     for i: 0, N {
         smallest_idx := i;
 
@@ -66,6 +66,20 @@ clamp :: proc (v: i32, lo: i32, hi: i32) -> i32 {
     return v;
 }
 
+// NOTE: Anonymous functions do NOT have closure,
+// so in either of these function scopes, the
+// parameter 'n' is not accessible.
+//
+// This is intended behavior since creating new
+// procs at runtime is very difficult with WASM
+stupid_idea :: proc (n: i32) -> proc () -> i32 {
+    if n == 1234 {
+        return proc -> i32 { return 5678; };
+    }
+
+    return proc -> i32 { return -1; };
+}
+
 some_value := 20 + 30 * 4 + 15 / 5;
 
 start :: proc #export {
@@ -75,7 +89,6 @@ start :: proc #export {
     print_hex(cast(u64) some_value);
     print("Hello, World!");
     print_ptr(__heap_start);
-    print_ptr(__stack_base);
     print_ptr(__stack_top);
     print_bin(42l);
     print_hex(42l);
@@ -96,25 +109,8 @@ start :: proc #export {
     print(arr[1]|>sumN());
     print(summing(cast(^i32) arr[1]));
 
-    v1: Vec3;
-    v1.x = 2;
-    v1.y = 4;
-    v1.z = 10;
-
-    v2: Vec3;
-    v2.x = 4;
-    v2.y = 2;
-    v2.z = 1;
-
-    v3: Vec3;
-    vec_add(v1, v2, ^v3);
-    print(v3.x);
-    print(v3.y);
-    print(v3.z);
-
-    print(v3|>mag_squared());
-
     print(10 |> ret_val(4));
+    print(11 |> ret_val(5));
     
     for i: 0, N do print(arr[1][i]);
 
@@ -141,5 +137,10 @@ start :: proc #export {
             |> clamp(30, 100);
     print(val);
 
-    for i: 0, N do print(something[i] |> clamp(3, 6));
+    for i: 0, N do
+        something[i]
+            |> clamp(3, 6)
+            |> print();
+
+    stupid_idea(1234)() |> print();
 }
\ No newline at end of file
index 9c969e114d596caf6756be1f99170308c8de70e5..51c9a03c979d9846c0ca376f1931702aff511b2c 100644 (file)
@@ -350,19 +350,13 @@ static i32 onyx_compile(CompilerState* compiler_state) {
         bh_arr_fastdelete(compiler_state->queued_files, 0);
     }
 
+    initialize_builtins();
+
     // Add builtin one-time entities
-    bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
-        .type = Entity_Type_Global_Header,
-        .global = &builtin_stack_base
-    }));
     bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
         .type = Entity_Type_Global_Header,
         .global = &builtin_stack_top
     }));
-    bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
-        .type = Entity_Type_Global,
-        .global = &builtin_stack_base
-    }));
     bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
         .type = Entity_Type_Global,
         .global = &builtin_stack_top
diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c
new file mode 100644 (file)
index 0000000..1a8c7bc
--- /dev/null
@@ -0,0 +1,45 @@
+#include "onyxastnodes.h"
+#include "onyxtypes.h"
+
+AstBasicType basic_type_void   = { { Ast_Kind_Basic_Type, 0, NULL, "void"   }, &basic_types[Basic_Kind_Void]  };
+AstBasicType basic_type_bool   = { { Ast_Kind_Basic_Type, 0, NULL, "bool"   }, &basic_types[Basic_Kind_Bool]  };
+AstBasicType basic_type_i8     = { { Ast_Kind_Basic_Type, 0, NULL, "i8"     }, &basic_types[Basic_Kind_I8]    };
+AstBasicType basic_type_u8     = { { Ast_Kind_Basic_Type, 0, NULL, "u8"     }, &basic_types[Basic_Kind_U8]    };
+AstBasicType basic_type_i16    = { { Ast_Kind_Basic_Type, 0, NULL, "i16"    }, &basic_types[Basic_Kind_I16]   };
+AstBasicType basic_type_u16    = { { Ast_Kind_Basic_Type, 0, NULL, "u16"    }, &basic_types[Basic_Kind_U16]   };
+AstBasicType basic_type_i32    = { { Ast_Kind_Basic_Type, 0, NULL, "i32"    }, &basic_types[Basic_Kind_I32]   };
+AstBasicType basic_type_u32    = { { Ast_Kind_Basic_Type, 0, NULL, "u32"    }, &basic_types[Basic_Kind_U32]   };
+AstBasicType basic_type_i64    = { { Ast_Kind_Basic_Type, 0, NULL, "i64"    }, &basic_types[Basic_Kind_I64]   };
+AstBasicType basic_type_u64    = { { Ast_Kind_Basic_Type, 0, NULL, "u64"    }, &basic_types[Basic_Kind_U64]   };
+AstBasicType basic_type_f32    = { { Ast_Kind_Basic_Type, 0, NULL, "f32"    }, &basic_types[Basic_Kind_F32]   };
+AstBasicType basic_type_f64    = { { Ast_Kind_Basic_Type, 0, NULL, "f64"    }, &basic_types[Basic_Kind_F64]   };
+AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
+
+static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } };
+static OnyxToken builtin_stack_top_token  = { Token_Type_Symbol, 11, "__stack_top ",  { 0 } };
+AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
+AstGlobal builtin_stack_top  = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top,  &builtin_stack_top_token,  NULL, (AstType *) &basic_type_rawptr, NULL };
+
+const BuiltinSymbol builtin_symbols[] = {
+    { "void",       (AstNode *) &basic_type_void },
+    { "bool",       (AstNode *) &basic_type_bool },
+    { "i8",         (AstNode *) &basic_type_i8 },
+    { "u8",         (AstNode *) &basic_type_u8 },
+    { "i16",        (AstNode *) &basic_type_i16 },
+    { "u16",        (AstNode *) &basic_type_u16 },
+    { "i32",        (AstNode *) &basic_type_i32 },
+    { "u32",        (AstNode *) &basic_type_u32 },
+    { "i64",        (AstNode *) &basic_type_i64 },
+    { "u64",        (AstNode *) &basic_type_u64 },
+    { "f32",        (AstNode *) &basic_type_f32 },
+    { "f64",        (AstNode *) &basic_type_f64 },
+    { "rawptr",     (AstNode *) &basic_type_rawptr },
+
+    { "__heap_start", (AstNode *) &builtin_heap_start },
+    { "__stack_top",  (AstNode *) &builtin_stack_top },
+
+    { NULL, NULL },
+};
+
+void initialize_builtins() {
+}
\ No newline at end of file
index 881b0cfae971256676f042d0458cfe5ed74b6409..99292d964b3a6958022a35f427dbc7d52edec394 100644 (file)
@@ -192,7 +192,7 @@ CHECK(call, AstCall* call) {
 
     if (check_expression(&call->callee)) return 1;
 
-    // NOTE: Check arguments and splat structs
+    // NOTE: Check arguments
     AstNode** prev_param = (AstNode **) &call->arguments;
     AstArgument* actual_param = call->arguments;
     while (actual_param != NULL) {
@@ -205,43 +205,7 @@ CHECK(call, AstCall* call) {
             return 1;
         }
 
-        // NOTE: Splat structures into multiple arguments
-        if (actual_param->type->kind == Type_Kind_Struct) {
-            if (!type_struct_is_simple(actual_param->type)) {
-                onyx_message_add(Msg_Type_Literal,
-                    actual_param->token->pos,
-                    "can only splat simple structure. nested structures or struct of arrays is not allowed.");
-                return 1;
-            }
-
-            bh_arr_each(StructMember *, smem, actual_param->type->Struct.memarr) {
-                AstFieldAccess* field = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access);
-                field->expr = actual_param->value;
-
-                // HACK: Since dereferences are not used for struct types, we need a
-                // special case here.
-                if (field->expr->kind == Ast_Kind_Dereference) {
-                    field->expr = ((AstDereference *) field->expr)->expr;
-                }
-
-                field->offset = (*smem)->offset;
-                field->type = (*smem)->type;
-
-                AstArgument* arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument);
-                arg->value = (AstTyped *) field;
-                arg->type = field->type;
-                arg->token = actual_param->token;
-                arg->next = actual_param->next;
-
-                call->arg_count++;
-
-                *prev_param = (AstNode *) arg;
-                prev_param = (AstNode **) &arg->next;
-            }
-        } else {
-            prev_param = (AstNode **) &actual_param->next;
-        }
-
+        prev_param = (AstNode **) &actual_param->next;
         actual_param = (AstArgument *) actual_param->next;
     }
 
@@ -752,18 +716,6 @@ CHECK(field_access, AstFieldAccess** pfield) {
         return 1;
     }
 
-    if (field->expr->flags & Ast_Flag_Param_Splatted) {
-        AstLocal* param = (AstLocal *) field->expr;
-
-        u32 steps = smem.idx + 1;
-        while (steps--) param = (AstLocal *) param->next;
-
-        // NOTE: Not actually a field access
-        *pfield = (AstFieldAccess *) param;
-        token_toggle_end(field->token);
-        return 0;
-    }
-
     field->offset = smem.offset;
     field->type = smem.type;
 
@@ -1008,9 +960,6 @@ CHECK(struct, AstStructType* s_node) {
 }
 
 CHECK(function_header, AstFunction* func) {
-    i32 changed_params = 0;
-
-    AstLocal **prev_param = &func->params;
     AstLocal *param = func->params;
     while (param != NULL) {
         fill_in_type((AstTyped *) param);
@@ -1030,55 +979,10 @@ CHECK(function_header, AstFunction* func) {
             return 1;
         }
 
-        if (param->type->kind == Type_Kind_Struct) {
-            param->flags |= Ast_Flag_Param_Splatted;
-
-            if (!type_struct_is_simple(param->type)) {
-                onyx_message_add(Msg_Type_Literal,
-                    param->token->pos,
-                    "only simple structures can be passed by value");
-                return 1;
-            }
-
-            changed_params = 1;
-
-            AstLocal *first_new_param = NULL, *last_new_param = NULL;
-            AstLocal** insertion = prev_param;
-            bh_arr_each(StructMember *, smem, param->type->Struct.memarr) {
-                AstLocal* new_param = onyx_ast_node_new(semstate.node_allocator, sizeof(AstLocal), Ast_Kind_Param);
-                new_param->token = param->token;
-                new_param->type = (*smem)->type;
-                new_param->flags |= Ast_Flag_Const;
-
-                if (first_new_param == NULL) first_new_param = new_param;
-                last_new_param = new_param;
-
-                *insertion = new_param;
-                insertion = (AstLocal **) &new_param->next;
-            }
-
-            *prev_param = first_new_param;
-            last_new_param->next = param->next;
-            param->next = (AstNode *) first_new_param;
-
-            prev_param = (AstLocal **) &last_new_param->next;
-        } else {
-            prev_param = (AstLocal **) &param->next;
-        }
-
         param = (AstLocal *) param->next;
     }
 
-    if (changed_params) {
-        // NOTE: Need to rebuild the function parameters in a special way once the are modified.
-        // This may/will get cleaned up at a later point.
-
-        func->type = type_build_function_type(
-            semstate.node_allocator, func,
-            ((AstFunctionType *) func->type_node)->return_type);
-    } else {
-        fill_in_type((AstTyped *) func);
-    }
+    fill_in_type((AstTyped *) func);
 
     if ((func->flags & Ast_Flag_Exported) != 0) {
         if ((func->flags & Ast_Flag_Foreign) != 0) {
index cbafcff73680ac94fe966217d6795691759b3b47..f0d0279b5b558552e2dfb3754af4d1b29b5bf399 100644 (file)
@@ -939,6 +939,7 @@ static AstType* parse_type(OnyxParser* parser) {
 
             bh_arr(AstType *) params = NULL;
             bh_arr_new(global_scratch_allocator, params, 4);
+            bh_arr_set_length(params, 0);
 
             expect_token(parser, '(');
             while (parser->curr->type != ')') {
@@ -966,7 +967,8 @@ static AstType* parse_type(OnyxParser* parser) {
             new->param_count = param_count;
             new->return_type = return_type;
 
-            fori (i, 0, param_count - 1) new->params[i] = params[i];
+            if (param_count > 0)
+                fori (i, 0, param_count - 1) new->params[i] = params[i];
 
             *next_insertion = (AstType *) new;
             next_insertion = NULL;
index 32821b07f50ea9348908d6196fb059e3dc2b74ad..a4a855aecb321b9e0aaf694582fd009923e2cfea 100644 (file)
@@ -4,48 +4,6 @@
 #include "onyxutils.h"
 
 
-AstBasicType basic_type_void   = { { Ast_Kind_Basic_Type, 0, NULL, "void"   }, &basic_types[Basic_Kind_Void]  };
-AstBasicType basic_type_bool   = { { Ast_Kind_Basic_Type, 0, NULL, "bool"   }, &basic_types[Basic_Kind_Bool]  };
-AstBasicType basic_type_i8     = { { Ast_Kind_Basic_Type, 0, NULL, "i8"     }, &basic_types[Basic_Kind_I8]    };
-AstBasicType basic_type_u8     = { { Ast_Kind_Basic_Type, 0, NULL, "u8"     }, &basic_types[Basic_Kind_U8]    };
-AstBasicType basic_type_i16    = { { Ast_Kind_Basic_Type, 0, NULL, "i16"    }, &basic_types[Basic_Kind_I16]   };
-AstBasicType basic_type_u16    = { { Ast_Kind_Basic_Type, 0, NULL, "u16"    }, &basic_types[Basic_Kind_U16]   };
-AstBasicType basic_type_i32    = { { Ast_Kind_Basic_Type, 0, NULL, "i32"    }, &basic_types[Basic_Kind_I32]   };
-AstBasicType basic_type_u32    = { { Ast_Kind_Basic_Type, 0, NULL, "u32"    }, &basic_types[Basic_Kind_U32]   };
-AstBasicType basic_type_i64    = { { Ast_Kind_Basic_Type, 0, NULL, "i64"    }, &basic_types[Basic_Kind_I64]   };
-AstBasicType basic_type_u64    = { { Ast_Kind_Basic_Type, 0, NULL, "u64"    }, &basic_types[Basic_Kind_U64]   };
-AstBasicType basic_type_f32    = { { Ast_Kind_Basic_Type, 0, NULL, "f32"    }, &basic_types[Basic_Kind_F32]   };
-AstBasicType basic_type_f64    = { { Ast_Kind_Basic_Type, 0, NULL, "f64"    }, &basic_types[Basic_Kind_F64]   };
-AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
-
-static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } };
-static OnyxToken builtin_stack_base_token = { Token_Type_Symbol, 12, "__stack_base ", { 0 } };
-static OnyxToken builtin_stack_top_token  = { Token_Type_Symbol, 11, "__stack_top ",  { 0 } };
-AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
-AstGlobal builtin_stack_base = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Base, &builtin_stack_base_token, NULL, (AstType *) &basic_type_rawptr, NULL };
-AstGlobal builtin_stack_top  = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top,  &builtin_stack_top_token,  NULL, (AstType *) &basic_type_rawptr, NULL };
-
-const BuiltinSymbol builtin_symbols[] = {
-    { "void",       (AstNode *) &basic_type_void },
-    { "bool",       (AstNode *) &basic_type_bool },
-    { "i8",         (AstNode *) &basic_type_i8 },
-    { "u8",         (AstNode *) &basic_type_u8 },
-    { "i16",        (AstNode *) &basic_type_i16 },
-    { "u16",        (AstNode *) &basic_type_u16 },
-    { "i32",        (AstNode *) &basic_type_i32 },
-    { "u32",        (AstNode *) &basic_type_u32 },
-    { "i64",        (AstNode *) &basic_type_i64 },
-    { "u64",        (AstNode *) &basic_type_u64 },
-    { "f32",        (AstNode *) &basic_type_f32 },
-    { "f64",        (AstNode *) &basic_type_f64 },
-    { "rawptr",     (AstNode *) &basic_type_rawptr },
-
-    { "__heap_start", (AstNode *) &builtin_heap_start },
-    { "__stack_base", (AstNode *) &builtin_stack_base },
-    { "__stack_top",  (AstNode *) &builtin_stack_top },
-
-    { NULL, NULL },
-};
 
 static void scope_enter(Scope* new_scope);
 static void scope_leave();
@@ -239,6 +197,7 @@ static void symres_ufc(AstBinaryOp** ufc) {
     AstArgument* implicit_arg = onyx_ast_node_new(semstate.node_allocator,
             sizeof(AstArgument),
             Ast_Kind_Argument);
+    implicit_arg->token = (*ufc)->left->token;
     implicit_arg->value = (*ufc)->left;
     implicit_arg->next = (AstNode *) call_node->arguments;
 
index bf8d2ce18f645745d517594102d3df19b1df2938..a70fc5f48c3f089a72fcca6ed87dd4c4315c18f4 100644 (file)
@@ -168,8 +168,10 @@ b32 types_are_compatible(Type* t1, Type* t2) {
 
             if (!types_are_compatible(t1->Function.return_type, t2->Function.return_type)) return 0;
 
-            fori (i, 0, t1->Function.param_count - 1) {
-                if (!types_are_compatible(t1->Function.params[i], t2->Function.params[i])) return 0;
+            if (t1->Function.param_count > 0) {
+                fori (i, 0, t1->Function.param_count - 1) {
+                    if (!types_are_compatible(t1->Function.params[i], t2->Function.params[i])) return 0;
+                }
             }
 
             return 1;
index f335573436f4cb425eb86e8cc043e8890f1d0651..452119a62b9b5306f66a57f30a8485a74a82b701 100644 (file)
@@ -250,7 +250,7 @@ COMPILE_FUNC(function_body,         AstFunction* fd);
 COMPILE_FUNC(block,                 AstBlock* block);
 COMPILE_FUNC(statement,             AstNode* stmt);
 COMPILE_FUNC(assignment,            AstBinaryOp* assign);
-COMPILE_FUNC(store_instruction,     Type* type, u32 alignment, u32 offset);
+COMPILE_FUNC(store_instruction,     Type* type, u32 offset);
 COMPILE_FUNC(load_instruction,      Type* type, u32 offset);
 COMPILE_FUNC(if,                    AstIf* if_node);
 COMPILE_FUNC(while,                 AstWhile* while_node);
@@ -364,7 +364,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
             u64 offset = 0;
             compile_local_location(mod, &code, (AstLocal *) lval, &offset);
             compile_expression(mod, &code, assign->right);
-            compile_store_instruction(mod, &code, lval->type, type_get_alignment_log2(lval->type), offset);
+            compile_store_instruction(mod, &code, lval->type, offset);
         }
 
     } else if (lval->kind == Ast_Kind_Global) {
@@ -378,10 +378,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
         compile_expression(mod, &code, deref->expr);
         compile_expression(mod, &code, assign->right);
 
-        compile_store_instruction(mod, &code,
-                deref->type,
-                type_get_alignment_log2(deref->type),
-                0);
+        compile_store_instruction(mod, &code, deref->type, 0);
 
     } else if (lval->kind == Ast_Kind_Array_Access) {
         AstArrayAccess* aa = (AstArrayAccess *) lval;
@@ -390,10 +387,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
         compile_array_access_location(mod, &code, aa, &offset);
         compile_expression(mod, &code, assign->right);
 
-        compile_store_instruction(mod, &code,
-                aa->type,
-                type_get_alignment_log2(aa->type),
-                offset);
+        compile_store_instruction(mod, &code, aa->type, offset);
 
     } else if (lval->kind == Ast_Kind_Field_Access) {
         AstFieldAccess* field = (AstFieldAccess *) lval;
@@ -402,10 +396,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
         compile_field_access_location(mod, &code, field, &offset);
         compile_expression(mod, &code, assign->right);
 
-        compile_store_instruction(mod, &code,
-                field->type,
-                type_get_alignment_log2(field->type),
-                offset);
+        compile_store_instruction(mod, &code, field->type, offset);
     } else {
         assert(("Invalid lval", 0));
     }
@@ -413,9 +404,11 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
     *pcode = code;
 }
 
-COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
+COMPILE_FUNC(store_instruction, Type* type, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
 
+    u32 alignment = type_get_alignment_log2(type);
+
     if (type->kind == Type_Kind_Enum) {
         type = type->Enum.backing;
     }
@@ -452,6 +445,8 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
 COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
 
+    assert(("Should use compile_struct_load instead", type->kind != Type_Kind_Struct));
+
     if (type->kind == Type_Kind_Array) {
         if (offset != 0) {
             WID(WI_I32_CONST, offset);
@@ -591,7 +586,7 @@ COMPILE_FUNC(for, AstFor* for_node) {
     } else {
         compile_local_location(mod, &code, var, &offset);
         compile_expression(mod, &code, for_node->start);
-        compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
+        compile_store_instruction(mod, &code, var->type, offset);
     }
 
     WID(WI_BLOCK_START, 0x40);
@@ -628,7 +623,7 @@ COMPILE_FUNC(for, AstFor* for_node) {
         compile_load_instruction(mod, &code, var->type, offset);
         compile_expression(mod, &code, for_node->step);
         WI(add_instr);
-        compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
+        compile_store_instruction(mod, &code, var->type, offset);
     }
 
     compile_deferred_stmts(mod, &code, (AstNode *) for_node);
@@ -948,16 +943,40 @@ COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) {
 COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return) {
     bh_arr(WasmInstruction) code = *pcode;
 
-    i32 stack_base_idx = (i32) bh_imap_get(&mod->index_map, (u64) &builtin_stack_base);
     i32 local_offset = (i32) bh_imap_get(&mod->local_map, (u64) local);
 
-    WID(WI_GLOBAL_GET, stack_base_idx);
+    WID(WI_LOCAL_GET, mod->stack_base_idx);
 
     *offset_return += local_offset;
 
     *pcode = code;
 }
 
+COMPILE_FUNC(struct_load, AstTyped* expr) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    assert(expr->type->kind == Type_Kind_Struct);
+
+    u64 offset = 0;
+
+    bh_arr_each(StructMember *, smem, expr->type->Struct.memarr) {
+        offset = 0;
+
+        switch (expr->kind) {
+            case Ast_Kind_Local: compile_local_location(mod, &code, (AstLocal *) expr, &offset); break;
+            case Ast_Kind_Dereference: compile_expression(mod, &code, ((AstDereference *) expr)->expr); break;
+            case Ast_Kind_Array_Access: compile_array_access_location(mod, &code, (AstArrayAccess *) expr, &offset); break;
+            case Ast_Kind_Field_Access: compile_field_access_location(mod, &code, (AstFieldAccess *) expr, &offset); break;
+
+            default: assert(0);
+        }
+
+        compile_load_instruction(mod, &code, (*smem)->type, offset + (*smem)->offset);
+    }
+
+    *pcode = code;
+}
+
 COMPILE_FUNC(expression, AstTyped* expr) {
     bh_arr(WasmInstruction) code = *pcode;
 
@@ -974,6 +993,11 @@ COMPILE_FUNC(expression, AstTyped* expr) {
             if (tmp & LOCAL_IS_WASM) {
                 WID(WI_LOCAL_GET, (u32) (tmp & ~LOCAL_IS_WASM));
             } else {
+                if (expr->type->kind == Type_Kind_Struct) {
+                    compile_struct_load(mod, &code, expr);
+                    break;
+                }
+
                 u64 offset = 0;
                 compile_local_location(mod, &code, (AstLocal *) expr, &offset);
 
@@ -1092,6 +1116,11 @@ COMPILE_FUNC(expression, AstTyped* expr) {
         }
 
         case Ast_Kind_Dereference: {
+            if (expr->type->kind == Type_Kind_Struct) {
+                compile_struct_load(mod, &code, expr);
+                break;
+            }
+
             AstDereference* deref = (AstDereference *) expr;
             compile_expression(mod, &code, deref->expr);
             compile_load_instruction(mod, &code, deref->type, 0);
@@ -1099,6 +1128,11 @@ COMPILE_FUNC(expression, AstTyped* expr) {
         }
 
         case Ast_Kind_Array_Access: {
+            if (expr->type->kind == Type_Kind_Struct) {
+                compile_struct_load(mod, &code, expr);
+                break;
+            }
+
             AstArrayAccess* aa = (AstArrayAccess *) expr;
             u64 offset = 0;
             compile_array_access_location(mod, &code, aa, &offset);
@@ -1107,8 +1141,26 @@ COMPILE_FUNC(expression, AstTyped* expr) {
         }
 
         case Ast_Kind_Field_Access: {
+            if (expr->type->kind == Type_Kind_Struct) {
+                compile_struct_load(mod, &code, expr);
+                break;
+            }
+
             AstFieldAccess* field = (AstFieldAccess* ) expr;
 
+            if (field->expr->kind == Ast_Kind_Param && field->expr->type->kind == Type_Kind_Struct) {
+                StructMember smem;
+
+                token_toggle_end(field->token);
+                type_struct_lookup_member(field->expr->type, field->token->text, &smem);
+                token_toggle_end(field->token);
+
+                i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) field->expr) + smem.idx;
+
+                WID(WI_LOCAL_GET, localidx);
+                break;
+            }
+
             u64 offset = 0;
             compile_field_access_location(mod, &code, field, &offset);
             compile_load_instruction(mod, &code, field->type, offset);
@@ -1302,21 +1354,12 @@ COMPILE_FUNC(stack_enter, u64 stacksize) {
     bh_arr(WasmInstruction) code = *pcode;
 
     u32 stack_top_idx  = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top);
-    u32 stack_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_base);
 
     WID(WI_GLOBAL_GET, stack_top_idx);
-    WID(WI_GLOBAL_GET, stack_base_idx);
-    WID(WI_I32_STORE, ((WasmInstructionData) { 2, 0 }));
-    WID(WI_GLOBAL_GET, stack_top_idx);
-    WID(WI_I32_CONST, 4);
-    WI(WI_I32_ADD);
-    WID(WI_GLOBAL_SET, stack_top_idx);
-    WID(WI_GLOBAL_GET, stack_top_idx);
-    WID(WI_GLOBAL_SET, stack_base_idx);
-    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_LOCAL_TEE, mod->stack_base_idx);
     WID(WI_I32_CONST, stacksize);
     WI(WI_I32_ADD);
-    WID(WI_GLOBAL_SET, stack_top_idx);
+    WID(WI_GLOBAL_SET, stack_top_idx); 
 
     *pcode = code;
 }
@@ -1325,20 +1368,10 @@ COMPILE_FUNC(stack_leave, u32 unused) {
     bh_arr(WasmInstruction) code = *pcode;
 
     u32 stack_top_idx  = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top);
-    u32 stack_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_base);
-
-    WID(WI_GLOBAL_GET, stack_base_idx);
-    WID(WI_GLOBAL_SET, stack_top_idx);
 
-    WID(WI_GLOBAL_GET, stack_top_idx);
-    WID(WI_I32_CONST, 4);
-    WI(WI_I32_SUB);
+    WID(WI_LOCAL_GET, mod->stack_base_idx);
     WID(WI_GLOBAL_SET, stack_top_idx);
 
-    WID(WI_GLOBAL_GET, stack_top_idx);
-    WID(WI_I32_LOAD, ((WasmInstructionData) { 2, 0 }));
-    WID(WI_GLOBAL_SET, stack_base_idx);
-
     *pcode = code;
 }
 
@@ -1352,9 +1385,17 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) {
     i32 param_count = ft->Function.param_count;
     i32 params_left = param_count;
     while (params_left-- > 0) {
-        // HACK: Using these directly as part of a string feels weird but they are
-        // valid characters so I don't think it is going to be much of an issue
-        *(t++) = (char) onyx_type_to_wasm_type(*param_type);
+        if ((*param_type)->kind == Type_Kind_Struct) {
+            bh_arr_each(StructMember *, smem, (*param_type)->Struct.memarr) {
+                *(t++) = (char) onyx_type_to_wasm_type((*smem)->type);
+            }
+
+            param_count += (*param_type)->Struct.mem_count - 1;
+
+        } else {
+            *(t++) = (char) onyx_type_to_wasm_type(*param_type);
+        }
+
         param_type++;
     }
     *(t++) = ':';
@@ -1448,7 +1489,7 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
     WasmFunc wasm_func = {
         .type_idx = type_idx,
         .locals = {
-            .i32_count = 0,
+            .i32_count = 1, // NOTE: for the old stack base
             .i64_count = 0,
             .f32_count = 0,
             .f64_count = 0,
@@ -1478,11 +1519,19 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
         // NOTE: Generate the local map
         u64 localidx = 0;
         for (AstLocal *param = fd->params; param != NULL; param = (AstLocal *) param->next) {
-            bh_imap_put(&mod->local_map, (u64) param, localidx++ | LOCAL_IS_WASM);
+            if (param->type->kind == Type_Kind_Struct) {
+                bh_imap_put(&mod->local_map, (u64) param, localidx);
+                localidx += param->type->Struct.mem_count;
+
+            } else {
+                bh_imap_put(&mod->local_map, (u64) param, localidx++ | LOCAL_IS_WASM);
+            }
         }
 
         static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
 
+        mod->stack_base_idx = localidx++;
+
         // HACK: This assumes that the order of the count members
         // is the same as the order of the local_types above
         u8* count = &wasm_func.locals.i32_count;
@@ -1588,8 +1637,6 @@ static void compile_global(OnyxWasmModule* module, AstGlobal* global) {
 
     if (global->flags & Ast_Flag_Global_Stack_Top)
         module->stack_top_ptr = &bh_arr_last(module->globals).initial_value[0].data.i1;
-    if (global->flags & Ast_Flag_Global_Stack_Base)
-        module->stack_base_ptr = &bh_arr_last(module->globals).initial_value[0].data.i1;
 
 }
 
@@ -1785,7 +1832,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
         .structured_jump_target = NULL,
 
         .stack_top_ptr = NULL,
-        .stack_base_ptr = NULL,
+        .stack_base_idx = 0,
     };
 
     bh_arr_new(alloc, module.types, 4);
@@ -1826,17 +1873,14 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ProgramInfo* program) {
 
     bh_arr_each(Entity, entity, program->entities) {
 
-        if (module->stack_base_ptr) {
-            *module->stack_base_ptr = module->next_datum_offset;
+        if (module->stack_top_ptr) {
+            *module->stack_top_ptr = module->next_datum_offset;
 
-            if (*module->stack_base_ptr % 16 != 0) {
-                *module->stack_base_ptr += 16 - (*module->stack_base_ptr % 16);
+            if (*module->stack_top_ptr % 16 != 0) {
+                *module->stack_top_ptr += 16 - (*module->stack_top_ptr % 16);
             }
 
-            if (module->stack_top_ptr)
-                *module->stack_top_ptr = *module->stack_base_ptr;
-
-            builtin_heap_start.value.i = *module->stack_base_ptr + (1 << 16);
+            builtin_heap_start.value.i = *module->stack_top_ptr + (1 << 16);
             if (builtin_heap_start.value.i % 16 != 0) {
                 builtin_heap_start.value.i += 16 - (builtin_heap_start.value.i % 16);
             }