From: Brendan Hansen Date: Sat, 28 Aug 2021 18:27:04 +0000 (-0500) Subject: added 'do' expressions X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=d607a779a38891e514efc6e25ec5356fe31a1a4e;p=onyx.git added 'do' expressions --- diff --git a/bin/onyx b/bin/onyx index 3bcc2ba0..7758c4dc 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/docs/bugs b/docs/bugs index 4b26b29e..55a74452 100644 --- 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 '=='. diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index dbcb8f71..48ac2bcb 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 29dc274c..b423403d 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -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; diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index 439a1ff2..666a2038 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -91,6 +91,7 @@ static const char* ast_node_names[] = { "CODE BLOCK", "DIRECTIVE INSERT", "MACRO", + "DO BLOCK", "NOTE", diff --git a/src/onyxchecker.c b/src/onyxchecker.c index f57b116d..9a7b4f8d 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; diff --git a/src/onyxclone.c b/src/onyxclone.c index 425a2dca..7dfe23da 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -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 diff --git a/src/onyxparser.c b/src/onyxparser.c index 8553f3c5..9fefea06 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index d0599222..475e3f95 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 399002a1..c15a66d0 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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) {