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}; use std::any::Any; use std::cell::RefCell; use std::rc::Rc; #[derive(Debug, Clone)] pub struct Closure { /// The analyzed 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, } impl Closure { #[inline] pub fn new( params: Rc, body: Rc, exec: Rc, upvalues: Vec>>, positional_count: Option, ) -> Self { Self { parameter_node: params, function_node: body, exec_node: exec, upvalues, positional_count, } } } impl Object for Closure { fn type_name(&self) -> &'static str { "closure" } fn as_any(&self) -> &dyn Any { self } } #[derive(Debug)] struct CallFrame { stack_base: usize, closure: Option>, } pub trait VMObserver { const ACTIVE: bool = false; fn before_eval(&mut self, _vm: &VM, _node: &ExecNode) {} fn after_eval(&mut self, _vm: &VM, _node: &ExecNode, _res: &Result) {} } pub struct NoOpObserver; impl VMObserver for NoOpObserver {} pub struct TracingObserver { pub logs: Vec, indent: usize, } impl TracingObserver { pub fn new() -> Self { Self { logs: Vec::new(), indent: 0, } } fn pad(&self) -> String { "| ".repeat(self.indent) } } impl Default for TracingObserver { fn default() -> Self { Self::new() } } 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, metrics.purity, if metrics.is_recursive { " | REC" } else { "" } )); self.indent += 1; } fn after_eval(&mut self, vm: &VM, node: &ExecNode, res: &Result) { self.indent = self.indent.saturating_sub(1); let pad = self.pad(); match &node.kind { BoundKind::Define { .. } | BoundKind::Set { .. } => { let s_pad = format!("{}| ", pad); self.logs.push(format!("{}--- Scope Status ---", s_pad)); self.logs.push(format!( "{}Stack (top 5): {:?}", s_pad, vm.stack.iter().rev().take(5).collect::>() )); } _ => {} } let res_str = match res { Ok(v) => format!("{}", v), Err(e) => format!("ERROR: {}", e), }; self.logs.push(format!("{}}} -> {}", pad, res_str)); } } pub struct VM { stack: Vec, globals: Rc>>, frames: Vec, } impl VM { pub fn new(globals: Rc>>) -> Self { Self { stack: Vec::new(), globals, frames: Vec::new(), } } pub fn run(&mut self, root: &ExecNode) -> Result { self.stack.clear(); self.frames.clear(); self.frames.push(CallFrame { stack_base: 0, closure: None, }); let mut result = self.eval(root); self.frames.pop(); loop { match result { Ok(Value::TailCallRequest(payload)) => { let (next_obj, next_args) = *payload; if let Some(closure) = next_obj.as_any().downcast_ref::() { self.stack.clear(); self.frames.push(CallFrame { stack_base: 0, closure: Some(Rc::new(closure.clone())), }); if let Some(count) = closure.positional_count && next_args.len() == count as usize { self.stack.extend(next_args); } else { self.unpack(&closure.parameter_node, &next_args, &mut 0)?; } result = self.eval(&closure.exec_node); self.frames.pop(); } else { return Err(format!( "Tail call target is not a closure: {}", next_obj.type_name() )); } } _ => return result, } } } pub fn run_with_args(&mut self, closure: &Closure, args: Vec) -> Result { self.stack.clear(); self.frames.clear(); self.frames.push(CallFrame { stack_base: 0, closure: Some(Rc::new(closure.clone())), }); if let Some(count) = closure.positional_count && args.len() == count as usize { self.stack.extend(args); } else { self.unpack(&closure.parameter_node, &args, &mut 0)?; } self.eval(&closure.exec_node) } pub fn run_with_args_observed( &mut self, observer: &mut O, closure: &Closure, args: Vec, ) -> Result { self.stack.clear(); self.frames.clear(); self.frames.push(CallFrame { stack_base: 0, closure: Some(Rc::new(closure.clone())), }); if let Some(count) = closure.positional_count && args.len() == count as usize { self.stack.extend(args); } else { self.unpack(&closure.parameter_node, &args, &mut 0)?; } self.eval_observed(observer, &closure.exec_node) } pub fn run_with_observer( &mut self, observer: &mut O, root: &ExecNode, ) -> Result { self.stack.clear(); self.frames.clear(); self.frames.push(CallFrame { stack_base: 0, closure: None, }); let result = self.eval_observed(observer, root); self.frames.pop(); result } #[inline(always)] fn eval(&mut self, node: &ExecNode) -> Result { self.eval_internal(&mut NoOpObserver, node) } fn eval_observed( &mut self, observer: &mut O, node: &ExecNode, ) -> Result { self.eval_internal(observer, node) } #[inline(always)] fn eval_internal( &mut self, obs: &mut O, node: &ExecNode, ) -> Result { if O::ACTIVE { obs.before_eval(self, node); let result = self.eval_core(obs, node); obs.after_eval(self, node, &result); result } else { self.eval_core(obs, node) } } #[inline(always)] fn eval_core(&mut self, obs: &mut O, node: &ExecNode) -> Result { match &node.kind { BoundKind::Nop => Ok(Value::Void), BoundKind::Constant(v) => Ok(v.clone()), BoundKind::Define { addr, value, captured_by, .. } => { let val = self.eval_internal(obs, value)?; let final_val = if !captured_by.is_empty() && matches!(addr, Address::Local(_)) { Value::Cell(Rc::new(RefCell::new(val))) } else { val }; self.set_value(*addr, final_val.clone())?; Ok(final_val) } BoundKind::Destructure { pattern, value } => { let val = self.eval_internal(obs, value)?; let mut offset = 0; // Destructuring works on tuples/vectors, or single values wrapped in a slice if let Some(vals) = val.as_slice() { self.unpack(pattern, vals, &mut offset)?; } else { self.unpack(pattern, std::slice::from_ref(&val), &mut offset)?; } Ok(val) } BoundKind::Get { addr, .. } => self.get_value(*addr), BoundKind::Set { addr, value } => { let val = self.eval_internal(obs, value)?; self.set_value(*addr, val.clone())?; Ok(val) } BoundKind::If { cond, then_br, else_br, } => { let c = self.eval_internal(obs, cond)?; if c.is_truthy() { self.eval_internal(obs, then_br) } else if let Some(e) = else_br { self.eval_internal(obs, e) } else { Ok(Value::Void) } } BoundKind::Block { exprs } => { let mut last = Value::Void; for e in exprs { last = self.eval_internal(obs, e)?; } Ok(last) } 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)?); } 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 } => { let mut func_val = self.eval_internal(obs, callee)?; let mut arg_vals = match &args.kind { BoundKind::Tuple { elements } => { let mut vals = Vec::with_capacity(elements.len()); let mut is_complex = false; for e in elements { if matches!(e.kind, BoundKind::Tuple { .. }) { is_complex = true; break; } vals.push(self.eval_internal(obs, e)?); } if is_complex { self.prepare_args_internal(obs, args)? } else { vals } } _ => self.prepare_args_internal(obs, args)?, }; if node.ty.is_tail { match func_val { Value::Object(obj) => { return Ok(Value::TailCallRequest(Box::new((obj, arg_vals)))); } Value::Function(f) => return Ok((f.func)(arg_vals)), _ => { return Err(format!( "Tail call target is not a function: {}", func_val )); } } } loop { match func_val { Value::Function(f) => break Ok((f.func)(arg_vals)), Value::Object(obj) => { if let Some(closure) = obj.as_any().downcast_ref::() { let old_stack_top = self.stack.len(); let closure_rc = Rc::new(closure.clone()); self.frames.push(CallFrame { stack_base: old_stack_top, closure: Some(closure_rc.clone()), }); if let Some(count) = closure.positional_count && arg_vals.len() == count as usize { self.stack.extend(arg_vals); } else { // Map each parameter pattern to the provided arguments if let BoundKind::Tuple { elements } = &closure.parameter_node.kind { let mut offset = 0; for el in elements { self.unpack(el, &arg_vals, &mut offset)?; } } else { self.unpack(&closure.parameter_node, &arg_vals, &mut 0)?; } } let result = self.eval_internal(obs, &closure.exec_node); self.frames.pop(); self.stack.truncate(old_stack_top); match result { Ok(Value::TailCallRequest(payload)) => { let (next_obj, next_args) = *payload; func_val = Value::Object(next_obj); arg_vals = next_args; continue; } res => break res, } } else { break Err(format!("Object is not a closure: {}", obj.type_name())); } } _ => break Err(format!("Attempt to call non-function: {}", func_val)), } } } BoundKind::Again { args } => { let arg_vals = match &args.kind { BoundKind::Tuple { elements } => { let mut vals = Vec::with_capacity(elements.len()); let mut is_complex = false; for e in elements { if matches!(e.kind, BoundKind::Tuple { .. }) { is_complex = true; break; } vals.push(self.eval_internal(obs, e)?); } if is_complex { self.prepare_args_internal(obs, args)? } else { vals } } _ => self.prepare_args_internal(obs, args)?, }; let frame = self.frames.last().ok_or("No call frame for 'again'")?; if let Some(closure) = &frame.closure { Ok(Value::TailCallRequest(Box::new(( Rc::new(closure.as_ref().clone()) as Rc, arg_vals, )))) } else { Err("'again' called outside of a closure".to_string()) } } BoundKind::Tuple { elements } => { let mut vals = Vec::with_capacity(elements.len()); for e in elements { vals.push(self.eval_internal(obs, e)?); } Ok(Value::make_tuple(vals)) } BoundKind::Record { fields } => { let mut keys = Vec::with_capacity(fields.len()); let mut values = Vec::with_capacity(fields.len()); for (k, v) in fields { let key = self.eval_internal(obs, k)?; let val = self.eval_internal(obs, v)?; if let Value::Keyword(kw) = key { keys.push(kw); values.push(val); } else { return Err(format!("Record key must be keyword, got {}", key)); } } Ok(Value::make_record(keys, values)) } BoundKind::Expansion { bound_expanded, .. } => self.eval_internal(obs, bound_expanded), BoundKind::Extension(ext) => Err(format!( "Execution of extension '{}' not implemented yet", ext.display_name() )), } } pub fn resolve_tail_calls(&mut self, mut result: Value) -> Value { while let Value::TailCallRequest(payload) = result { let (next_obj, next_args) = *payload; if let Some(closure) = next_obj.as_any().downcast_ref::() { result = match self.run_with_args(closure, next_args) { Ok(v) => v, Err(e) => panic!("Myc Runtime Error (TailCall): {}", e), }; } else { panic!( "Tail call target is not a closure: {}", next_obj.type_name() ); } } result } fn capture_upvalue(&mut self, addr: Address) -> Result>, String> { match addr { Address::Local(idx) => { let frame = self.frames.last().ok_or("No call frame")?; let abs_index = frame.stack_base + (idx as usize); if abs_index < self.stack.len() { if let Value::Cell(cell) = &self.stack[abs_index] { Ok(cell.clone()) } else { let val = self.stack[abs_index].clone(); let cell = Rc::new(RefCell::new(val)); self.stack[abs_index] = Value::Cell(cell.clone()); Ok(cell) } } else { Err(format!("Stack underflow capture local {}", idx)) } } Address::Upvalue(idx) => { let frame = self.frames.last().ok_or("No call frame")?; if let Some(closure) = &frame.closure { let idx = idx as usize; if idx < closure.upvalues.len() { Ok(closure.upvalues[idx].clone()) } else { Err(format!("Upvalue access out of bounds capture {}", idx)) } } else { Err("Current frame has no closure".to_string()) } } Address::Global(_) => Err("Cannot capture global directly".to_string()), } } fn get_value(&self, addr: Address) -> Result { match addr { Address::Local(idx) => { let frame = self.frames.last().ok_or("No call frame")?; let abs_index = frame.stack_base + (idx as usize); if abs_index < self.stack.len() { match &self.stack[abs_index] { Value::Cell(cell) => Ok(cell.borrow().clone()), val => Ok(val.clone()), } } else { Err(format!("Stack underflow access local {}", idx)) } } Address::Global(idx) => { let idx = idx as usize; let globals = self.globals.borrow(); if idx < globals.len() { Ok(globals[idx].clone()) } else { Err(format!("Global access out of bounds {}", idx)) } } Address::Upvalue(idx) => { let frame = self.frames.last().ok_or("No call frame")?; if let Some(closure) = &frame.closure { let idx = idx as usize; if idx < closure.upvalues.len() { Ok(closure.upvalues[idx].borrow().clone()) } else { Err(format!("Upvalue access out of bounds {}", idx)) } } else { Err("Current frame has no closure (cannot access upvalues)".to_string()) } } } } fn set_value(&mut self, addr: Address, value: Value) -> Result<(), String> { match addr { Address::Local(idx) => { let frame = self.frames.last().ok_or("No call frame")?; let abs_index = frame.stack_base + (idx as usize); if abs_index < self.stack.len() { if let Value::Cell(cell) = &self.stack[abs_index] { *cell.borrow_mut() = value; } else { self.stack[abs_index] = value; } } else if abs_index == self.stack.len() { self.stack.push(value); } else { return Err(format!("Stack gap write local {}", idx)); } Ok(()) } Address::Global(idx) => { let idx = idx as usize; let mut globals = self.globals.borrow_mut(); if idx >= globals.len() { globals.resize(idx + 1, Value::Void); } globals[idx] = value; Ok(()) } Address::Upvalue(idx) => { let frame = self.frames.last().ok_or("No call frame")?; if let Some(closure) = &frame.closure { let idx = idx as usize; if idx < closure.upvalues.len() { *closure.upvalues[idx].borrow_mut() = value; Ok(()) } else { Err(format!("Upvalue assignment out of bounds {}", idx)) } } else { Err("Current frame has no closure".to_string()) } } } } fn flatten_value(val: Value, into: &mut Vec) { if let Some(values) = val.as_slice() { into.extend_from_slice(values); } else { into.push(val); } } fn prepare_args_internal( &mut self, obs: &mut O, args: &ExecNode, ) -> Result, String> { let mut arg_vals = Vec::new(); match &args.kind { BoundKind::Tuple { elements } => { self.eval_and_flatten_internal(obs, elements, &mut arg_vals)?; } _ => { VM::flatten_value(self.eval_internal(obs, args)?, &mut arg_vals); } } Ok(arg_vals) } fn eval_and_flatten_internal( &mut self, obs: &mut O, elements: &[ExecNode], into: &mut Vec, ) -> Result<(), String> { for e in elements { into.push(self.eval_internal(obs, e)?); } Ok(()) } fn unpack( &mut self, pattern: &Node, T>, values: &[Value], offset: &mut usize, ) -> Result<(), String> { match &pattern.kind { BoundKind::Define { addr, .. } => { let val = values.get(*offset).cloned().unwrap_or(Value::Void); *offset += 1; self.set_value(*addr, val) } BoundKind::Set { addr, .. } => { let val = values.get(*offset).cloned().unwrap_or(Value::Void); *offset += 1; self.set_value(*addr, val) } BoundKind::Tuple { elements } => { if let Some(sub_values) = values.get(*offset).and_then(|v| v.as_slice()) { *offset += 1; let mut sub_offset = 0; for el in elements { self.unpack(el, sub_values, &mut sub_offset)?; } return Ok(()); } for el in elements { self.unpack(el, values, offset)?; } Ok(()) } _ => Err("Invalid node in parameter pattern".to_string()), } } }