NODE(DirectiveInsert) \
NODE(Macro) \
\
+ NODE(CaptureBlock) \
+ NODE(CaptureLocal) \
+ \
NODE(ForeignBlock) \
\
NODE(Package) \
Ast_Kind_Macro,
Ast_Kind_Do_Block,
+ Ast_Kind_Capture_Block,
+ Ast_Kind_Capture_Local,
+
Ast_Kind_Foreign_Block,
Ast_Kind_Zero_Value,
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;
"MACRO",
"DO BLOCK",
+ "CAPTURE BLOCK",
+ "CAPTURE LOCAL",
+
"FOREIGN BLOCK",
"ZERO VALUE",
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;
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;
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.");
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;
}
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--;
case Token_Type_Symbol: {
if (parse_possible_quick_function_definition(parser, &retval)) {
+ retval->flags |= Ast_Flag_Function_Is_Lambda;
ENTITY_SUBMIT(retval);
break;
}
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;
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;
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;
}
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();