Refactor: Analyze node purity and recursion
The Analyzer has been refactored to decorate `TypedNode`s with their purity and recursion status. This involves creating a new `AnalyzedNode` type and a `NodeMetrics` struct to hold this information. The `Analyzer` now returns an `AnalyzedNode` instead of a separate `Analysis` struct. This change lays the groundwork for future optimizations and analysis passes.
This commit is contained in:
+20
-117
@@ -1,4 +1,4 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, BoundKind, TypedNode};
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind};
|
||||
use crate::ast::compiler::tco::ExecNode;
|
||||
use crate::ast::nodes::Node;
|
||||
use crate::ast::types::{Object, Value};
|
||||
@@ -8,8 +8,11 @@ use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Closure {
|
||||
pub parameter_node: Rc<TypedNode>,
|
||||
pub function_node: Rc<TypedNode>,
|
||||
/// The analyzed parameter pattern.
|
||||
pub parameter_node: Rc<AnalyzedNode>,
|
||||
/// 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>,
|
||||
@@ -18,8 +21,8 @@ pub struct Closure {
|
||||
impl Closure {
|
||||
#[inline]
|
||||
pub fn new(
|
||||
params: Rc<TypedNode>,
|
||||
body: Rc<TypedNode>,
|
||||
params: Rc<AnalyzedNode>,
|
||||
body: Rc<AnalyzedNode>,
|
||||
exec: Rc<ExecNode>,
|
||||
upvalues: Vec<Rc<RefCell<Value>>>,
|
||||
positional_count: Option<u32>,
|
||||
@@ -85,11 +88,14 @@ impl VMObserver for TracingObserver {
|
||||
const ACTIVE: bool = true;
|
||||
fn before_eval(&mut self, _vm: &VM, node: &ExecNode) {
|
||||
let pad = self.pad();
|
||||
let metrics = &node.ty.original.ty;
|
||||
self.logs.push(format!(
|
||||
"{}{} [{}]: {{",
|
||||
"{}{} [{} | P:{:?}{}]: {{",
|
||||
pad,
|
||||
node.kind.display_name(),
|
||||
node.ty.ty
|
||||
node.ty.ty,
|
||||
metrics.purity,
|
||||
if metrics.is_recursive { " | REC" } else { "" }
|
||||
));
|
||||
self.indent += 1;
|
||||
}
|
||||
@@ -166,8 +172,13 @@ macro_rules! dispatch_eval {
|
||||
BoundKind::Lambda { params, upvalues, body, positional_count } => {
|
||||
let mut captured = Vec::with_capacity(upvalues.len());
|
||||
for addr in upvalues { captured.push($self.capture_upvalue(*addr)?); }
|
||||
// CRITICAL FIX: body.clone() is O(1), body.as_ref().clone() was O(N)!
|
||||
let closure = Closure::new(params.ty.original.clone(), body.ty.original.clone(), body.clone(), captured, *positional_count);
|
||||
let closure = Closure::new(
|
||||
params.ty.original.clone(),
|
||||
body.ty.original.clone(),
|
||||
body.clone(),
|
||||
captured,
|
||||
*positional_count
|
||||
);
|
||||
Ok(Value::Object(Rc::new(closure)))
|
||||
},
|
||||
BoundKind::Call { callee, args } => {
|
||||
@@ -361,7 +372,6 @@ impl VM {
|
||||
dispatch_eval!(self, node, eval)
|
||||
}
|
||||
|
||||
/// Resolves potential tail call requests iteratively until a final value is reached.
|
||||
pub fn resolve_tail_calls(&mut self, mut result: Value) -> Value {
|
||||
while let Value::TailCallRequest(payload) = result {
|
||||
let (next_obj, next_args) = *payload;
|
||||
@@ -622,110 +632,3 @@ impl VM {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::compiler::tco::TCO;
|
||||
use crate::ast::nodes::{Node, Symbol};
|
||||
use crate::ast::types::{NodeIdentity, SourceLocation, StaticType};
|
||||
|
||||
fn make_dummy_identity() -> Rc<NodeIdentity> {
|
||||
Rc::new(NodeIdentity {
|
||||
location: SourceLocation { line: 0, col: 0 },
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_capture_boxing_modification() {
|
||||
let id = make_dummy_identity();
|
||||
let lambda_body = Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Void,
|
||||
kind: BoundKind::Set {
|
||||
addr: Address::Upvalue(0),
|
||||
value: Box::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Int,
|
||||
kind: BoundKind::Constant(Value::Int(20)),
|
||||
}),
|
||||
},
|
||||
};
|
||||
let root = Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Int,
|
||||
kind: BoundKind::Block {
|
||||
exprs: vec![
|
||||
Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Int,
|
||||
kind: BoundKind::Set {
|
||||
addr: Address::Local(0),
|
||||
value: Box::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Int,
|
||||
kind: BoundKind::Constant(Value::Int(10)),
|
||||
}),
|
||||
},
|
||||
},
|
||||
Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Any,
|
||||
kind: BoundKind::Set {
|
||||
addr: Address::Local(1),
|
||||
value: Box::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Any,
|
||||
kind: BoundKind::Lambda {
|
||||
params: Rc::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Tuple(vec![]),
|
||||
kind: BoundKind::Tuple { elements: vec![] },
|
||||
}),
|
||||
upvalues: vec![Address::Local(0)],
|
||||
body: Rc::new(lambda_body),
|
||||
positional_count: Some(0),
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Void,
|
||||
kind: BoundKind::Call {
|
||||
callee: Box::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Any,
|
||||
kind: BoundKind::Get {
|
||||
addr: Address::Local(1),
|
||||
name: Symbol::from("f"),
|
||||
},
|
||||
}),
|
||||
args: Box::new(Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Tuple(vec![]),
|
||||
kind: BoundKind::Tuple { elements: vec![] },
|
||||
}),
|
||||
},
|
||||
},
|
||||
Node {
|
||||
identity: id.clone(),
|
||||
ty: StaticType::Int,
|
||||
kind: BoundKind::Get {
|
||||
addr: Address::Local(0),
|
||||
name: Symbol::from("x"),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
let globals = Rc::new(RefCell::new(Vec::new()));
|
||||
let mut vm = VM::new(globals);
|
||||
let exec_root = TCO::optimize(root);
|
||||
let result = vm.run(&exec_root);
|
||||
match result {
|
||||
Ok(Value::Int(val)) => assert_eq!(val, 20),
|
||||
_ => panic!("Expected Int(20)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user