Introduce closure AST node

The `Closure` struct has been moved from `ast/vm.rs` to a new module
`ast/closure.rs`. This improves the organization of the AST nodes. The
`Closure` struct represents a compiled function body along with its
captured upvalues, which is a key feature for Myc Script.
This commit is contained in:
2026-03-22 19:37:04 +01:00
parent 37d7ed3e75
commit 6c37b0c64f
7 changed files with 68 additions and 53 deletions
+60
View File
@@ -0,0 +1,60 @@
use crate::ast::nodes::{AnalyzedNode, ExecNode};
use crate::ast::types::{Object, Value};
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
/// A compiled closure: a function body together with its captured upvalues.
///
/// Closures are the primary callable value in Myc Script. They are created by
/// `fn`-expressions and stored as `Value::Closure`.
#[derive(Debug, Clone)]
pub struct Closure {
/// The executable parameter pattern.
pub parameter_node: Rc<ExecNode>,
/// The analyzed body (before TCO transformation).
pub function_node: Rc<AnalyzedNode>,
/// The executable node (after TCO transformation).
pub exec_node: Rc<ExecNode>,
/// Captured variables from enclosing scopes.
pub upvalues: Vec<Rc<RefCell<Value>>>,
/// Number of positional parameters, if known statically.
pub positional_count: Option<u32>,
/// Number of stack slots required for this closure (set during compilation).
pub stack_size: u32,
}
impl Closure {
#[inline]
pub fn new(
params: Rc<ExecNode>,
body: Rc<AnalyzedNode>,
exec: Rc<ExecNode>,
upvalues: Vec<Rc<RefCell<Value>>>,
positional_count: Option<u32>,
stack_size: u32,
) -> Self {
Self {
parameter_node: params,
function_node: body,
exec_node: exec,
upvalues,
positional_count,
stack_size,
}
}
}
impl Object for Closure {
fn type_name(&self) -> &'static str {
"closure"
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ use crate::ast::nodes::{
IdentifierBinding, LambdaBinding, Node, NodeKind, UpvalueIdx, VirtualId,
};
use crate::ast::types::{Purity, Value};
use crate::ast::vm::Closure;
use crate::ast::closure::Closure;
use std::cell::RefCell;
use std::rc::Rc;
+1 -1
View File
@@ -2,7 +2,7 @@ use crate::ast::nodes::{
Address, AnalyzedNode, IdentifierBinding, NodeKind, VirtualId,
};
use crate::ast::types::{Purity, Value};
use crate::ast::vm::Closure;
use crate::ast::closure::Closure;
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;
+1 -1
View File
@@ -3,7 +3,7 @@ use crate::ast::nodes::{
NodeKind, VirtualId,
};
use crate::ast::types::{Identity, Value};
use crate::ast::vm::Closure;
use crate::ast::closure::Closure;
use std::collections::HashSet;
// --- PathTracker ---
+2 -1
View File
@@ -3,7 +3,8 @@ use crate::ast::compiler::binder::{Binder, CompilerScope, LocalInfo};
use crate::ast::compiler::{CapturePass, TypeChecker, TypedNode};
use crate::ast::nodes::{AnalyzedPhase, Symbol, SyntaxKind, SyntaxNode};
use crate::ast::parser::Parser;
use crate::ast::vm::{Closure, TracingObserver, VM};
use crate::ast::closure::Closure;
use crate::ast::vm::{TracingObserver, VM};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
+1
View File
@@ -1,3 +1,4 @@
pub mod closure;
pub mod compiler;
pub mod diagnostics;
pub mod environment;
+2 -49
View File
@@ -1,58 +1,11 @@
use crate::ast::nodes::{Address, AnalyzedNode, ExecNode, IdentifierBinding, NodeKind, StackOffset};
use crate::ast::closure::Closure;
use crate::ast::nodes::{Address, ExecNode, IdentifierBinding, NodeKind, StackOffset};
use crate::ast::rtl::series::{RecordSeries, SeriesView};
use crate::ast::rtl::streams::{build_map_stream, build_pipeline_node, StreamNode};
use crate::ast::types::{Object, PipeFn, Value};
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct Closure {
/// The executable parameter pattern.
pub parameter_node: Rc<ExecNode>,
/// The analyzed body (before TCO).
pub function_node: Rc<AnalyzedNode>,
/// The executable node (after TCO).
pub exec_node: Rc<ExecNode>,
pub upvalues: Vec<Rc<RefCell<Value>>>,
pub positional_count: Option<u32>,
/// The number of stack slots required for this closure (calculated late).
pub stack_size: u32,
}
impl Closure {
#[inline]
pub fn new(
params: Rc<ExecNode>,
body: Rc<AnalyzedNode>,
exec: Rc<ExecNode>,
upvalues: Vec<Rc<RefCell<Value>>>,
positional_count: Option<u32>,
stack_size: u32,
) -> Self {
Self {
parameter_node: params,
function_node: body,
exec_node: exec,
upvalues,
positional_count,
stack_size,
}
}
}
impl Object for Closure {
fn type_name(&self) -> &'static str {
"closure"
}
fn as_any(&self) -> &dyn Any {
self
}
fn into_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}
#[derive(Debug)]
struct CallFrame {
stack_base: usize,