about summary refs log tree commit diff
path: root/boot/ir.c
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-26 04:15:12 +0200
committerMel <mel@rnrd.eu>2026-05-26 04:15:12 +0200
commitbf82cbd2a7d4e234313e253cb6f7dd351b2c5c5a (patch)
tree42dcf198deee1dae3c9b3586dc37e6dd23938244 /boot/ir.c
parent900b412b052a0f745f0853d6703e4bafbb0a3ce5 (diff)
downloadcatskill-bf82cbd2a7d4e234313e253cb6f7dd351b2c5c5a.tar.zst
catskill-bf82cbd2a7d4e234313e253cb6f7dd351b2c5c5a.zip
Locate and pass through captured locals to stateful closures
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/ir.c')
-rw-r--r--boot/ir.c101
1 files changed, 83 insertions, 18 deletions
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*
@@ -729,12 +784,22 @@ ir_make_increment_decrement(
 }
 
 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