From 7f0c2a858848ae25dd3c6feef209c35c8359e285 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 18 Apr 2023 21:13:49 -0500 Subject: [PATCH] added: parsing, symres, checking of capture blocks --- compiler/include/astnodes.h | 24 ++++++++++++++++++++++++ compiler/src/astnodes.c | 3 +++ compiler/src/checker.c | 26 +++++++++++++++++++++++++- compiler/src/clone.c | 21 +++++++++++++++++++++ compiler/src/parser.c | 29 +++++++++++++++++++++++++++++ compiler/src/symres.c | 31 +++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 1 deletion(-) diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 74c6b48a..c3ffdc3b 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -103,6 +103,9 @@ NODE(DirectiveInsert) \ NODE(Macro) \ \ + NODE(CaptureBlock) \ + NODE(CaptureLocal) \ + \ NODE(ForeignBlock) \ \ NODE(Package) \ @@ -231,6 +234,9 @@ typedef enum AstKind { Ast_Kind_Macro, Ast_Kind_Do_Block, + Ast_Kind_Capture_Block, + Ast_Kind_Capture_Local, + Ast_Kind_Foreign_Block, Ast_Kind_Zero_Value, @@ -1332,12 +1338,30 @@ struct AstFunction { AstBinding *original_binding_to_node; + AstCaptureBlock *captures; + b32 is_exported : 1; b32 is_foreign : 1; b32 is_foreign_dyncall : 1; b32 is_intrinsic : 1; }; +struct AstCaptureBlock { + AstNode_base; + + bh_arr(AstCaptureLocal *) captures; + + u32 total_size_in_bytes; + + b32 is_legal : 1; +}; + +struct AstCaptureLocal { + AstTyped_base; + + u32 offset; +}; + struct AstPolyQuery { AstNode_base; diff --git a/compiler/src/astnodes.c b/compiler/src/astnodes.c index 04bf9f64..d97b793c 100644 --- a/compiler/src/astnodes.c +++ b/compiler/src/astnodes.c @@ -108,6 +108,9 @@ static const char* ast_node_names[] = { "MACRO", "DO BLOCK", + "CAPTURE BLOCK", + "CAPTURE LOCAL", + "FOREIGN BLOCK", "ZERO VALUE", diff --git a/compiler/src/checker.c b/compiler/src/checker.c index ca4ceb89..abafdefe 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -2251,6 +2251,7 @@ CheckStatus check_expression(AstTyped** pexpr) { case Ast_Kind_Switch_Case: break; case Ast_Kind_Foreign_Block: break; case Ast_Kind_Zero_Value: break; + case Ast_Kind_Capture_Local: break; default: retval = Check_Error; @@ -2419,6 +2420,21 @@ CheckStatus check_directive_export_name(AstDirectiveExportName *ename) { return Check_Success; } +CheckStatus check_capture_block(AstCaptureBlock *block) { + block->total_size_in_bytes = 0; + + bh_arr_each(AstCaptureLocal *, capture, block->captures) { + CHECK(expression, (AstTyped **) capture); + + assert((*capture)->type); + + (*capture)->offset = block->total_size_in_bytes; + block->total_size_in_bytes += type_size_of((*capture)->type); + } + + return Check_Success; +} + CheckStatus check_statement(AstNode** pstmt) { AstNode* stmt = *pstmt; @@ -2549,7 +2565,15 @@ CheckStatus check_function(AstFunction* func) { if (for_node_stack) bh_arr_clear(for_node_stack); if (func->body) { - CheckStatus status = check_block(func->body); + CheckStatus status = Check_Success; + if (func->captures) { + status = check_capture_block(func->captures); + } + + if (status == Check_Success) { + status = check_block(func->body); + } + if (status == Check_Error && func->generated_from && context.cycle_detected == 0) ERROR(func->generated_from->pos, "Error in polymorphic procedure generated from this location."); diff --git a/compiler/src/clone.c b/compiler/src/clone.c index 4070c0b6..d21f0e18 100644 --- a/compiler/src/clone.c +++ b/compiler/src/clone.c @@ -117,6 +117,8 @@ static inline i32 ast_kind_to_size(AstNode* node) { case Ast_Kind_Directive_First: return sizeof(AstDirectiveFirst); case Ast_Kind_Directive_Export_Name: return sizeof(AstDirectiveExportName); case Ast_Kind_Import: return sizeof(AstImport); + case Ast_Kind_Capture_Block: return sizeof(AstCaptureBlock); + case Ast_Kind_Capture_Local: return sizeof(AstCaptureLocal); case Ast_Kind_Count: return 0; } @@ -594,6 +596,25 @@ AstNode* ast_clone(bh_allocator a, void* n) { case Ast_Kind_Directive_Export_Name: C(AstDirectiveExportName, func); break; + + case Ast_Kind_Capture_Block: { + AstCaptureBlock* cd = (AstCaptureBlock *) nn; + AstCaptureBlock* cs = (AstCaptureBlock *) node; + + cd->captures = NULL; + bh_arr_new(global_heap_allocator, cd->captures, bh_arr_length(cs->captures)); + + bh_arr_each(AstCaptureLocal *, expr, cs->captures) { + bh_arr_push(cd->captures, (AstCaptureLocal *) ast_clone(a, (AstNode *) *expr)); + } + + cd->is_legal = 0; + break; + } + + case Ast_Kind_Capture_Local: + C(AstCaptureLocal, type_node); + break; } clone_depth--; diff --git a/compiler/src/parser.c b/compiler/src/parser.c index 423f0256..7aa9c6b1 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -524,6 +524,7 @@ static AstTyped* parse_factor(OnyxParser* parser) { case Token_Type_Symbol: { if (parse_possible_quick_function_definition(parser, &retval)) { + retval->flags |= Ast_Flag_Function_Is_Lambda; ENTITY_SUBMIT(retval); break; } @@ -1708,6 +1709,34 @@ static AstNode* parse_statement(OnyxParser* parser) { break; } + if (parse_possible_directive(parser, "capture")) { + // :LinearTokenDependent + AstCaptureBlock *captures = make_node(AstCaptureBlock, Ast_Kind_Capture_Block); + captures->token = parser->curr - 2; + + bh_arr_new(global_heap_allocator, captures->captures, 2); + + expect_token(parser, '{'); + while (!consume_token_if_next(parser, '}')) { + if (parser->hit_unexpected_token) break; + + AstCaptureLocal *capture = make_node(AstCaptureLocal, Ast_Kind_Capture_Local); + capture->token = expect_token(parser, Token_Type_Symbol); + + expect_token(parser, ':'); + capture->type_node = parse_type(parser); + + bh_arr_push(captures->captures, capture); + + if (peek_token(0)->type != '}') + expect_token(parser, ','); + } + + retval = (AstNode *) captures; + needs_semicolon = 0; + break; + } + if (next_tokens_are(parser, 2, '#', Token_Type_Symbol)) { retval = (AstNode *) parse_factor(parser); break; diff --git a/compiler/src/symres.c b/compiler/src/symres.c index 0920ec77..5cc9cab2 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -837,6 +837,23 @@ static SymresStatus symres_directive_insert(AstDirectiveInsert* insert) { return Symres_Success; } +static SymresStatus symres_capture_block(AstCaptureBlock *block) { + if (!block->is_legal) { + onyx_report_error(block->token->pos, Error_Critical, "#capture block is not allowed here."); + return Symres_Error; + } + + bh_arr_each(AstCaptureLocal *, capture, block->captures) { + SYMRES(type, &(*capture)->type_node); + } + + bh_arr_each(AstCaptureLocal *, capture, block->captures) { + symbol_introduce(current_scope, (*capture)->token, (AstNode *) *capture); + } + + return Symres_Success; +} + static SymresStatus symres_statement(AstNode** stmt, b32 *remove) { if (remove) *remove = 0; @@ -864,6 +881,12 @@ static SymresStatus symres_statement(AstNode** stmt, b32 *remove) { if (remove) *remove = 1; break; + case Ast_Kind_Capture_Block: + SYMRES(capture_block, (AstCaptureBlock *) *stmt); + + if (remove) *remove = 1; + break; + default: SYMRES(expression, (AstTyped **) stmt); break; } @@ -1091,6 +1114,14 @@ SymresStatus symres_function(AstFunction* func) { func->flags |= Ast_Flag_Has_Been_Symres; } + if (func->body && func->body->body && func->body->body->kind == Ast_Kind_Capture_Block) { + func->captures = (void *) func->body->body; + + if (func->flags & Ast_Flag_Function_Is_Lambda) { + ((AstCaptureBlock *) func->body->body)->is_legal = 1; + } + } + SYMRES(block, func->body); scope_leave(); -- 2.25.1