added 'do' expressions
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 28 Aug 2021 18:27:04 +0000 (13:27 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 28 Aug 2021 18:27:04 +0000 (13:27 -0500)
bin/onyx
docs/bugs
include/onyxastnodes.h
include/onyxwasm.h
src/onyxastnodes.c
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index 3bcc2ba078bf9b5e67217cabfa112613f8d76cb9..7758c4dc245a51f75514141ce8bbd2c91bd6cc9b 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 4b26b29e34e41cea25c87686d049a8a33d330cfd..55a744520cdc7fa247b5526ec8fbf25c5124ee6a 100644 (file)
--- a/docs/bugs
+++ b/docs/bugs
@@ -6,14 +6,22 @@ List of known bugs:
 
 [ ] Enums suck. Make them more powerful.
 
-[ ] add `do` expressions:
-    
+[X] add `do` expressions:
+
     x := do {
         a := 1;
         b := 2;
         return a + b;
     };
 
+    So then, expression macros can just do the following:
+
+    add :: macro (x: i32, y: i32) -> i32 do return x + y;
+
+    x := add(1, 2);
+    x := do { return 1 + 2; }
+
+
 [X] Add support for tabs in error messages.
 
 [ ] switch statements should work with any type that supports '=='.
index dbcb8f717595d56434cf27c2011d151d5dd757b4..48ac2bcbb7e49fac98ca80a18a5040cdbfb3621d 100644 (file)
@@ -29,6 +29,7 @@
     NODE(RangeLiteral)         \
     NODE(Compound)             \
     NODE(IfExpression)         \
+    NODE(DoBlock)              \
                                \
     NODE(DirectiveSolidify)    \
     NODE(DirectiveError)       \
@@ -195,6 +196,7 @@ typedef enum AstKind {
     Ast_Kind_Code_Block,
     Ast_Kind_Directive_Insert,
     Ast_Kind_Macro,
+    Ast_Kind_Do_Block,
 
     Ast_Kind_Note,
 
@@ -492,10 +494,12 @@ typedef enum VarArgKind {
 typedef enum BlockRule {
     Block_Rule_New_Scope         = BH_BIT(1),
     Block_Rule_Clear_Defer       = BH_BIT(2),
+    Block_Rule_Override_Return   = BH_BIT(3),
 
     Block_Rule_Normal     = Block_Rule_New_Scope | Block_Rule_Clear_Defer,
     Block_Rule_Macro      = Block_Rule_New_Scope,
     Block_Rule_Code_Block = Block_Rule_New_Scope,
+    Block_Rule_Do_Block   = Block_Rule_New_Scope | Block_Rule_Clear_Defer | Block_Rule_Override_Return,
 } BlockRule;
 
 typedef struct Arguments Arguments;
@@ -626,6 +630,11 @@ struct AstIfExpression {
     AstTyped* true_expr;
     AstTyped* false_expr;
 };
+struct AstDoBlock {
+    AstTyped_base;
+
+    AstBlock* block;
+};
 
 struct AstDirectiveSolidify {
     AstTyped_base;
index 29dc274cf6b38e8688ae763c81fa4b4a160ac656..b423403db0be1eaa7feb18d7140839a4fa239237 100644 (file)
@@ -556,7 +556,8 @@ typedef struct OnyxWasmModule {
     bh_table(StrLitInfo) loaded_file_info;
     bh_table(StrLitInfo) string_literals;
 
-    bh_arr(u8) structured_jump_target;
+    bh_arr(u8)  structured_jump_target;
+    bh_arr(AstLocal*) return_location_stack;   // NOTE: Used for do-block return expressions.
 
     bh_arr(WasmFuncType*) types; // NOTE: This have to be pointers because the type is variadic in size
     bh_arr(WasmImport)    imports;
index 439a1ff25498a861a453c7d3b79dba79bc614c7a..666a20386ac0a310071d6e9381ffaa7becdafce6 100644 (file)
@@ -91,6 +91,7 @@ static const char* ast_node_names[] = {
     "CODE BLOCK",
     "DIRECTIVE INSERT",
     "MACRO",
+    "DO BLOCK",
 
     "NOTE",
 
index f57b116d4eb426869cdb5f42c6856c3ce05bc6e1..9a7b4f8ded6aefa5fb0c106904752807222629c8 100644 (file)
@@ -82,7 +82,7 @@ CheckStatus check_memres_type(AstMemRes* memres);
 CheckStatus check_memres(AstMemRes* memres);
 CheckStatus check_type(AstType* type);
 CheckStatus check_insert_directive(AstDirectiveInsert** pinsert);
-
+CheckStatus check_do_block(AstDoBlock** pdoblock);
 
 // HACK HACK HACK
 b32 expression_types_must_be_known = 0;
@@ -1357,6 +1357,26 @@ CheckStatus check_if_expression(AstIfExpression* if_expr) {
     return Check_Success;
 }
 
+CheckStatus check_do_block(AstDoBlock** pdoblock) {
+    AstDoBlock* doblock = *pdoblock;
+    if (doblock->flags & Ast_Flag_Has_Been_Checked) return Check_Success;
+
+    fill_in_type((AstTyped *) doblock);
+
+    Type** old_expected_return_type = expected_return_type;
+    expected_return_type = &doblock->type;
+
+    doblock->block->rules = Block_Rule_Do_Block;
+    CHECK(block, doblock->block);
+
+    if (doblock->type == &type_auto_return)
+        ERROR(doblock->token->pos, "Unable to determine type of do-block expression.");
+
+    expected_return_type = old_expected_return_type;
+    doblock->flags |= Ast_Flag_Has_Been_Checked;
+    return Check_Success;
+}
+
 CheckStatus check_address_of(AstAddressOf* aof) {
     CHECK(expression, &aof->expr);
     if (aof->expr->type == NULL) {
@@ -1549,12 +1569,12 @@ CheckStatus check_method_call(AstBinaryOp** mcall) {
         // would be good.                                      - brendanfh 2020/02/05
         if (implicit_argument->type->kind != Type_Kind_Pointer)
             implicit_argument = (AstTyped *) make_address_of(context.ast_alloc, implicit_argument);
-        
+
         implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument);
 
         bh_arr_insertn(call_node->args.values, 0, 1);
         call_node->args.values[0] = implicit_argument;
-    }    
+    }
     (*mcall)->flags |= Ast_Flag_Has_Been_Checked;
 
     CHECK(call, &call_node);
@@ -1731,6 +1751,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
             fill_in_type(expr);
             break;
 
+        case Ast_Kind_Do_Block:
+            retval = check_do_block((AstDoBlock **) pexpr);
+            break;
+
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
@@ -1740,7 +1764,7 @@ CheckStatus check_expression(AstTyped** pexpr) {
         case Ast_Kind_Package: break;
         case Ast_Kind_Error: break;
         case Ast_Kind_Unary_Field_Access: break;
-        
+
         // NOTE: The only way to have an Intrinsic_Call node is to have gone through the
         // checking of a call node at least once.
         case Ast_Kind_Intrinsic_Call: break;
index 425a2dca8efda262b1c5af87de35421e141e342b..7dfe23da80dcee7c5e47652814a0468db0eff31b 100644 (file)
@@ -3,30 +3,30 @@
 #include "onyxutils.h"
 
 static inline b32 should_clone(AstNode* node) {
-       if (node->flags & Ast_Flag_No_Clone) return 0;
-
-       switch (node->kind) {
-               // List of nodes that should not be copied
-               case Ast_Kind_Global:
-               case Ast_Kind_Memres:
-               case Ast_Kind_StrLit:
-               case Ast_Kind_Package:
-               case Ast_Kind_Enum_Type:
-               case Ast_Kind_Enum_Value:
-               case Ast_Kind_Overloaded_Function:
-               case Ast_Kind_Polymorphic_Proc:
-               case Ast_Kind_Alias:
-               case Ast_Kind_Code_Block:
-               case Ast_Kind_Macro:
-               case Ast_Kind_File_Contents:
-                       return 0;
-
-               default: return 1;
-       }
+    if (node->flags & Ast_Flag_No_Clone) return 0;
+
+    switch (node->kind) {
+        // List of nodes that should not be copied
+        case Ast_Kind_Global:
+        case Ast_Kind_Memres:
+        case Ast_Kind_StrLit:
+        case Ast_Kind_Package:
+        case Ast_Kind_Enum_Type:
+        case Ast_Kind_Enum_Value:
+        case Ast_Kind_Overloaded_Function:
+        case Ast_Kind_Polymorphic_Proc:
+        case Ast_Kind_Alias:
+        case Ast_Kind_Code_Block:
+        case Ast_Kind_Macro:
+        case Ast_Kind_File_Contents:
+            return 0;
+
+        default: return 1;
+    }
 }
 
 static inline i32 ast_kind_to_size(AstNode* node) {
-       switch (node->kind) {
+    switch (node->kind) {
         case Ast_Kind_Error: return sizeof(AstNode);
         case Ast_Kind_Package: return sizeof(AstPackage);
         case Ast_Kind_Load_File: return sizeof(AstInclude);
@@ -98,217 +98,218 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Static_If: return sizeof(AstIfWhile);
         case Ast_Kind_If_Expression: return sizeof(AstIfExpression);
         case Ast_Kind_Directive_Insert: return sizeof(AstDirectiveInsert);
+        case Ast_Kind_Do_Block: return sizeof(AstDoBlock);
         case Ast_Kind_Count: return 0;
-       }
+    }
 
     return 0;
 }
 
 AstNode* ast_clone_list(bh_allocator a, void* n) {
-       AstNode* node = (AstNode *) n;
-       if (node == NULL) return NULL;
-
-       AstNode* root = ast_clone(a, node);
-       AstNode* curr = root->next;
-       AstNode** insertion = &root->next;
-
-       while (curr != NULL) {
-               curr = ast_clone(a, curr);
-               *insertion = curr;
-               insertion = &curr->next;
-               curr = curr->next;
-       }
+    AstNode* node = (AstNode *) n;
+    if (node == NULL) return NULL;
+
+    AstNode* root = ast_clone(a, node);
+    AstNode* curr = root->next;
+    AstNode** insertion = &root->next;
+
+    while (curr != NULL) {
+        curr = ast_clone(a, curr);
+        *insertion = curr;
+        insertion = &curr->next;
+        curr = curr->next;
+    }
 
-       return root;
+    return root;
 }
 
 #define C(nt, mname) ((nt *) nn)->mname = (void *) ast_clone(a, ((nt *) node)->mname);
 
 // NOTE: Using void* to avoid a lot of unnecessary casting
 AstNode* ast_clone(bh_allocator a, void* n) {
-       AstNode* node = (AstNode *) n;
+    AstNode* node = (AstNode *) n;
 
-       if (node == NULL) return NULL;
-       if (!should_clone(node)) return node;
+    if (node == NULL) return NULL;
+    if (!should_clone(node)) return node;
 
-       static int clone_depth = 0;
-       clone_depth++;
+    static int clone_depth = 0;
+    clone_depth++;
 
-       i32 node_size = ast_kind_to_size(node);
-       // bh_printf("Cloning %s with size %d\n", onyx_ast_node_kind_string(node->kind), node_size);
+    i32 node_size = ast_kind_to_size(node);
+    // bh_printf("Cloning %s with size %d\n", onyx_ast_node_kind_string(node->kind), node_size);
 
-       AstNode* nn = onyx_ast_node_new(a, node_size, node->kind);
-       memmove(nn, node, node_size);
+    AstNode* nn = onyx_ast_node_new(a, node_size, node->kind);
+    memmove(nn, node, node_size);
 
-       switch ((u16) node->kind) {
-               case Ast_Kind_Binary_Op:
+    switch ((u16) node->kind) {
+        case Ast_Kind_Binary_Op:
         case Ast_Kind_Pipe:
         case Ast_Kind_Method_Call:
-               C(AstBinaryOp, left);
-               C(AstBinaryOp, right);
-                       break;
+            C(AstBinaryOp, left);
+            C(AstBinaryOp, right);
+            break;
 
-               case Ast_Kind_Unary_Op:
-                       C(AstUnaryOp, expr);
-                       C(AstUnaryOp, type_node);
-                       break;
+        case Ast_Kind_Unary_Op:
+            C(AstUnaryOp, expr);
+            C(AstUnaryOp, type_node);
+            break;
 
-               case Ast_Kind_Param:
-               case Ast_Kind_Local:
-                       C(AstLocal, type_node);
-                       break;
+        case Ast_Kind_Param:
+        case Ast_Kind_Local:
+            C(AstLocal, type_node);
+            break;
 
-               case Ast_Kind_Call:
+        case Ast_Kind_Call:
             arguments_deep_clone(a, &((AstCall *) nn)->args, &((AstCall *) node)->args);
-                       break;
+            break;
 
-               case Ast_Kind_Argument:
-                       C(AstArgument, value);
-                       break;
+        case Ast_Kind_Argument:
+            C(AstArgument, value);
+            break;
 
-               case Ast_Kind_Address_Of:
-                       C(AstAddressOf, expr);
-                       break;
+        case Ast_Kind_Address_Of:
+            C(AstAddressOf, expr);
+            break;
 
-               case Ast_Kind_Dereference:
-                       C(AstDereference, expr);
-                       break;
+        case Ast_Kind_Dereference:
+            C(AstDereference, expr);
+            break;
 
-               case Ast_Kind_Slice:
-               case Ast_Kind_Subscript:
-                       C(AstSubscript, addr);
-                       C(AstSubscript, expr);
-                       break;
+        case Ast_Kind_Slice:
+        case Ast_Kind_Subscript:
+            C(AstSubscript, addr);
+            C(AstSubscript, expr);
+            break;
 
-               case Ast_Kind_Field_Access:
-                       C(AstFieldAccess, expr);
-                       break;
+        case Ast_Kind_Field_Access:
+            C(AstFieldAccess, expr);
+            break;
 
-               case Ast_Kind_Size_Of:
-                       C(AstSizeOf, so_ast_type);
-                       break;
+        case Ast_Kind_Size_Of:
+            C(AstSizeOf, so_ast_type);
+            break;
 
-               case Ast_Kind_Align_Of:
-                       C(AstAlignOf, ao_ast_type);
-                       break;
+        case Ast_Kind_Align_Of:
+            C(AstAlignOf, ao_ast_type);
+            break;
 
-               case Ast_Kind_Struct_Literal: {
-                       AstStructLiteral* st = (AstStructLiteral *) node;
-                       AstStructLiteral* dt = (AstStructLiteral *) nn;
+        case Ast_Kind_Struct_Literal: {
+            AstStructLiteral* st = (AstStructLiteral *) node;
+            AstStructLiteral* dt = (AstStructLiteral *) nn;
 
-                       dt->stnode = (AstTyped *) ast_clone(a, st->stnode);
+            dt->stnode = (AstTyped *) ast_clone(a, st->stnode);
 
             arguments_deep_clone(a, &dt->args, &st->args);
-                       break;
-               }
+            break;
+        }
 
-               case Ast_Kind_Array_Literal: {
-                       AstArrayLiteral* st = (AstArrayLiteral *) node;
-                       AstArrayLiteral* dt = (AstArrayLiteral *) nn;
+        case Ast_Kind_Array_Literal: {
+            AstArrayLiteral* st = (AstArrayLiteral *) node;
+            AstArrayLiteral* dt = (AstArrayLiteral *) nn;
 
-                       dt->atnode = (AstTyped *) ast_clone(a, st->atnode);
+            dt->atnode = (AstTyped *) ast_clone(a, st->atnode);
 
-                       dt->values = NULL;
-                       bh_arr_new(global_heap_allocator, dt->values, bh_arr_length(st->values));
-                       bh_arr_each(AstTyped *, val, st->values)
-                               bh_arr_push(dt->values, (AstTyped *) ast_clone(a, *val));
+            dt->values = NULL;
+            bh_arr_new(global_heap_allocator, dt->values, bh_arr_length(st->values));
+            bh_arr_each(AstTyped *, val, st->values)
+                bh_arr_push(dt->values, (AstTyped *) ast_clone(a, *val));
 
-                       break;
-               }
+            break;
+        }
 
         case Ast_Kind_Range_Literal:
-               C(AstRangeLiteral, low);
-               C(AstRangeLiteral, high);
-               C(AstRangeLiteral, step);
-               break;
-
-               case Ast_Kind_Return:
-                       C(AstReturn, expr);
-                       break;
-
-               case Ast_Kind_Block:
-                       ((AstBlock *) nn)->body = ast_clone_list(a, ((AstBlock *) node)->body);
-                       break;
-
-               case Ast_Kind_Defer:
-                       C(AstDefer, stmt);
-                       break;
-
-               case Ast_Kind_For:
-                       C(AstFor, var);
-                       C(AstFor, iter);
-                       C(AstFor, stmt);
-                       break;
-
-               case Ast_Kind_If:
-               case Ast_Kind_While:
-                       C(AstIfWhile, local);
-                       C(AstIfWhile, assignment);
-
-                       if (((AstIfWhile *) nn)->assignment)
-                               ((AstIfWhile *) nn)->assignment->left = (AstTyped *) ((AstIfWhile *) nn)->local;
-
-                       C(AstIfWhile, cond);
-                       //fallthrough
-
-               case Ast_Kind_Static_If:
-                       C(AstIfWhile, true_stmt);
-                       C(AstIfWhile, false_stmt);
-                       break;
-
-               case Ast_Kind_Switch: {
-                       AstSwitch* dw = (AstSwitch *) nn;
-                       AstSwitch* sw = (AstSwitch *) node;
-
-                       dw->local = (AstLocal *) ast_clone(a, sw->local);
-                       dw->assignment = (AstBinaryOp *) ast_clone(a, sw->assignment);
-                       if (dw->assignment)
-                               dw->assignment->left = (AstTyped *) sw->local;
-                       dw->expr = (AstTyped *) ast_clone(a, sw->expr);
-
-                       dw->default_case = (AstBlock *) ast_clone(a, sw->default_case);
-
-                       dw->cases = NULL;
-                       bh_arr_new(global_heap_allocator, dw->cases, bh_arr_length(sw->cases));
-
-                       bh_arr_each(AstSwitchCase, c, sw->cases) {
-                               bh_arr(AstTyped *) new_values = NULL;
-                               bh_arr_new(global_heap_allocator, new_values, bh_arr_length(c->values));
-                               bh_arr_each(AstTyped *, value, c->values)
-                                       bh_arr_push(new_values, (AstTyped *) ast_clone(a, *value));
-
-                               AstSwitchCase sc;
-                               sc.values = new_values; 
-                               sc.block = (AstBlock *) ast_clone(a, c->block);
-                               bh_arr_push(dw->cases, sc);
-                       }
-                       break;
-               }
-
-               case Ast_Kind_Pointer_Type:
-                       C(AstPointerType, elem);
-                       break;
-
-               case Ast_Kind_Array_Type:
-                       C(AstArrayType, count_expr);
-                       C(AstArrayType, elem);
-                       break;
-
-               case Ast_Kind_Slice_Type:
-                       C(AstSliceType, elem);
-                       break;
-
-               case Ast_Kind_DynArr_Type:
-                       C(AstDynArrType, elem);
-                       break;
-
-               case Ast_Kind_VarArg_Type:
-                       C(AstVarArgType, elem);
-                       break;
-
-               case Ast_Kind_Type_Alias:
-                       C(AstTypeAlias, to);
-                       break;
+            C(AstRangeLiteral, low);
+            C(AstRangeLiteral, high);
+            C(AstRangeLiteral, step);
+            break;
+
+        case Ast_Kind_Return:
+            C(AstReturn, expr);
+            break;
+
+        case Ast_Kind_Block:
+            ((AstBlock *) nn)->body = ast_clone_list(a, ((AstBlock *) node)->body);
+            break;
+
+        case Ast_Kind_Defer:
+            C(AstDefer, stmt);
+            break;
+
+        case Ast_Kind_For:
+            C(AstFor, var);
+            C(AstFor, iter);
+            C(AstFor, stmt);
+            break;
+
+        case Ast_Kind_If:
+        case Ast_Kind_While:
+            C(AstIfWhile, local);
+            C(AstIfWhile, assignment);
+
+            if (((AstIfWhile *) nn)->assignment)
+                ((AstIfWhile *) nn)->assignment->left = (AstTyped *) ((AstIfWhile *) nn)->local;
+
+            C(AstIfWhile, cond);
+            //fallthrough
+
+        case Ast_Kind_Static_If:
+            C(AstIfWhile, true_stmt);
+            C(AstIfWhile, false_stmt);
+            break;
+
+        case Ast_Kind_Switch: {
+            AstSwitch* dw = (AstSwitch *) nn;
+            AstSwitch* sw = (AstSwitch *) node;
+
+            dw->local = (AstLocal *) ast_clone(a, sw->local);
+            dw->assignment = (AstBinaryOp *) ast_clone(a, sw->assignment);
+            if (dw->assignment)
+                dw->assignment->left = (AstTyped *) sw->local;
+            dw->expr = (AstTyped *) ast_clone(a, sw->expr);
+
+            dw->default_case = (AstBlock *) ast_clone(a, sw->default_case);
+
+            dw->cases = NULL;
+            bh_arr_new(global_heap_allocator, dw->cases, bh_arr_length(sw->cases));
+
+            bh_arr_each(AstSwitchCase, c, sw->cases) {
+                bh_arr(AstTyped *) new_values = NULL;
+                bh_arr_new(global_heap_allocator, new_values, bh_arr_length(c->values));
+                bh_arr_each(AstTyped *, value, c->values)
+                    bh_arr_push(new_values, (AstTyped *) ast_clone(a, *value));
+
+                AstSwitchCase sc;
+                sc.values = new_values; 
+                sc.block = (AstBlock *) ast_clone(a, c->block);
+                bh_arr_push(dw->cases, sc);
+            }
+            break;
+        }
+
+        case Ast_Kind_Pointer_Type:
+            C(AstPointerType, elem);
+            break;
+
+        case Ast_Kind_Array_Type:
+            C(AstArrayType, count_expr);
+            C(AstArrayType, elem);
+            break;
+
+        case Ast_Kind_Slice_Type:
+            C(AstSliceType, elem);
+            break;
+
+        case Ast_Kind_DynArr_Type:
+            C(AstDynArrType, elem);
+            break;
+
+        case Ast_Kind_VarArg_Type:
+            C(AstVarArgType, elem);
+            break;
+
+        case Ast_Kind_Type_Alias:
+            C(AstTypeAlias, to);
+            break;
 
         case Ast_Kind_Struct_Type: {
             AstStructType* ds = (AstStructType *) nn;
@@ -326,8 +327,8 @@ AstNode* ast_clone(bh_allocator a, void* n) {
         }
 
         case Ast_Kind_Struct_Member:
-               C(AstStructMember, type_node);
-               C(AstStructMember, initial_value);
+            C(AstStructMember, type_node);
+            C(AstStructMember, initial_value);
             break;
 
         case Ast_Kind_Poly_Call_Type: {
@@ -358,72 +359,72 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             break;
         }
 
-               case Ast_Kind_Function_Type:
-                       C(AstFunctionType, return_type);
-                       ((AstFunctionType *) nn)->param_count = ((AstFunctionType *) node)->param_count;
-                       fori (i, 0, (i64) ((AstFunctionType *) nn)->param_count) {
-                               ((AstFunctionType *) nn)->params[i] = (AstType *) ast_clone(a, ((AstFunctionType *) node)->params[i]);
-                       }
-                       break;
-
-               case Ast_Kind_Binding:
-                       bh_printf("Cloning binding: %b\n", node->token->text, node->token->length);
-                       C(AstTyped, type_node);
-                       C(AstBinding, node);
-                       break;
-
-               case Ast_Kind_Function: {
-                       if (clone_depth > 1) {
-                               clone_depth--;
-                               return node;
-                       }
-
-                       AstFunction* df = (AstFunction *) nn;
-                       AstFunction* sf = (AstFunction *) node;
-
-                       if (sf->flags & Ast_Flag_Foreign) return node;
-
-                       df->return_type = (AstType *) ast_clone(a, sf->return_type);
-                       df->body = (AstBlock *) ast_clone(a, sf->body);
-
-                       df->params = NULL;
-                       bh_arr_new(global_heap_allocator, df->params, bh_arr_length(sf->params));
-
-                       bh_arr_each(AstParam, param, sf->params) {
-                               AstParam new_param = { 0 };
-                               new_param.local = (AstLocal *) ast_clone(a, param->local);
-                               new_param.default_value = (AstTyped *) ast_clone(a, param->default_value);
+        case Ast_Kind_Function_Type:
+            C(AstFunctionType, return_type);
+            ((AstFunctionType *) nn)->param_count = ((AstFunctionType *) node)->param_count;
+            fori (i, 0, (i64) ((AstFunctionType *) nn)->param_count) {
+                ((AstFunctionType *) nn)->params[i] = (AstType *) ast_clone(a, ((AstFunctionType *) node)->params[i]);
+            }
+            break;
+
+        case Ast_Kind_Binding:
+            bh_printf("Cloning binding: %b\n", node->token->text, node->token->length);
+            C(AstTyped, type_node);
+            C(AstBinding, node);
+            break;
+
+        case Ast_Kind_Function: {
+            if (clone_depth > 1) {
+                clone_depth--;
+                return node;
+            }
+
+            AstFunction* df = (AstFunction *) nn;
+            AstFunction* sf = (AstFunction *) node;
+
+            if (sf->flags & Ast_Flag_Foreign) return node;
+
+            df->return_type = (AstType *) ast_clone(a, sf->return_type);
+            df->body = (AstBlock *) ast_clone(a, sf->body);
+
+            df->params = NULL;
+            bh_arr_new(global_heap_allocator, df->params, bh_arr_length(sf->params));
+
+            bh_arr_each(AstParam, param, sf->params) {
+                AstParam new_param = { 0 };
+                new_param.local = (AstLocal *) ast_clone(a, param->local);
+                new_param.default_value = (AstTyped *) ast_clone(a, param->default_value);
                 new_param.vararg_kind = param->vararg_kind;
-                               bh_arr_push(df->params, new_param);
-                       }
+                bh_arr_push(df->params, new_param);
+            }
 
-                       break;
-               }
+            break;
+        }
 
-               case Ast_Kind_Use:
-                       C(AstUse, expr);
-                       break;
+        case Ast_Kind_Use:
+            C(AstUse, expr);
+            break;
 
-               case Ast_Kind_Directive_Solidify: {
-                       AstDirectiveSolidify* dd = (AstDirectiveSolidify *) nn;
-                       AstDirectiveSolidify* sd = (AstDirectiveSolidify *) node;
+        case Ast_Kind_Directive_Solidify: {
+            AstDirectiveSolidify* dd = (AstDirectiveSolidify *) nn;
+            AstDirectiveSolidify* sd = (AstDirectiveSolidify *) node;
 
-                       dd->poly_proc = (AstPolyProc *) ast_clone(a, (AstNode *) sd->poly_proc);
-                       dd->resolved_proc = NULL;
+            dd->poly_proc = (AstPolyProc *) ast_clone(a, (AstNode *) sd->poly_proc);
+            dd->resolved_proc = NULL;
 
-                       dd->known_polyvars = NULL;
-                       bh_arr_new(global_heap_allocator, dd->known_polyvars, bh_arr_length(sd->known_polyvars));
+            dd->known_polyvars = NULL;
+            bh_arr_new(global_heap_allocator, dd->known_polyvars, bh_arr_length(sd->known_polyvars));
 
-                       bh_arr_each(AstPolySolution, sln, sd->known_polyvars) {
-                               AstPolySolution new_sln;
+            bh_arr_each(AstPolySolution, sln, sd->known_polyvars) {
+                AstPolySolution new_sln;
                 new_sln.kind     = sln->kind;
-                               new_sln.poly_sym = (AstNode *) ast_clone(a, (AstNode *) sln->poly_sym);
-                               new_sln.ast_type = (AstType *) ast_clone(a, (AstNode *) sln->ast_type);
-                               bh_arr_push(dd->known_polyvars, new_sln);
-                       }
+                new_sln.poly_sym = (AstNode *) ast_clone(a, (AstNode *) sln->poly_sym);
+                new_sln.ast_type = (AstType *) ast_clone(a, (AstNode *) sln->ast_type);
+                bh_arr_push(dd->known_polyvars, new_sln);
+            }
 
-                       break;
-               }
+            break;
+        }
 
         case Ast_Kind_Compound: {
             AstCompound* cd = (AstCompound *) nn;
@@ -439,27 +440,32 @@ AstNode* ast_clone(bh_allocator a, void* n) {
         }
 
         case Ast_Kind_Named_Value:
-               C(AstNamedValue, value);
+            C(AstNamedValue, value);
             break;
 
         case Ast_Kind_If_Expression:
-               C(AstIfExpression, cond);
-               C(AstIfExpression, true_expr);
-               C(AstIfExpression, false_expr);
+            C(AstIfExpression, cond);
+            C(AstIfExpression, true_expr);
+            C(AstIfExpression, false_expr);
             break;
 
-               case Ast_Kind_Directive_Insert:
-                       C(AstDirectiveInsert, code_expr);
-                       break;
+        case Ast_Kind_Directive_Insert:
+            C(AstDirectiveInsert, code_expr);
+            break;
 
-               case Ast_Kind_Typeof:
-                       C(AstTypeOf, expr);
-                       ((AstTypeOf *) nn)->resolved_type = NULL;
-                       break;
-       }
+        case Ast_Kind_Typeof:
+            C(AstTypeOf, expr);
+            ((AstTypeOf *) nn)->resolved_type = NULL;
+            break;
+
+        case Ast_Kind_Do_Block:
+            C(AstDoBlock, block);
+            ((AstDoBlock *) nn)->type_node = (AstType *) &basic_type_auto_return;
+            break;
+    }
 
-       clone_depth--;
-       return nn;
+    clone_depth--;
+    return nn;
 }
 
 #undef C
index 8553f3c5cb33c9b27dd500cf8b1a8308ec3c9d1a..9fefea065daffd282e91c3c55b9f9fe73af36a33 100644 (file)
@@ -478,15 +478,6 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
-        #if 0
-        case Token_Type_Keyword_Proc: {
-            OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
-            onyx_report_warning(proc_token->pos, "Warning: 'proc' is a deprecated keyword.");
-            retval = (AstTyped *) parse_function_definition(parser, proc_token);
-            break;
-        }
-        #endif
-
         case Token_Type_Keyword_Package: {
             retval = (AstTyped *) parse_package_expression(parser);
             break;
@@ -497,6 +488,24 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
+        case Token_Type_Keyword_Do: {
+            OnyxToken* do_token = expect_token(parser, Token_Type_Keyword_Do);
+            AstDoBlock* do_block = make_node(AstDoBlock, Ast_Kind_Do_Block);
+            do_block->token = do_token;
+            do_block->type_node = (AstType *) &basic_type_auto_return;
+
+            if (parser->curr->type != '{') {
+                onyx_report_error(parser->curr->pos, "Expected '{' after 'do', got '%s'.", token_name(parser->curr->type));
+                retval = NULL;
+                break;
+            }
+
+            do_block->block = parse_block(parser, 1);
+
+            retval = (AstTyped *) do_block;
+            break;
+        }
+
         // :TypeValueInterchange
         case '<': {
             AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
index d0599222f31ef50326db5b0a2f7555f7cbc32e25..475e3f951449d2503d3b09bd69eae1526f20715e 100644 (file)
@@ -491,6 +491,9 @@ static SymresStatus symres_expression(AstTyped** expr) {
             SYMRES(directive_insert, (AstDirectiveInsert *) *expr);
             break;
 
+        case Ast_Kind_Do_Block:
+            SYMRES(block, ((AstDoBlock *) *expr)->block);
+            break;
 
         default: break;
     }
index 399002a12940c3ebbdb867d181b7b6b4464802cc..c15a66d04288e9fbabec2bb4d5e278780bae53d3 100644 (file)
@@ -256,6 +256,7 @@ EMIT_FUNC(array_store,                   Type* type, u32 offset);
 EMIT_FUNC(array_literal,                 AstArrayLiteral* al);
 EMIT_FUNC(range_literal,                 AstRangeLiteral* range);
 EMIT_FUNC(if_expression,                 AstIfExpression* if_expr);
+EMIT_FUNC(do_block,                      AstDoBlock* doblock);
 EMIT_FUNC(expression,                    AstTyped* expr);
 EMIT_FUNC(cast,                          AstUnaryOp* cast);
 EMIT_FUNC(return,                        AstReturn* ret);
@@ -283,8 +284,11 @@ EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers) {
 
     generate_block_headers = generate_block_headers && (block->rules & Block_Rule_New_Scope);
 
-    if (generate_block_headers)
-        emit_enter_structured_block(mod, &code, SBT_Breakable_Block);
+    if (generate_block_headers) {
+        emit_enter_structured_block(mod, &code, (block->rules & Block_Rule_Override_Return)
+                                                ? SBT_Return_Block
+                                                : SBT_Breakable_Block);
+    }
 
     forll (AstNode, stmt, block->body, next) {
         emit_statement(mod, &code, stmt);
@@ -346,19 +350,15 @@ EMIT_FUNC_NO_ARGS(leave_structured_block) {
     *pcode = code;
 }
 
-EMIT_FUNC(structured_jump, AstJump* jump) {
-    bh_arr(WasmInstruction) code = *pcode;
-
+i64 get_structured_jump_label(OnyxWasmModule* mod, JumpType jump_type, u32 jump_count) {
     // :CLEANUP These numbers should become constants because they are shared with
     // enter_structured_block's definitions.
     static const u8 wants[Jump_Type_Count] = { 1, 2, 3, 4 };
 
-    u64 labelidx = 0;
-    u8 wanted = wants[jump->jump];
+    i64 labelidx = 0;
+    u8 wanted = wants[jump_type];
     b32 success = 0;
 
-    u32 jump_count = jump->count;
-
     i32 len = bh_arr_length(mod->structured_jump_target) - 1;
     for (u8* t = &bh_arr_last(mod->structured_jump_target); len >= 0; len--, t--) {
         if (*t == wanted) jump_count--;
@@ -370,6 +370,14 @@ EMIT_FUNC(structured_jump, AstJump* jump) {
         labelidx++;
     }
 
+    return (success == 0) ? -1 : labelidx;
+}
+
+EMIT_FUNC(structured_jump, AstJump* jump) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    i64 labelidx = get_structured_jump_label(mod, jump->jump, jump->count);
+
     if (bh_arr_length(mod->deferred_stmts) != 0) {
         i32 i = bh_arr_length(mod->deferred_stmts) - 1;
         i32 d = bh_arr_length(mod->structured_jump_target) - (labelidx + 1);
@@ -380,7 +388,7 @@ EMIT_FUNC(structured_jump, AstJump* jump) {
         }
     }
 
-    if (success) {
+    if (labelidx >= 0) {
         // NOTE: If the previous instruction was a non conditional jump,
         // don't emit another jump since it will never be reached.
         if (bh_arr_last(code).type != WI_JUMP)
@@ -406,7 +414,7 @@ EMIT_FUNC(statement, AstNode* stmt) {
         case Ast_Kind_Block:      emit_block(mod, &code, (AstBlock *) stmt, 1); break;
         case Ast_Kind_Defer:      emit_defer(mod, &code, (AstDefer *) stmt); break;
         case Ast_Kind_Local:      emit_local_allocation(mod, &code, (AstTyped *) stmt); break;
-        
+
         case Ast_Kind_Directive_Insert: break;
 
         default:                  emit_expression(mod, &code, (AstTyped *) stmt); break;
@@ -2283,11 +2291,36 @@ EMIT_FUNC(if_expression, AstIfExpression* if_expr) {
     if (!result_is_local) {
         emit_local_location(mod, &code, (AstLocal *) if_expr, &offset);
         emit_load_instruction(mod, &code, if_expr->type, offset);
-        
+
+    } else {
+        WIL(WI_LOCAL_GET, result_local);
+    }
+
+    *pcode = code;
+}
+
+EMIT_FUNC(do_block, AstDoBlock* doblock) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    u64 result_local    = local_allocate(mod->local_alloc, (AstTyped *) doblock);
+    b32 result_is_local = (b32) ((result_local & LOCAL_IS_WASM) != 0);
+
+    bh_imap_put(&mod->local_map, (u64) doblock, result_local);
+    bh_arr_push(mod->return_location_stack, (AstLocal *) doblock);
+
+    emit_block(mod, &code, doblock->block, 1);
+
+    u64 offset = 0;
+    if (!result_is_local) {
+        emit_local_location(mod, &code, (AstLocal *) doblock, &offset);
+        emit_load_instruction(mod, &code, doblock->type, offset);
+
     } else {
         WIL(WI_LOCAL_GET, result_local);
     }
 
+    bh_arr_pop(mod->return_location_stack);
+
     *pcode = code;
 }
 
@@ -2478,6 +2511,7 @@ EMIT_FUNC(expression, AstTyped* expr) {
         }
 
         case Ast_Kind_Block:          emit_block(mod, &code, (AstBlock *) expr, 1); break;
+        case Ast_Kind_Do_Block:       emit_do_block(mod, &code, (AstDoBlock *) expr); break;
         case Ast_Kind_Call:           emit_call(mod, &code, (AstCall *) expr); break;
         case Ast_Kind_Argument:       emit_expression(mod, &code, ((AstArgument *) expr)->value); break;
         case Ast_Kind_Intrinsic_Call: emit_intrinsic_call(mod, &code, (AstCall *) expr); break;
@@ -2764,7 +2798,7 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
     if (fromidx != -1 && toidx != -1) {
         WasmInstructionType cast_op = cast_map[fromidx][toidx];
         assert(cast_op != WI_UNREACHABLE);
-        
+
         if (cast_op != WI_NOP) {
             WI(cast_op);
         }
@@ -2778,7 +2812,20 @@ EMIT_FUNC(return, AstReturn* ret) {
 
     // If we have an expression to return, we see if it should be placed on the linear memory stack, or the WASM stack.
     if (ret->expr) {
-        if (mod->curr_cc == CC_Return_Stack) {
+        if (bh_arr_length(mod->return_location_stack) > 0) {
+            AstLocal* dest = bh_arr_last(mod->return_location_stack);
+            u64 dest_loc = bh_imap_get(&mod->local_map, (u64) dest);
+            b32 dest_is_local = (b32) ((dest_loc & LOCAL_IS_WASM) != 0);
+
+            u64 offset = 0;
+            if (!dest_is_local) emit_local_location(mod, &code, dest, &offset);
+
+            emit_expression(mod, &code, ret->expr);
+
+            if (!dest_is_local) emit_store_instruction(mod, &code, dest->type, offset);
+            else                WIL(WI_LOCAL_SET, dest_loc);
+
+        } else if (mod->curr_cc == CC_Return_Stack) {
             WIL(WI_LOCAL_GET, mod->stack_base_idx);
             WID(WI_I32_CONST, type_size_of(ret->expr->type));
             WI(WI_I32_SUB);
@@ -2803,12 +2850,18 @@ EMIT_FUNC(return, AstReturn* ret) {
         }
     }
 
-    // Make a patch for the two instructions needed to restore the stack pointer
-    SUBMIT_PATCH(mod->stack_leave_patches, 0);
-    WI(WI_NOP);
-    WI(WI_NOP);
+    i64 jump_label = get_structured_jump_label(mod, Jump_Type_Return, 1);
+    if (jump_label >= 0) {
+        WIL(WI_JUMP, jump_label);
 
-    WI(WI_RETURN);
+    } else {
+        // Make a patch for the two instructions needed to restore the stack pointer
+        SUBMIT_PATCH(mod->stack_leave_patches, 0);
+        WI(WI_NOP);
+        WI(WI_NOP);
+
+        WI(WI_RETURN);
+    }
 
     *pcode = code;
 }
@@ -2858,7 +2911,7 @@ EMIT_FUNC(zero_value, WasmType wt) {
 
 EMIT_FUNC(zero_value_for_type, Type* type, OnyxToken* where) {
     bh_arr(WasmInstruction) code = *pcode;
-    
+
     if (type_is_structlike_strict(type)) {
         i32 mem_count = type_linear_member_count(type);
         TypeWithOffset two;
@@ -3036,7 +3089,7 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) {
 
         bh_arr_insert_end(wasm_func.code, 5);
         fori (i, 0, 5) wasm_func.code[i] = (WasmInstruction) { WI_NOP, 0 };
-        
+
         mod->stack_base_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR);
 
         // Generate code
@@ -3173,7 +3226,7 @@ static void emit_string_literal(OnyxWasmModule* mod, AstStrLit* strlit) {
         StrLitInfo sti = bh_table_get(StrLitInfo, mod->string_literals, (char *) strdata);
         strlit->addr   = sti.addr;
         strlit->length = sti.len;
-        
+
         bh_free(global_heap_allocator, strdata);
         return;
     }
@@ -3216,7 +3269,7 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) {
             i++;
         }
 
-        break;    
+        break;
     }
 
     case Ast_Kind_Struct_Literal: {
@@ -3275,7 +3328,7 @@ static b32 emit_raw_data_(OnyxWasmModule* mod, ptr data, AstTyped* node) {
 
         if (effective_type->kind == Type_Kind_Enum)
             effective_type = effective_type->Enum.backing;
-        
+
         switch (effective_type->Basic.kind) {
         case Basic_Kind_Bool:
         case Basic_Kind_I8:
@@ -3449,6 +3502,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
         .next_elem_idx = 0,
 
         .structured_jump_target = NULL,
+        .return_location_stack = NULL,
         .local_allocations = NULL,
         .stack_leave_patches = NULL,
 
@@ -3473,6 +3527,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_arr_new(alloc, module.data, 4);
     bh_arr_new(alloc, module.elems, 4);
 
+    bh_arr_new(global_heap_allocator, module.return_location_stack, 4);
     bh_arr_new(global_heap_allocator, module.structured_jump_target, 16);
     bh_arr_set_length(module.structured_jump_target, 0);
 
@@ -3520,7 +3575,7 @@ void emit_entity(Entity* ent) {
     switch (ent->type) {
         case Entity_Type_Foreign_Function_Header:
             if (!should_emit_function(ent->function)) break;
-            
+
             module->foreign_function_count++;
             emit_foreign_function(module, ent->function);
             // fallthrough
@@ -3535,7 +3590,7 @@ void emit_entity(Entity* ent) {
                     ent->expr->token->pos.line,
                     ent->expr->token->pos.column);
             }
-            
+
             bh_imap_put(&module->index_map, (u64) ent->function, module->next_func_idx++);
 
             if (ent->function->flags & Ast_Flag_Proc_Is_Null) {