added ability to pass complicated structs by value
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 18 Sep 2020 16:43:28 +0000 (11:43 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 18 Sep 2020 16:43:28 +0000 (11:43 -0500)
CHANGELOG
include/onyxastnodes.h
onyx
progs/poly_struct.onyx
src/onyxchecker.c
src/onyxwasm.c
tests/i32map.onyx

index 8567f3d07c1c90c70658a61c8d4b2c5623d48de4..1b18ec8ee61fd5bda1b0c538e2f292e245f040af 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,16 @@
+Release v0.0.4
+--------------
+Additions:
+* Ability to pass complicated structs by value. Very useful in polymorphic data types.
+
+Removals:
+
+Changes:
+
+Bug fixes:
+
+
+
 Release v0.0.3
 --------------
 Additions:
index b5307cea7f20db36a83a790a1826cfc3f0f93540..02646b6b5d09c6e4870dc7b38830327d1b227406 100644 (file)
@@ -392,6 +392,13 @@ typedef enum ForLoopType {
     For_Loop_DynArr,
 } ForLoopType;
 
+typedef enum ParamPassType {
+    Param_Pass_Invalid,
+    Param_Pass_By_Value,
+    Param_Pass_By_VarArg,
+    Param_Pass_By_Implicit_Pointer,
+} ParamPassType;
+
 // Base Nodes
 #define AstNode_base \
     AstKind kind;             \
@@ -422,7 +429,7 @@ struct AstBinOp         { AstTyped_base; BinaryOp operation; AstTyped *left, *ri
 struct AstUnaryOp       { AstTyped_base; UnaryOp operation; AstTyped *expr; };
 struct AstNumLit        { AstTyped_base; union { i32 i; i64 l; f32 f; f64 d; } value; };
 struct AstStrLit        { AstTyped_base; u64 addr; u64 length; };
-struct AstLocal         { AstTyped_base; AstLocal *prev_local; };
+struct AstLocal         { AstTyped_base; ParamPassType ppt; };
 struct AstCall          { AstTyped_base; AstArgument *arguments; u64 arg_count; AstTyped *callee; };
 struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; u64 arg_count; OnyxIntrinsic intrinsic; };
 struct AstArgument      { AstTyped_base; AstTyped *value; };
@@ -597,6 +604,9 @@ struct AstGlobal        {
     };
 };
 struct AstParam {
+    // HACK CLEANUP: This does not need to have a local buried inside of it.
+    // Convert this to be AstTyped_base and pull the ParamPassType from AstLocal
+    // to here.                                        - brendanfh 2020/09/18
     AstLocal *local;
     AstTyped *default_value;
 
diff --git a/onyx b/onyx
index f722c77d53b61302b198b899800ee610197177dd..f93ebfa0ee1d072eff795630ebba246a78d2290b 100755 (executable)
Binary files a/onyx and b/onyx differ
index a64d6a2c4c2b6e4a59eeb3ef6dc66217a13cb312..138b1a48061549d8667bdf9b280666376f4eac38 100644 (file)
@@ -5,21 +5,18 @@ package main
 use package core
 
 main :: proc (args: [] cstring) {
-    imap : I32Map(^string);
+    imap : I32Map(string);
     i32map_init(^imap);
     defer i32map_free(^imap);
 
-    hello := "Hello ";
-    world := "World!";
-
-    i32map_put(^imap, 50, ^hello);
-    i32map_put(^imap, 1234, ^world);
+    i32map_put(^imap, 50,   "Hello ");
+    i32map_put(^imap, 1234, "World!");
 
     println(i32map_has(^imap, 50));
     println(i32map_has(^imap, 51));
 
     // i32map_delete(^imap, 50);
 
-    print(  *i32map_get(^imap, 50));
-    println(*i32map_get(^imap, 1234));
+    print(  i32map_get(^imap, 50, ""));
+    println(i32map_get(^imap, 1234, ""));
 }
index 0b3991b8f7afcb2f3e4419023e4a55ae547c999f..6e4510d6bef775f1ac7b83101d3faea2c71eb201 100644 (file)
@@ -303,13 +303,15 @@ b32 check_call(AstCall* call) {
             return 1;
         }
 
-        if (type_is_structlike_strict(actual->value->type)) {
-            if (!type_structlike_is_simple(actual->value->type)) {
-                onyx_report_error(actual->token->pos,
-                    "Can only pass simple structs as parameters (no nested structures). passing by pointer is the only way for now.");
-                return 1;
-            }
-        }
+        // NOTE: This restricts you to only passing simple structures as parameters.
+        // At one point in time it was okay, but there are some necessary complexities.
+        // if (type_is_structlike_strict(actual->value->type)) {
+        //     if (!type_structlike_is_simple(actual->value->type)) {
+        //         onyx_report_error(actual->token->pos,
+        //             "Can only pass simple structs as parameters (no nested structures). passing by pointer is the only way for now.");
+        //         return 1;
+        //     }
+        // }
 
         if (actual->value->kind == Ast_Kind_Polymorphic_Proc)
             has_polymorphic_args = 1;
@@ -1266,6 +1268,14 @@ b32 check_function_header(AstFunction* func) {
             return 1;
         }
 
+        local->ppt = Param_Pass_By_Value;
+
+        if (type_is_structlike_strict(local->type)
+                && !type_structlike_is_simple(local->type)) {
+            // local->type = type_make_pointer(semstate.node_allocator, local->type);
+            local->ppt = Param_Pass_By_Implicit_Pointer;
+        }
+
         if (param->is_vararg) has_had_varargs = 1;
 
         if (local->type->kind != Type_Kind_Array
index f75a143a8f0283eb40abea6a8763c895205c7632..f3cdc524e95f3daf5c2b24548d018ffe9c68f741 100644 (file)
@@ -922,8 +922,10 @@ EMIT_FUNC(for_array, AstFor* for_node, u64 iter_local) {
     WI(WI_BLOCK_END);
 
     WIL(WI_LOCAL_GET, ptr_local);
-    WIL(WI_I32_CONST, elem_size);
-    WI(WI_I32_ADD);
+    if (elem_size != 1) {
+        WIL(WI_I32_CONST, elem_size);
+        WI(WI_I32_ADD);
+    }
     WIL(WI_LOCAL_SET, ptr_local);
 
     bh_arr_pop(mod->structured_jump_target);
@@ -1018,8 +1020,10 @@ EMIT_FUNC(for_slice, AstFor* for_node, u64 iter_local) {
     WI(WI_BLOCK_END);
 
     WIL(WI_LOCAL_GET, ptr_local);
-    WIL(WI_I32_CONST, elem_size);
-    WI(WI_I32_ADD);
+    if (elem_size != 1) {
+        WIL(WI_I32_CONST, elem_size);
+        WI(WI_I32_ADD);
+    }
     WIL(WI_LOCAL_SET, ptr_local);
 
     bh_arr_pop(mod->structured_jump_target);
@@ -1316,6 +1320,18 @@ EMIT_FUNC(call, AstCall* call) {
             stack_grow_amm += type_size_of(arg->type);
             vararg_count += 1;
         }
+
+        // CLEANUP structs-by-value
+        else if (type_is_structlike_strict(arg->type) && !type_structlike_is_simple(arg->type)) {
+            WID(WI_GLOBAL_GET, stack_top_idx);
+            emit_store_instruction(mod, &code, arg->type, stack_grow_amm);
+
+            WID(WI_GLOBAL_GET, stack_top_idx);
+            WID(WI_I32_CONST, stack_grow_amm);
+            WI(WI_I32_ADD);
+
+            stack_grow_amm += type_size_of(arg->type);
+        }
     }
 
     if (vararg_count > 0) {
@@ -1333,7 +1349,7 @@ EMIT_FUNC(call, AstCall* call) {
 
     stack_grow_amm += return_size;
 
-    b32 needs_stack = (cc == CC_Return_Stack) || (vararg_count > 0);
+    b32 needs_stack = (cc == CC_Return_Stack) || (stack_grow_amm > 0);
 
     if (needs_stack) {
         WID(WI_GLOBAL_GET, stack_top_idx);
@@ -1791,14 +1807,17 @@ EMIT_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) {
         u64 o2 = 0;
         emit_array_access_location(mod, &code, (AstArrayAccess *) source_expr, &o2);
         offset += o2;
+
     } else if ((source_expr->kind == Ast_Kind_Local || source_expr->kind == Ast_Kind_Param)
         && source_expr->type->kind != Type_Kind_Pointer) {
         u64 o2 = 0;
         emit_local_location(mod, &code, (AstLocal *) source_expr, &o2);
         offset += o2;
+
     } else if (source_expr->kind == Ast_Kind_Memres
         && source_expr->type->kind != Type_Kind_Pointer) {
         emit_memory_reservation_location(mod, &code, (AstMemRes *) source_expr);
+
     } else {
         emit_expression(mod, &code, source_expr);
     }
@@ -1822,10 +1841,9 @@ EMIT_FUNC(local_location, AstLocal* local, u64* offset_return) {
     u64 local_offset = (u64) bh_imap_get(&mod->local_map, (u64) local);
 
     if (local_offset & LOCAL_IS_WASM) {
-        // HACK: This case doesn't feel quite right. I think the
-        // only way to end up here is if you are taking the slice
-        // off a pointer that is a local. But this still feels
-        // like the wrong long term solution.
+        // CLEANUP structs-by-value
+        // This is a weird condition but it is relied on in a couple places including
+        // passing non-simple structs by value.             -brendanfh 2020/09/18
         WIL(WI_LOCAL_GET, local_offset);
 
     } else {
@@ -1990,13 +2008,6 @@ EMIT_FUNC(location, AstTyped* expr) {
         case Ast_Kind_Field_Access: {
             AstFieldAccess* field = (AstFieldAccess *) expr;
 
-            if (field->expr->kind == Ast_Kind_Param && type_is_structlike_strict(field->expr->type)) {
-                u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + field->idx;
-
-                WIL(WI_LOCAL_GET, localidx);
-                break;
-            }
-
             u64 offset = 0;
             emit_field_access_location(mod, &code, field, &offset);
             if (offset != 0) {
@@ -2026,17 +2037,28 @@ EMIT_FUNC(expression, AstTyped* expr) {
 
     switch (expr->kind) {
         case Ast_Kind_Param: {
-            u64 localidx = bh_imap_get(&mod->local_map, (u64) expr);
-
-            if (type_is_structlike_strict(expr->type)) {
-                u32 mem_count = type_structlike_mem_count(expr->type);
+            AstLocal* param = (AstLocal *) expr;
+            u64 localidx = bh_imap_get(&mod->local_map, (u64) param);
+
+            switch (param->ppt) {
+                case Param_Pass_By_Value: {
+                    if (type_is_structlike_strict(expr->type)) {
+                        u32 mem_count = type_structlike_mem_count(expr->type);
+                        fori (idx, 0, mem_count) WIL(WI_LOCAL_GET, localidx + idx);
+
+                    } else {
+                        WIL(WI_LOCAL_GET, localidx);
+                    }
+                    break;
+                }
 
-                fori (idx, 0, mem_count) {
-                    WIL(WI_LOCAL_GET, localidx + idx);
+                case Param_Pass_By_Implicit_Pointer: {
+                    WIL(WI_LOCAL_GET, localidx);
+                    emit_load_instruction(mod, &code, expr->type, 0);
+                    break;
                 }
 
-            } else {
-                WIL(WI_LOCAL_GET, localidx);
+                default: assert(0);
             }
 
             break;
@@ -2144,14 +2166,20 @@ EMIT_FUNC(expression, AstTyped* expr) {
         case Ast_Kind_Field_Access: {
             AstFieldAccess* field = (AstFieldAccess* ) expr;
 
-            if (field->expr->kind == Ast_Kind_Param && type_is_structlike_strict(field->expr->type)) {
-                u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + field->idx;
+            // CLEANUP structs-by-value
+            if (field->expr->kind == Ast_Kind_Param) {
+                AstLocal* param = (AstLocal *) field->expr;
 
-                WIL(WI_LOCAL_GET, localidx);
-                break;
+                if (param->ppt == Param_Pass_By_Value && !type_is_pointer(param->type)) {
+                    u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + field->idx;
+                    WIL(WI_LOCAL_GET, localidx);
+                    break;
+                }
             }
 
-            if (field->expr->kind == Ast_Kind_StrLit) {
+
+            // HACK
+            else if (field->expr->kind == Ast_Kind_StrLit) {
                 StructMember smem;
 
                 token_toggle_end(field->token);
@@ -2462,15 +2490,23 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) {
     i32 params_left = param_count;
     while (params_left-- > 0) {
         if (type_is_structlike_strict(*param_type)) {
-            u32 mem_count = type_structlike_mem_count(*param_type);
-            StructMember smem;
+            if (!type_structlike_is_simple(*param_type)) {
+                // HACK!!
+                // CLEANUP structs-by-value
+                *(t++) = WASM_TYPE_INT32;
 
-            fori (i, 0, mem_count) {
-                type_lookup_member_by_idx(*param_type, i, &smem);
-                *(t++) = (char) onyx_type_to_wasm_type(smem.type);
+            } else {
+                u32 mem_count = type_structlike_mem_count(*param_type);
+                StructMember smem;
+
+                fori (i, 0, mem_count) {
+                    type_lookup_member_by_idx(*param_type, i, &smem);
+                    *(t++) = (char) onyx_type_to_wasm_type(smem.type);
+                }
+
+                param_count += mem_count - 1;
             }
 
-            param_count += mem_count - 1;
         } else {
             *(t++) = (char) onyx_type_to_wasm_type(*param_type);
         }
@@ -2582,12 +2618,23 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
         // NOTE: Generate the local map
         u64 localidx = 0;
         bh_arr_each(AstParam, param, fd->params) {
-            if (type_is_structlike_strict(param->local->type)) {
-                bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM);
-                localidx += type_structlike_mem_count(param->local->type);
+            switch (param->local->ppt) {
+                case Param_Pass_By_Value: {
+                    if (type_is_structlike_strict(param->local->type)) {
+                        bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM);
+                        localidx += type_structlike_mem_count(param->local->type);
+
+                        break;
+                    }
+                    // fallthrough
+                }
 
-            } else {
-                bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM);
+                case Param_Pass_By_Implicit_Pointer: {
+                    bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM);
+                    break;
+                }
+
+                default: assert(0);
             }
         }
 
index 7425a97cfb9a9a0c8c37200ad5f34df24f983736..92385c875d1d63ad13b776072d67d1d39917adb4 100644 (file)
@@ -5,24 +5,21 @@ package main
 use package core
 
 main :: proc (args: [] cstring) {
-    imap : I32Map(^string);
+    imap : I32Map(string);
     i32map_init(^imap);
     defer {
         print("Freeing map\n");
         i32map_free(^imap);
     }
 
-    hello := "Hello ";
-    world := "World!";
-
-    i32map_put(^imap, 50, ^hello);
-    i32map_put(^imap, 1234, ^world);
+    i32map_put(^imap, 50, "Hello ");
+    i32map_put(^imap, 1234, "World!");
 
     println(i32map_has(^imap, 50));
     println(i32map_has(^imap, 51));
 
-    print(*i32map_get(^imap, 50));
-    println(*i32map_get(^imap, 1234));
+    print(i32map_get(^imap, 50, ""));
+    println(i32map_get(^imap, 1234, ""));
 
     i32map_delete(^imap, 50);
     println(i32map_has(^imap, 50));