finalized returning multiple values
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 12 Jan 2021 16:13:38 +0000 (10:13 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 12 Jan 2021 16:13:38 +0000 (10:13 -0600)
bin/onyx
include/onyxastnodes.h
onyx.exe
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxwasm.c

index c9a1216ec9eb9f1ae144f934aacbd32be04a42f4..795bdb46277a79c8275c3f06c4601ad027a21133 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 83880b4d7b991b96ba68dd4abaaea10b5153ca6f..879d89a91c69c098b222f42a60b12db2aa282a27 100644 (file)
@@ -1043,6 +1043,7 @@ static inline CallingConvention type_function_get_cc(Type* type) {
     if (type->Function.return_type->kind == Type_Kind_Struct) return CC_Return_Stack;
     if (type->Function.return_type->kind == Type_Kind_Slice) return CC_Return_Stack;
     if (type->Function.return_type->kind == Type_Kind_DynArray) return CC_Return_Stack;
+    if (type->Function.return_type->kind == Type_Kind_Compound) return CC_Return_Stack;
     return CC_Return_Wasm;
 }
 
index b503b6cb3f305b682f3238e2690669b569634180..d254d18ef69973ad2b5f495dd6e9494860d50240 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 12f47cc2520783b896fc6535e45ff9de267eef32..03ffaf50fe91eb1882df8b11b5f980fb47e901c5 100644 (file)
@@ -1474,7 +1474,13 @@ CheckStatus check_block(AstBlock* block) {
             onyx_report_error((*value)->token->pos,
                     "Unable to resolve type for local '%b'.",
                     (*value)->token->text, (*value)->token->length);
-            return 1;
+            return Check_Error;
+        }
+
+        if ((*value)->type->kind == Type_Kind_Compound) {
+            onyx_report_error((*value)->token->pos,
+                    "Compound type not allowed as local variable type. Try splitting this into multiple variables.");
+            return Check_Error;
         }
     }
 
@@ -1510,6 +1516,14 @@ CheckStatus check_overloaded_function(AstOverloadedFunction* func) {
 CheckStatus check_struct(AstStructType* s_node) {
     // NOTE: fills in the stcache
     type_build_from_ast(semstate.allocator, (AstType *) s_node);
+    if (s_node->stcache == NULL) return Check_Error;
+
+    bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) {
+        if ((*smem)->type->kind == Type_Kind_Compound) {
+            onyx_report_error(s_node->token->pos, "Compound types are not allowed as struct member types.");
+            return Check_Error;
+        }
+    }
 
     return Check_Success;
 }
@@ -1574,6 +1588,11 @@ CheckStatus check_function_header(AstFunction* func) {
             return Check_Error;
         }
 
+        if (local->type->kind == Type_Kind_Compound) {
+            onyx_report_error(param->local->token->pos, "Compound types are not allowed as parameter types. Try splitting this into multiple parameters.");
+            return Check_Error;
+        }
+
         // NOTE: I decided to make parameter default values not type checked against
         // the actual parameter type. The actual type checking will happen in check_call
         // when the default value is used as an argument and then has to be checked against
index dcb73be119a527217856b75dcd1b07a1f7816535..02200203d7bbd1ec4882faabb2028a4b2aa38294 100644 (file)
@@ -58,6 +58,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Enum_Type: return sizeof(AstEnumType);
         case Ast_Kind_Type_Alias: return sizeof(AstTypeAlias);
         case Ast_Kind_Type_Raw_Alias: return sizeof(AstTypeRawAlias);
+        case Ast_Kind_Type_Compound: return sizeof(AstCompoundType);
         case Ast_Kind_Type_End: return 0;
         case Ast_Kind_Struct_Member: return sizeof(AstStructMember);
         case Ast_Kind_Enum_Value: return sizeof(AstEnumValue);
@@ -89,6 +90,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Switch: return sizeof(AstSwitch);
         case Ast_Kind_Switch_Case: return sizeof(AstSwitchCase);
         case Ast_Kind_Directive_Solidify: return sizeof(AstDirectiveSolidify);
+        case Ast_Kind_Compound: return sizeof(AstCompound);
         case Ast_Kind_Count: return 0;
        }
 
@@ -342,6 +344,19 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             break;
         }
 
+        case Ast_Kind_Type_Compound: {
+            AstCompoundType* cd = (AstCompoundType *) nn;
+            AstCompoundType* cs = (AstCompoundType *) node;
+
+            cd->types = NULL;
+            bh_arr_new(global_heap_allocator, cd->types, bh_arr_length(cs->types));
+
+            bh_arr_each(AstType *, type, cs->types) {
+                bh_arr_push(cd->types, (AstType *) ast_clone(a, (AstNode *) *type));
+            }
+            break;
+        }
+
                case Ast_Kind_Function_Type:
                        ((AstFunctionType *) nn)->return_type = (AstType *) ast_clone(a, ((AstFunctionType *) node)->return_type);
                        ((AstFunctionType *) nn)->param_count = ((AstFunctionType *) node)->param_count;
@@ -407,6 +422,19 @@ AstNode* ast_clone(bh_allocator a, void* n) {
 
                        break;
                }
+
+        case Ast_Kind_Compound: {
+            AstCompound* cd = (AstCompound *) nn;
+            AstCompound* cs = (AstCompound *) node;
+
+            cd->exprs = NULL;
+            bh_arr_new(global_heap_allocator, cd->exprs, bh_arr_length(cs->exprs));
+
+            bh_arr_each(AstTyped *, expr, cs->exprs) {
+                bh_arr_push(cd->exprs, (AstTyped *) ast_clone(a, (AstNode *) *expr));
+            }
+            break;
+        }
        }
 
        return nn;
index e8e5a403c6c5711d9beccdaf88432f486134b7af..51277e20aaea62a5b87910066bb0cc1cb35b9b0d 100644 (file)
@@ -1441,6 +1441,30 @@ static void parse_polymorphic_variable(OnyxParser* parser, AstType*** next_inser
     }
 }
 
+static AstType* parse_compound_type(OnyxParser* parser) {
+    AstType* first = parse_type(parser);
+
+    if (parser->curr->type == ',') {
+        AstCompoundType* ctype = make_node(AstCompoundType, Ast_Kind_Type_Compound);
+        ctype->token = parser->curr;
+
+        bh_arr_new(global_heap_allocator, ctype->types, 2);
+        bh_arr_push(ctype->types, first);
+
+        while (parser->curr->type == ',') {
+            if (parser->hit_unexpected_token) return (AstType *) ctype;
+            consume_token(parser);
+
+            bh_arr_push(ctype->types, parse_type(parser));
+        }
+
+        return (AstType *) ctype;
+
+    } else {
+        return first;
+    }
+}
+
 // <symbol>
 // '^' <type>
 static AstType* parse_type(OnyxParser* parser) {
@@ -1613,7 +1637,7 @@ static AstType* parse_type(OnyxParser* parser) {
             case '(': {
                 expect_token(parser, '(');
                 
-                *next_insertion = parse_type(parser);
+                *next_insertion = parse_compound_type(parser);
                 next_insertion = NULL;
 
                 expect_token(parser, ')');
index 5cc05d9c6f866e2ec13dce033ae5e8710fa3951e..ea0d9e8e87eef139e7de3e31569cdc626bbec36f 100644 (file)
@@ -209,6 +209,14 @@ AstType* symres_type(AstType* type) {
         return type;
     }
 
+    if (type->kind == Ast_Kind_Type_Compound) {
+        AstCompoundType* ctype = (AstCompoundType *) type;
+
+        bh_arr_each(AstType *, type, ctype->types) {
+            *type = symres_type(*type);
+        }
+    }
+
     return type;
 }
 
index e824988d3a4efb97e8b3e0966af373e3dc194334..ed76107daafb4e6455767dbbb6c4345023f5336b 100644 (file)
@@ -263,6 +263,7 @@ u32 type_size_of(Type* type) {
         case Type_Kind_Slice:    return 8;
         case Type_Kind_VarArgs:  return 8;
         case Type_Kind_DynArray: return 12;
+        case Type_Kind_Compound: return type->Compound.size;
         default:                 return 0;
     }
 }
@@ -280,6 +281,7 @@ u32 type_alignment_of(Type* type) {
         case Type_Kind_Slice:    return 4;
         case Type_Kind_VarArgs:  return 4;
         case Type_Kind_DynArray: return 4;
+        case Type_Kind_Compound: return 8; // HACK
         default: return 1;
     }
 }
@@ -523,6 +525,25 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             return type_build_from_ast(alloc, (AstType *) concrete);
         }
 
+        case Ast_Kind_Type_Compound: {
+            AstCompoundType* ctype = (AstCompoundType *) type_node;
+
+            i64 type_count = bh_arr_length(ctype->types);
+
+            Type* comp_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * type_count);
+            comp_type->kind = Type_Kind_Compound;
+            comp_type->Compound.size = 0;
+            comp_type->Compound.count = type_count;
+
+            fori (i, 0, type_count) {
+                assert(ctype->types[i] != NULL);
+                comp_type->Compound.types[i] = type_build_from_ast(alloc, ctype->types[i]);
+                comp_type->Compound.size += type_size_of(comp_type->Compound.types[i]);
+            }
+
+            return comp_type;
+        }
+
         case Ast_Kind_Symbol:
             assert(("symbol node in type expression", 0));
             return NULL;
@@ -698,6 +719,21 @@ const char* type_get_name(Type* type) {
             return bh_aprintf(global_scratch_allocator, "%s", buf);
         }
 
+        case Type_Kind_Compound: {
+            char buf[512];
+            fori (i, 0, 512) buf[i] = 0;
+
+            strncat(buf, "(", 511);
+            fori (i, 0, type->Compound.count) {
+                strncat(buf, type_get_name(type->Compound.types[i]), 511);
+                if (i != type->Compound.count - 1)
+                    strncat(buf, ", ", 511);
+            }
+            strncat(buf, ")", 511);
+
+            return bh_aprintf(global_scratch_allocator, "%s", buf);
+        }
+
         default: return "unknown";
     }
 }
@@ -900,7 +936,9 @@ b32 type_is_numeric(Type* type) {
 b32 type_is_compound(Type* type) {
     return type->kind != Type_Kind_Basic
         && type->kind != Type_Kind_Pointer
-        && type->kind != Type_Kind_Enum;
+        && type->kind != Type_Kind_Enum
+        && type->kind != Type_Kind_Function
+        && type->kind != Type_Kind_Array;
 }
 
 b32 type_is_simd(Type* type) {
@@ -942,7 +980,7 @@ b32 type_is_structlike_strict(Type* type) {
     if (type->kind == Type_Kind_Struct)   return 1;
     if (type->kind == Type_Kind_Slice)    return 1;
     if (type->kind == Type_Kind_DynArray) return 1;
-    if (type->kind == Type_Kind_VarArgs) return 1;
+    if (type->kind == Type_Kind_VarArgs)  return 1;
     return 0;
 }
 
index 5b3deb6ba62e60a708726a536d83011a5df33283..24ff36abe12b4811efbfc4ff96ca45ea5837cfdf 100644 (file)
@@ -182,12 +182,25 @@ static u64 local_lookup_idx(LocalAllocator* la, u64 value) {
 #define WIL(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, { .l = data } }))
 #define WIP(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, { .p = data } }))
 #define EMIT_FUNC(kind, ...) static void emit_ ## kind (OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, __VA_ARGS__)
+#define STACK_SWAP(type1, type2) { \
+    u64 t0 = local_raw_allocate(mod->local_alloc, type1); \
+    u64 t1 = local_raw_allocate(mod->local_alloc, type2); \
+                                                          \
+    WIL(WI_LOCAL_SET, t0);                                \
+    WIL(WI_LOCAL_SET, t1);                                \
+    WIL(WI_LOCAL_GET, t0);                                \
+    WIL(WI_LOCAL_GET, t1);                                \
+                                                          \
+    local_raw_free(mod->local_alloc, type1);              \
+    local_raw_free(mod->local_alloc, type2);              \
+    }
 
 EMIT_FUNC(function_body,                 AstFunction* fd);
 EMIT_FUNC(block,                         AstBlock* block, b32 generate_block_headers);
 EMIT_FUNC(statement,                     AstNode* stmt);
 EMIT_FUNC(assignment,                    AstBinaryOp* assign);
-EMIT_FUNC(assignment_of_array,           AstBinaryOp* assign);
+EMIT_FUNC(assignment_of_array,           AstTyped* left, AstTyped* right);
+EMIT_FUNC(compound_assignment,           AstBinaryOp* assign);
 EMIT_FUNC(store_instruction,             Type* type, u32 offset);
 EMIT_FUNC(load_instruction,              Type* type, u32 offset);
 EMIT_FUNC(if,                            AstIfWhile* if_node);
@@ -204,6 +217,7 @@ EMIT_FUNC(array_access_location,         AstArrayAccess* aa, u64* offset_return)
 EMIT_FUNC(field_access_location,         AstFieldAccess* field, u64* offset_return);
 EMIT_FUNC(local_location,                AstLocal* local, u64* offset_return);
 EMIT_FUNC(memory_reservation_location,   AstMemRes* memres);
+EMIT_FUNC(location_return_offset,        AstTyped* expr, u64* offset_return);
 EMIT_FUNC(location,                      AstTyped* expr);
 EMIT_FUNC(struct_load,                   Type* type, u64 offset);
 EMIT_FUNC(struct_lval,                   AstTyped* lval);
@@ -324,7 +338,13 @@ EMIT_FUNC(assignment, AstBinaryOp* assign) {
     }
 
     if (assign->right->type->kind == Type_Kind_Array) {
-        emit_assignment_of_array(mod, &code, assign);
+        emit_assignment_of_array(mod, &code, assign->left, assign->right);
+        *pcode = code;
+        return;
+    }
+
+    if (assign->right->type->kind == Type_Kind_Compound) {
+        emit_compound_assignment(mod, &code, assign);
         *pcode = code;
         return;
     }
@@ -389,13 +409,13 @@ EMIT_FUNC(assignment, AstBinaryOp* assign) {
     *pcode = code;
 }
 
-EMIT_FUNC(assignment_of_array, AstBinaryOp* assign) {
+EMIT_FUNC(assignment_of_array, AstTyped* left, AstTyped* right) {
     bh_arr(WasmInstruction) code = *pcode;
 
-    Type* rtype = assign->right->type;
+    Type* rtype = right->type;
     assert(rtype->kind == Type_Kind_Array);
 
-    if (assign->right->kind == Ast_Kind_Array_Literal) {
+    if (right->kind == Ast_Kind_Array_Literal) {
         Type* elem_type = rtype;
         u32 elem_count = 1;
         while (elem_type->kind == Type_Kind_Array) {
@@ -406,17 +426,17 @@ EMIT_FUNC(assignment_of_array, AstBinaryOp* assign) {
 
         u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
 
-        emit_location(mod, &code, assign->left);
+        emit_location(mod, &code, left);
         WIL(WI_LOCAL_SET, lptr_local);
 
-        AstArrayLiteral* al = (AstArrayLiteral *) assign->right;
+        AstArrayLiteral* al = (AstArrayLiteral *) right;
         fori (i, 0, elem_count) {
-            if (!type_is_structlike(elem_type))
+            if (!type_is_compound(elem_type))
                 WIL(WI_LOCAL_GET, lptr_local);
 
             emit_expression(mod, &code, al->values[i]);
 
-            if (!type_is_structlike(elem_type)) {
+            if (!type_is_compound(elem_type)) {
                 emit_store_instruction(mod, &code, elem_type, i * elem_size);
             } else {
                 WIL(WI_LOCAL_GET, lptr_local);
@@ -427,8 +447,8 @@ EMIT_FUNC(assignment_of_array, AstBinaryOp* assign) {
         local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
 
     } else {
-        emit_location(mod, &code, assign->left);
-        emit_expression(mod, &code, assign->right);
+        emit_location(mod, &code, left);
+        emit_expression(mod, &code, right);
         emit_array_store(mod, &code, rtype, 0);
     }
 
@@ -436,6 +456,42 @@ EMIT_FUNC(assignment_of_array, AstBinaryOp* assign) {
     return;
 }
 
+EMIT_FUNC(compound_assignment, AstBinaryOp* assign) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    emit_expression(mod, &code, assign->right);
+
+    AstCompound* compound_lval = (AstCompound *) assign->left;
+    bh_arr_rev_each(AstTyped *, plval, compound_lval->exprs) {
+        AstTyped *lval = *plval;
+
+        if (type_is_structlike_strict(lval->type)) {
+            emit_struct_lval(mod, &code, lval);
+            continue;
+        }
+
+        if (lval->kind == Ast_Kind_Local || lval->kind == Ast_Kind_Param) {
+            if (bh_imap_get(&mod->local_map, (u64) lval) & LOCAL_IS_WASM) {
+                u64 localidx = bh_imap_get(&mod->local_map, (u64) lval);
+                WIL(WI_LOCAL_SET, localidx);
+                continue;
+            }
+        }
+
+        u64 expr_tmp = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+        WIL(WI_LOCAL_SET, expr_tmp);
+        u64 offset = 0;
+        emit_location_return_offset(mod, &code, lval, &offset);
+        WIL(WI_LOCAL_GET, expr_tmp);
+        
+        local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+        emit_store_instruction(mod, &code, lval->type, offset);
+    }
+
+    *pcode = code;
+    return;
+}
+
 EMIT_FUNC(store_instruction, Type* type, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
 
@@ -449,6 +505,42 @@ EMIT_FUNC(store_instruction, Type* type, u32 offset) {
         return;
     }
 
+    if (type->kind == Type_Kind_Compound) {
+        u64 loc_tmp = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+        WIL(WI_LOCAL_SET, loc_tmp);
+
+        u32 placement = offset + type_size_of(type);
+        forir (i, type->Compound.count - 1, 0) {
+            Type* curr_type = type->Compound.types[i];
+            placement -= type_size_of(curr_type);
+
+            if (type_is_compound(curr_type)) {
+                if (bh_arr_last(code).type == WI_LOCAL_SET && (u64) bh_arr_last(code).data.l == loc_tmp) {
+                    bh_arr_last(code).type = WI_LOCAL_TEE;
+                } else {
+                    WIL(WI_LOCAL_GET, loc_tmp);
+                }
+
+                emit_store_instruction(mod, &code, curr_type, placement);
+            } else {
+                WasmType wt = onyx_type_to_wasm_type(curr_type);
+                u64 tmp_idx = local_raw_allocate(mod->local_alloc, wt);
+
+                WIL(WI_LOCAL_SET, tmp_idx);
+                WIL(WI_LOCAL_GET, loc_tmp);
+                WIL(WI_LOCAL_GET, tmp_idx);
+
+                emit_store_instruction(mod, &code, curr_type, placement);
+
+                local_raw_free(mod->local_alloc, wt);
+            }
+        }
+
+        local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+        *pcode = code;
+        return;
+    }
+
     if (type->kind == Type_Kind_Enum) {
         type = type->Enum.backing;
     }
@@ -505,6 +597,23 @@ EMIT_FUNC(load_instruction, Type* type, u32 offset) {
         return;
     }
 
+    if (type->kind == Type_Kind_Compound) {
+        u64 loc_tmp = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
+        WIL(WI_LOCAL_TEE, loc_tmp);
+
+        u32 accum_offset = offset;
+        fori (i, 0, type->Compound.count) {
+            if (i != 0) WIL(WI_LOCAL_GET, loc_tmp);
+
+            emit_load_instruction(mod, &code, type->Compound.types[i], accum_offset);
+            accum_offset += type_size_of(type->Compound.types[i]);
+        }
+
+        local_raw_free(mod->local_alloc, WASM_TYPE_INT32);
+        *pcode = code;
+        return;
+    }
+
     if (type->kind == Type_Kind_Enum) {
         type = type->Enum.backing;
     }
@@ -1223,8 +1332,8 @@ EMIT_FUNC(call, AstCall* call) {
     bh_arr_each(AstArgument *, parg, call->arg_arr) {
         AstArgument* arg = *parg;
 
-        b32 place_on_stack = 0;
-        b32 arg_is_struct  = type_is_structlike(arg->value->type);
+        b32 place_on_stack  = 0;
+        b32 arg_is_compound = type_is_compound(arg->value->type);
 
         if (arg->va_kind != VA_Kind_Not_VA) {
             if (vararg_offset == 0xffffffff) vararg_offset = stack_grow_amm;
@@ -1232,7 +1341,7 @@ EMIT_FUNC(call, AstCall* call) {
         }
         if (type_get_param_pass(arg->value->type) == Param_Pass_By_Implicit_Pointer) place_on_stack = 1;
 
-        if (place_on_stack && !arg_is_struct) WID(WI_GLOBAL_GET, stack_top_idx);
+        if (place_on_stack && !arg_is_compound) WID(WI_GLOBAL_GET, stack_top_idx);
 
         if (stack_grow_amm != 0) {
             stack_top_store_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
@@ -1255,7 +1364,7 @@ EMIT_FUNC(call, AstCall* call) {
         }
 
         if (place_on_stack) {
-            if (arg_is_struct) WID(WI_GLOBAL_GET, stack_top_idx);
+            if (arg_is_compound) WID(WI_GLOBAL_GET, stack_top_idx);
             emit_store_instruction(mod, &code, arg->value->type, stack_grow_amm);
 
             if (arg->va_kind != VA_Kind_Not_VA) vararg_count += 1;
@@ -1951,7 +2060,7 @@ EMIT_FUNC(array_store, Type* type, u32 offset) {
     // greater than like 16 we output a loop that copies them?
     //                                               - brendanfh 2020/12/16
     fori (i, 0, elem_count) {
-        if (!type_is_structlike(elem_type))
+        if (!type_is_compound(elem_type))
             WIL(WI_LOCAL_GET, lptr_local);
 
         if (bh_arr_last(code).type == WI_LOCAL_SET && (u64) bh_arr_last(code).data.l == rptr_local)
@@ -1960,7 +2069,7 @@ EMIT_FUNC(array_store, Type* type, u32 offset) {
             WIL(WI_LOCAL_GET, rptr_local);
         emit_load_instruction(mod, &code, elem_type, i * elem_size);
 
-        if (!type_is_structlike(elem_type)) {
+        if (!type_is_compound(elem_type)) {
             emit_store_instruction(mod, &code, elem_type, i * elem_size + offset);
         } else {
             WIL(WI_LOCAL_GET, lptr_local);
@@ -1986,12 +2095,12 @@ EMIT_FUNC(array_literal, AstArrayLiteral* al) {
     u32 elem_size = type_size_of(al->type->Array.elem);
 
     fori (i, 0, al->type->Array.count) {
-        if (!type_is_structlike(al->type->Array.elem))
+        if (!type_is_compound(al->type->Array.elem))
             WIL(WI_LOCAL_GET, mod->stack_base_idx);
 
         emit_expression(mod, &code, al->values[i]);
 
-        if (!type_is_structlike(al->type->Array.elem)) {
+        if (!type_is_compound(al->type->Array.elem)) {
             emit_store_instruction(mod, &code, al->type->Array.elem, local_offset + i * elem_size);
         } else {
             WIL(WI_LOCAL_GET, mod->stack_base_idx);
@@ -2016,52 +2125,38 @@ EMIT_FUNC(range_literal, AstRangeLiteral* range) {
     *pcode = code;
 }
 
-EMIT_FUNC(location, AstTyped* expr) {
+EMIT_FUNC(location_return_offset, AstTyped* expr, u64* offset_return) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (expr->kind) {
         case Ast_Kind_Param:
         case Ast_Kind_Local: {
-            u64 offset = 0;
-            emit_local_location(mod, &code, (AstLocal *) expr, &offset);
-            if (offset != 0) {
-                WID(WI_I32_CONST, offset);
-                WI(WI_I32_ADD);
-            }
+            emit_local_location(mod, &code, (AstLocal *) expr, offset_return);
             break;
         }
 
         case Ast_Kind_Dereference: {
             emit_expression(mod, &code, ((AstDereference *) expr)->expr);
+            *offset_return = 0;
             break;
         }
 
         case Ast_Kind_Array_Access: {
             AstArrayAccess* aa = (AstArrayAccess *) expr;
-            u64 offset = 0;
-            emit_array_access_location(mod, &code, aa, &offset);
-            if (offset != 0) {
-                WID(WI_I32_CONST, offset);
-                WI(WI_I32_ADD);
-            }
+            emit_array_access_location(mod, &code, aa, offset_return);
             break;
         }
 
         case Ast_Kind_Field_Access: {
             AstFieldAccess* field = (AstFieldAccess *) expr;
-
-            u64 offset = 0;
-            emit_field_access_location(mod, &code, field, &offset);
-            if (offset != 0) {
-                WID(WI_I32_CONST, offset);
-                WI(WI_I32_ADD);
-            }
+            emit_field_access_location(mod, &code, field, offset_return);
             break;
         }
 
         case Ast_Kind_Memres: {
             AstMemRes* memres = (AstMemRes *) expr;
             WID(WI_I32_CONST, memres->addr);
+            *offset_return = 0;
             break;
         }
 
@@ -2074,6 +2169,19 @@ EMIT_FUNC(location, AstTyped* expr) {
     *pcode = code;
 }
 
+EMIT_FUNC(location, AstTyped* expr) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    u64 offset = 0;
+    emit_location_return_offset(mod, &code, expr, &offset);
+    if (offset != 0) {
+        WID(WI_I32_CONST, offset);
+        WI(WI_I32_ADD);
+    } 
+
+    *pcode = code;
+}
+
 EMIT_FUNC(expression, AstTyped* expr) {
     bh_arr(WasmInstruction) code = *pcode;
 
@@ -2322,15 +2430,26 @@ EMIT_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Compound: {
+            AstCompound* compound = (AstCompound *) expr;
+
+            bh_arr_each(AstTyped *, expr, compound->exprs) {
+                emit_expression(mod, &code, *expr);
+            }
+            break;
+        }
+
         default:
             bh_printf("Unhandled case: %d\n", expr->kind);
             DEBUG_HERE;
             assert(0);
     }
 
+    // FIX: This is going to be wrong for structs and compound types.
     if (expr->flags & Ast_Flag_Expr_Ignored &&
-        !type_results_in_void(expr->type))
+        !type_results_in_void(expr->type)) {
         WI(WI_DROP);
+    }
 
     *pcode = code;
 }
@@ -2415,7 +2534,7 @@ EMIT_FUNC(return, AstReturn* ret) {
 
     if (ret->expr) {
         if (mod->curr_cc == CC_Return_Stack) {
-            if (type_is_structlike_strict(ret->expr->type)) {
+            if (type_is_compound(ret->expr->type)) {
                 emit_expression(mod, &code, ret->expr);
 
                 WIL(WI_LOCAL_GET, mod->stack_base_idx);