From bf82cbd2a7d4e234313e253cb6f7dd351b2c5c5a Mon Sep 17 00:00:00 2001 From: Mel Date: Tue, 26 May 2026 04:15:12 +0200 Subject: Locate and pass through captured locals to stateful closures Signed-off-by: Mel --- boot/ir.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 18 deletions(-) (limited to 'boot/ir.c') diff --git a/boot/ir.c b/boot/ir.c index 164d9a4..f86d63f 100644 --- a/boot/ir.c +++ b/boot/ir.c @@ -137,6 +137,13 @@ struct Param struct Type_Ref type; }; +// one captured local in a closing function. +struct Capture +{ + struct String name; + struct Type_Ref type; // referenced by capture +}; + // minimal lowered statement set. enum Statement_Kind { @@ -239,7 +246,7 @@ enum Expression_Kind EXPRESSION_FLOAT_LITERAL, EXPRESSION_STRING_LITERAL, EXPRESSION_BOOLEAN_LITERAL, - EXPRESSION_NAME, + EXPRESSION_REFERENCE, EXPRESSION_UNARY_OPERATION, EXPRESSION_BINARY_OPERATION, EXPRESSION_SIZEOF_OPERATION, @@ -249,7 +256,6 @@ enum Expression_Kind EXPRESSION_CAST, EXPRESSION_CONSTRUCT, EXPRESSION_INCREMENT_DECREMENT, - EXPRESSION_FUNCTION_REF, }; struct Expression_Integer_Literal @@ -272,11 +278,56 @@ struct Expression_Bool_Literal bool value; }; -struct Expression_Name +enum Reference_Kind +{ + REFERENCE_NONE, + REFERENCE_NAME, + REFERENCE_FUNCTION, + REFERENCE_CAPTURE, +}; + +// a simple, by-name reference to some language object, +// requiring no special treatment. +struct Reference_Name { struct String name; }; +// a reference to a function, either a named, thin one, +// or a fat, synthetic one. +// when a reference points to a thin named function (basically any +// normal function that's not a closure) and is not a simple, direct call, +// we will have to call out to a wrapping thunk, to match the fat +// calling convention of closures. +struct Reference_Function +{ + Function_Id function_id; + // matching closure type for the function's signature. + Type_Id closure_type_id; +}; + +// a reference to a captured local from another, enclosing +// scope within a closure function. +// will be gathered from the closure state. +struct Reference_Capture +{ + struct String name; +}; + +union Reference_Value +{ + struct Reference_Name name; + struct Reference_Function function; + struct Reference_Capture capture; +}; + +// a reference to some other language object. +struct Expression_Reference +{ + enum Reference_Kind kind; + union Reference_Value value; +}; + struct Expression_Unary_Operator { enum Unary_Operation operation; @@ -356,21 +407,13 @@ struct Expression_Increment_Decrement struct Expression* subject; }; -// reference to a known catskill function in a value context. -struct Expression_Function_Ref -{ - Function_Id function_id; - // matching synthetic closure type for the function's signature. - Type_Id closure_type_id; -}; - union Expression_Value { struct Expression_Integer_Literal integer_literal; struct Expression_Float_Literal float_literal; struct Expression_String_Literal string_literal; struct Expression_Bool_Literal bool_literal; - struct Expression_Name name; + struct Expression_Reference reference; struct Expression_Unary_Operator unary_operator; struct Expression_Binary_Operator binary_operator; struct Expression_Sizeof_Operator sizeof_operator; @@ -380,7 +423,6 @@ union Expression_Value struct Expression_Cast cast; struct Expression_Construct construct; struct Expression_Increment_Decrement increment_decrement; - struct Expression_Function_Ref function_ref; }; struct Expression @@ -420,6 +462,12 @@ struct Function // synthesized lazily on first reference in value context, or 0. Type_Id closure_type_id; + // locals captured from enclosing function scopes, filled during body + // lowering. (only valid for stateful lambdas) + Array(struct Capture) captures; + // synthetic structure containing all captured locals. (only stateful lambdas) + Type_Id capture_state_type_id; + // tree-side header which produced this function node. // required for synthesizing the closure type after function is lowered. struct Tree_Function_Header* ast_header; @@ -428,6 +476,11 @@ struct Function // to collect all top-declarations. struct Tree_Block* ast_body; struct Block* body; + + // has this function been processed to completion already? + // synthetic lambdas get their bodies lowered directly when encountered, + // unlike other function declarations, to get access to the current local stack. + bool completed; }; struct Type_Hash_To_Id @@ -561,6 +614,7 @@ function_new(Function_Id id, struct String name) *function = (struct Function){ .id = id, .name = name, + .captures = array_new(struct Capture, 4), }; return function; } @@ -636,8 +690,9 @@ struct Expression* ir_make_name(struct String name, struct Span span) { union Expression_Value v = { 0 }; - v.name.name = name; - return expression_new(EXPRESSION_NAME, v, span); + v.reference.kind = REFERENCE_NAME; + v.reference.value.name.name = name; + return expression_new(EXPRESSION_REFERENCE, v, span); } struct Expression* @@ -728,13 +783,23 @@ ir_make_increment_decrement( return expression_new(EXPRESSION_INCREMENT_DECREMENT, v, span); } +struct Expression* +ir_make_capture_ref(struct String name, struct Span span) +{ + union Expression_Value v = { 0 }; + v.reference.kind = REFERENCE_CAPTURE; + v.reference.value.capture.name = name; + return expression_new(EXPRESSION_REFERENCE, v, span); +} + struct Expression* ir_make_function_ref(Function_Id function_id, Type_Id closure_type_id, struct Span span) { union Expression_Value v = { 0 }; - v.function_ref.function_id = function_id; - v.function_ref.closure_type_id = closure_type_id; - return expression_new(EXPRESSION_FUNCTION_REF, v, span); + v.reference.kind = REFERENCE_FUNCTION; + v.reference.value.function.function_id = function_id; + v.reference.value.function.closure_type_id = closure_type_id; + return expression_new(EXPRESSION_REFERENCE, v, span); } struct Type_Ref -- cgit 1.4.1