diff --git a/src/ast/closure.rs b/src/ast/closure.rs new file mode 100644 index 0000000..56fa69e --- /dev/null +++ b/src/ast/closure.rs @@ -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, + /// The analyzed body (before TCO transformation). + pub function_node: Rc, + /// The executable node (after TCO transformation). + pub exec_node: Rc, + /// Captured variables from enclosing scopes. + pub upvalues: Vec>>, + /// Number of positional parameters, if known statically. + pub positional_count: Option, + /// Number of stack slots required for this closure (set during compilation). + pub stack_size: u32, +} + +impl Closure { + #[inline] + pub fn new( + params: Rc, + body: Rc, + exec: Rc, + upvalues: Vec>>, + positional_count: Option, + 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) -> Rc { + self + } +} diff --git a/src/ast/compiler/optimizer/engine.rs b/src/ast/compiler/optimizer/engine.rs index 99d6990..51e9398 100644 --- a/src/ast/compiler/optimizer/engine.rs +++ b/src/ast/compiler/optimizer/engine.rs @@ -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; diff --git a/src/ast/compiler/optimizer/inliner.rs b/src/ast/compiler/optimizer/inliner.rs index 7531512..71e4694 100644 --- a/src/ast/compiler/optimizer/inliner.rs +++ b/src/ast/compiler/optimizer/inliner.rs @@ -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; diff --git a/src/ast/compiler/optimizer/utils.rs b/src/ast/compiler/optimizer/utils.rs index 33c4396..833f420 100644 --- a/src/ast/compiler/optimizer/utils.rs +++ b/src/ast/compiler/optimizer/utils.rs @@ -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 --- diff --git a/src/ast/environment.rs b/src/ast/environment.rs index a5afb43..1a0cc2c 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -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}; diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 2bfd8ac..2307e48 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,3 +1,4 @@ +pub mod closure; pub mod compiler; pub mod diagnostics; pub mod environment; diff --git a/src/ast/vm.rs b/src/ast/vm.rs index 42c07c3..ec20d4d 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -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, - /// The analyzed body (before TCO). - pub function_node: Rc, - /// The executable node (after TCO). - pub exec_node: Rc, - pub upvalues: Vec>>, - pub positional_count: Option, - /// The number of stack slots required for this closure (calculated late). - pub stack_size: u32, -} - -impl Closure { - #[inline] - pub fn new( - params: Rc, - body: Rc, - exec: Rc, - upvalues: Vec>>, - positional_count: Option, - 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) -> Rc { - self - } -} - #[derive(Debug)] struct CallFrame { stack_base: usize,