diff --git a/src/ast/compiler/optimizer/engine.rs b/src/ast/compiler/optimizer/engine.rs index c867444..5ced0a1 100644 --- a/src/ast/compiler/optimizer/engine.rs +++ b/src/ast/compiler/optimizer/engine.rs @@ -88,7 +88,7 @@ impl Optimizer { if let Some(val) = sub.get_value(&addr) && inliner.is_inlinable_value(val, addr) { - return Rc::new(folder.make_constant_node(val.clone(), &node)); + return Rc::new(folder.make_constant_node(val.clone(), node)); } // 2. Try inlining from AST substitution map (pure expressions) @@ -104,7 +104,7 @@ impl Optimizer { if let Some(val) = globals.get(idx.0 as usize) && inliner.is_inlinable_value(val, addr) { - return Rc::new(folder.make_constant_node(val.clone(), &node)); + return Rc::new(folder.make_constant_node(val.clone(), node)); } } } @@ -128,7 +128,7 @@ impl Optimizer { if let BoundKind::Constant(Value::Record(layout, values)) = &rec_opt.kind && let Some(idx) = layout.index_of(*field) { - return Rc::new(folder.make_constant_node(values[idx].clone(), &node)); + return Rc::new(folder.make_constant_node(values[idx].clone(), node)); } if Rc::ptr_eq(&rec_opt, rec) { @@ -395,7 +395,7 @@ impl Optimizer { } else if let Some(else_node) = else_br { return self.visit_node(else_node.clone(), sub, path); } else { - return Rc::new(folder.make_nop_node(&node)); + return Rc::new(folder.make_nop_node(node)); } } @@ -517,7 +517,7 @@ impl Optimizer { if self.enabled { if new_exprs.is_empty() { - return Rc::new(folder.make_nop_node(&node)); + return Rc::new(folder.make_nop_node(node)); } else if new_exprs.len() == 1 { return new_exprs.pop().unwrap(); } @@ -533,7 +533,7 @@ impl Optimizer { positional_count, } => { let mut info = UsageInfo::default(); - info.collect(&node); + info.collect(node); let mut new_upvalues = Vec::new(); let mut mapping = Vec::new(); @@ -643,7 +643,7 @@ impl Optimizer { } if self.enabled - && let Some(folded) = folder.try_fold_record(layout, &mapped_values, &node) + && let Some(folded) = folder.try_fold_record(layout, &mapped_values, node) { return Rc::new(folded); } diff --git a/src/ast/compiler/optimizer/folder.rs b/src/ast/compiler/optimizer/folder.rs index 2bd3631..bc18c16 100644 --- a/src/ast/compiler/optimizer/folder.rs +++ b/src/ast/compiler/optimizer/folder.rs @@ -94,7 +94,7 @@ impl<'a> Folder<'a> { _ => return None, }; let result = match func_val { - Value::Function(f) => (f.func)(arg_values), + Value::Function(f) => (f.func)(&arg_values), _ => return None, }; Some(self.make_constant_node(result, callee)) diff --git a/src/ast/environment.rs b/src/ast/environment.rs index b4d9dfb..f5be136 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -229,7 +229,7 @@ impl Environment { name: &str, ty: StaticType, purity_level: Purity, - func: impl Fn(Vec) -> Value + 'static, + func: impl Fn(&[Value]) -> Value + 'static, ) { self.register_native( name, @@ -501,7 +501,7 @@ impl Environment { pub fn run_script_compiled(&self, compiled: TypedNode) -> Result { let linked = self.link(compiled); let func = self.instantiate(linked); - let res = (func.func)(vec![]); + let res = (func.func)(&[]); self.run_pipeline(); Ok(res) } @@ -526,7 +526,7 @@ impl Environment { .downcast_ref::() .is_some() { - result = vm.run_with_args_observed(&mut observer, next_obj, next_args); + result = vm.run_with_args_observed(&mut observer, next_obj, &next_args); } else { result = Err(format!( "Tail call target is not a closure: {}", diff --git a/src/ast/rtl/core.rs b/src/ast/rtl/core.rs index cb05341..2950e4a 100644 --- a/src/ast/rtl/core.rs +++ b/src/ast/rtl/core.rs @@ -64,7 +64,7 @@ fn register_arithmetic(env: &Environment) { let mut acc = 0.0; for arg in args { if let Value::Int(i) = arg { - acc += i as f64; + acc += *i as f64; } else if let Value::Float(f) = arg { acc += f; } @@ -180,7 +180,7 @@ fn register_arithmetic(env: &Environment) { let mut acc = 1.0; for arg in args { if let Value::Int(i) = arg { - acc *= i as f64; + acc *= *i as f64; } else if let Value::Float(f) = arg { acc *= f; } diff --git a/src/ast/rtl/math.rs b/src/ast/rtl/math.rs index 25c18b2..59c709e 100644 --- a/src/ast/rtl/math.rs +++ b/src/ast/rtl/math.rs @@ -168,7 +168,7 @@ pub fn register(env: &Environment) { let prng = std::rc::Rc::new(std::cell::RefCell::new(rng)); Value::Function(std::rc::Rc::new(crate::ast::types::NativeFunction { - func: std::rc::Rc::new(move |_| Value::Float(prng.borrow_mut().f64())), + func: std::rc::Rc::new(move |_args| Value::Float(prng.borrow_mut().f64())), purity: Purity::Impure, })) }, diff --git a/src/ast/rtl/series.rs b/src/ast/rtl/series.rs index f08cf26..2a4b2a3 100644 --- a/src/ast/rtl/series.rs +++ b/src/ast/rtl/series.rs @@ -503,7 +503,7 @@ pub fn register(env: &Environment) { ret: StaticType::Any, // In reality: Object(RecordSeries) })), Purity::Impure, - |args: std::vec::Vec| { + |args: &[Value]| { if args.len() != 1 { panic!("create-series expects exactly 1 argument (a record)"); } @@ -525,7 +525,7 @@ pub fn register(env: &Environment) { ret: StaticType::Void, })), Purity::Impure, - |args: std::vec::Vec| { + |args: &[Value]| { if args.len() != 2 { panic!("push-series expects exactly 2 arguments (series, record)"); } diff --git a/src/ast/rtl/streams.rs b/src/ast/rtl/streams.rs index 9781eed..18224c9 100644 --- a/src/ast/rtl/streams.rs +++ b/src/ast/rtl/streams.rs @@ -1,4 +1,4 @@ -use crate::ast::types::Value; +use crate::ast::types::{PipeFn, Value}; use std::cell::RefCell; use std::rc::Rc; @@ -162,8 +162,8 @@ pub struct PipeStream { current_values: Vec, /// The current output signal of this pipe. current_signal: RefCell>, - /// The executable closure representing the Lambda. Expects a Vec of arguments. - pub executor: Option) -> Value>>, + /// The executable closure representing the Lambda. Expects a slice of arguments. + pub executor: Option>, /// Observers of THIS pipe. observers: RefCell>>>, } @@ -172,7 +172,7 @@ impl PipeStream { pub fn new( name: String, input_count: usize, - executor: Option) -> Value>>, + executor: Option>, ) -> Self { Self { name, @@ -210,8 +210,8 @@ impl Observer for PipeStream { }; if barrier_reached { - // 1. Prepare Arguments for Lambda (Current values of all inputs) - let args = self.current_values.clone(); + // 1. Prepare Arguments for Lambda (Current values of all inputs) - NO CLONE NEEDED! + let args = &self.current_values; // 2. Execute Lambda using the encapsulated VM executor let result = if let Some(exec) = &mut self.executor { @@ -291,7 +291,7 @@ impl Observer for RecordPusher { /// This keeps the VM "dumb" and moves the buffer selection logic to the RTL. pub fn build_pipeline_node( inputs: Vec>, - executor: Box) -> Value>, + executor: Box, out_type: &StaticType, ) -> Rc { use crate::ast::rtl::series::*; @@ -442,7 +442,7 @@ pub fn register(env: &Environment) { ret: StaticType::Series(Box::new(StaticType::Record(ohlc_layout.clone()))), })), Purity::Impure, // Modifies global generator registry - move |args: std::vec::Vec| { + move |args: &[Value]| { if args.len() != 2 { panic!("create-random-ohlc expects exactly 2 arguments (seed, limit)"); } @@ -527,7 +527,7 @@ pub fn register(env: &Environment) { ret: StaticType::Any, // Returns StreamNode })), Purity::Impure, - move |args: std::vec::Vec| { + move |args: &[Value]| { if args.len() != 1 { panic!("create-ticker expects exactly 1 argument (the condition closure)"); } @@ -550,7 +550,7 @@ pub fn register(env: &Environment) { // 3. Create generator let generator = move || -> bool { - match ticker_vm.run_with_args(my_closure.clone(), vec![]) { + match ticker_vm.run_with_args(my_closure.clone(), &[]) { Ok(Value::Bool(b)) => { if b { // Ticker pulses with a simple `true` value or `Void` @@ -578,7 +578,7 @@ pub fn register(env: &Environment) { #[cfg(test)] mod tests { use super::*; - use crate::ast::types::Value; + use crate::ast::types::{PipeFn, Value}; #[test] fn test_root_to_pipe_flow() { diff --git a/src/ast/rtl/type_registry.rs b/src/ast/rtl/type_registry.rs index a9a75e7..cd21064 100644 --- a/src/ast/rtl/type_registry.rs +++ b/src/ast/rtl/type_registry.rs @@ -53,10 +53,10 @@ impl TypeRegistry { pub fn create_factory(factory_func: F) -> Value where T: Scriptable, - F: Fn(Vec) -> Result + 'static, + F: Fn(&[Value]) -> Result + 'static, { // The factory is a script function that calls the Rust factory, gets T, then wraps it. - let closure = move |args: Vec| -> Value { + let closure = move |args: &[Value]| -> Value { match factory_func(args) { Ok(instance) => instance.wrap(), Err(msg) => { @@ -90,7 +90,7 @@ impl RecordBuilder { pub fn method(mut self, name: &str, func: F) -> Self where - F: Fn(Vec) -> Value + 'static, + F: Fn(&[Value]) -> Value + 'static, { let key = Keyword::intern(name); self.fields @@ -101,9 +101,9 @@ impl RecordBuilder { // Helper for methods that return Result (propagating panics for now) pub fn method_checked(self, name: &str, func: F) -> Self where - F: Fn(Vec) -> Result + 'static, + F: Fn(&[Value]) -> Result + 'static, { - let closure = move |args: Vec| match func(args) { + let closure = move |args: &[Value]| match func(args) { Ok(v) => v, Err(e) => panic!("Method call error: {}", e), }; @@ -218,7 +218,7 @@ mod tests { let greet_fn = &values[idx]; if let Value::Function(f) = greet_fn { - let res = (f.func)(vec![]); + let res = (f.func)(&[]); if let Value::Text(s) = res { assert_eq!(&*s, "Hello Alice"); } else { @@ -234,7 +234,7 @@ mod tests { #[test] fn test_factory() { - let factory_val = TypeRegistry::create_factory(|args: Vec| { + let factory_val = TypeRegistry::create_factory(|args: &[Value]| { if args.len() != 2 { return Err("Expected 2 args".to_string()); } @@ -250,13 +250,13 @@ mod tests { }); if let Value::Function(f) = factory_val { - let instance = (f.func)(vec![Value::Text("Bob".into()), Value::Int(40)]); + let instance = (f.func)(&[Value::Text("Bob".into()), Value::Int(40)]); if let Value::Record(layout, values) = instance { let idx = layout.index_of(Keyword::intern("greet")).unwrap(); let greet_fn = &values[idx]; if let Value::Function(gf) = greet_fn { - let res = (gf.func)(vec![]); + let res = (gf.func)(&[]); if let Value::Text(s) = res { assert_eq!(&*s, "Hello Bob"); } else { diff --git a/src/ast/types.rs b/src/ast/types.rs index 2b3ffba..aa9cfb1 100644 --- a/src/ast/types.rs +++ b/src/ast/types.rs @@ -204,9 +204,12 @@ pub enum Purity { Pure, } +pub type NativeFn = dyn Fn(&[Value]) -> Value; +pub type PipeFn = dyn FnMut(&[Value]) -> Value; + /// A native host function with metadata. pub struct NativeFunction { - pub func: Rc) -> Value>, + pub func: Rc, pub purity: Purity, } @@ -503,7 +506,7 @@ impl Value { Value::Record(layout, Rc::new(values)) } - pub fn make_function(purity: Purity, func: impl Fn(Vec) -> Value + 'static) -> Self { + pub fn make_function(purity: Purity, func: impl Fn(&[Value]) -> Value + 'static) -> Self { Value::Function(Rc::new(NativeFunction { func: Rc::new(func), purity, diff --git a/src/ast/vm.rs b/src/ast/vm.rs index e1efb3c..e1d7cc9 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -180,7 +180,7 @@ impl VM { pub fn run_with_args( &mut self, closure_obj: Rc, - args: Vec, + args: &[Value], ) -> Result { let closure = closure_obj.as_any().downcast_ref::().unwrap(); self.stack.clear(); @@ -192,9 +192,9 @@ impl VM { if let Some(count) = closure.positional_count && args.len() == count as usize { - self.stack.extend(args); + self.stack.extend_from_slice(args); } else { - self.unpack(&closure.parameter_node, &args, &mut 0)?; + self.unpack(&closure.parameter_node, args, &mut 0)?; } self.eval(&closure.exec_node) } @@ -203,7 +203,7 @@ impl VM { &mut self, observer: &mut O, closure_obj: Rc, - args: Vec, + args: &[Value], ) -> Result { let closure = closure_obj.as_any().downcast_ref::().unwrap(); self.stack.clear(); @@ -215,9 +215,9 @@ impl VM { if let Some(count) = closure.positional_count && args.len() == count as usize { - self.stack.extend(args); + self.stack.extend_from_slice(args); } else { - self.unpack(&closure.parameter_node, &args, &mut 0)?; + self.unpack(&closure.parameter_node, args, &mut 0)?; } self.eval_observed(observer, &closure.exec_node) } @@ -419,8 +419,8 @@ impl VM { // Create the persistent execution closure for the PipeStream let mut pipe_vm = crate::ast::vm::VM::new(self.globals.clone()); let my_closure = lambda_obj.clone(); - let executor: Box) -> Value> = - Box::new(move |args: Vec| -> Value { + let executor: Box = + Box::new(move |args: &[Value]| -> Value { match pipe_vm.run_with_args(my_closure.clone(), args) { Ok(res) => res, Err(e) => panic!("Pipeline lambda execution failed: {}", e), @@ -462,32 +462,21 @@ impl VM { 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)?, - }; + let base = self.stack.len(); + if let Err(e) = self.eval_args_to_stack(obs, args) { + self.stack.truncate(base); + return Err(e); + } if node.ty.is_tail { + let arg_vals = self.stack[base..].to_vec(); + self.stack.truncate(base); + match func_val { Value::Object(obj) => { return Ok(Value::TailCallRequest(Box::new((obj, arg_vals)))); } - Value::Function(f) => return Ok((f.func)(arg_vals)), + Value::Function(f) => return Ok((f.func)(&arg_vals)), Value::FieldAccessor(k) => { if arg_vals.len() != 1 { return Err(format!( @@ -547,148 +536,166 @@ impl VM { } } + // Standard Call Path + let mut current_func = func_val; loop { - match func_val { - Value::Function(f) => break Ok((f.func)(arg_vals)), + let result = match ¤t_func { + Value::Function(f) => { + let res = (f.func)(&self.stack[base..]); + self.stack.truncate(base); + return Ok(res); + } Value::FieldAccessor(k) => { - if arg_vals.len() != 1 { - break Err(format!( + let arg_len = self.stack.len() - base; + let res = if arg_len != 1 { + Err(format!( "Field accessor .{} expects exactly 1 argument, got {}", k.name(), - arg_vals.len() - )); - } - let rec = &arg_vals[0]; - if let Value::Record(layout, values) = rec { - if let Some(idx) = layout.index_of(k) { - break Ok(values[idx].clone()); - } else { - break Err(format!("Record does not have field :{}", k.name())); - } - } else if let Value::Object(obj) = rec { - // Polymorphic Field Access: Allow `.field` on a RecordSeries - if let Some(rs) = obj - .as_any() - .downcast_ref::() - { - if let Some(field_series) = rs.field(k) { - let view = crate::ast::rtl::series::SeriesView::new( - field_series, - k, - ); - break Ok(Value::Object(std::rc::Rc::new(view))); - } else { - break Err(format!( - "RecordSeries does not have field :{}", - k.name() - )); - } - } - break Err(format!( - "Field accessor .{} expects a record or RecordSeries, got {}", - k.name(), - obj.type_name() - )); + arg_len + )) } else { - break Err(format!( - "Field accessor .{} expects a record or RecordSeries, got {}", - k.name(), - rec - )); - } + let rec = &self.stack[base]; + if let Value::Record(layout, values) = rec { + if let Some(idx) = layout.index_of(*k) { + Ok(values[idx].clone()) + } else { + Err(format!("Record does not have field :{}", k.name())) + } + } else if let Value::Object(obj) = rec { + if let Some(rs) = obj + .as_any() + .downcast_ref::() + { + if let Some(field_series) = rs.field(*k) { + let view = crate::ast::rtl::series::SeriesView::new( + field_series, + *k, + ); + Ok(Value::Object(std::rc::Rc::new(view))) + } else { + Err(format!( + "RecordSeries does not have field :{}", + k.name() + )) + } + } else { + Err(format!( + "Field accessor .{} expects a record or RecordSeries, got {}", + k.name(), + obj.type_name() + )) + } + } else { + Err(format!( + "Field accessor .{} expects a record or RecordSeries, got {}", + k.name(), + rec + )) + } + }; + self.stack.truncate(base); + return res; } Value::Object(obj) => { if let Some(closure) = obj.as_any().downcast_ref::() { - let old_stack_top = self.stack.len(); self.frames.push(CallFrame { - stack_base: old_stack_top, + stack_base: base, closure: Some(obj.clone()), }); - if let Some(count) = closure.positional_count - && arg_vals.len() == count as usize + + let unpack_res = if let Some(count) = closure.positional_count + && (self.stack.len() - base) == count as usize { - self.stack.extend(arg_vals); + Ok(()) } else { - // Map each parameter pattern to the provided arguments + let args_for_unpack = self.stack[base..].to_vec(); + self.stack.truncate(base); if let BoundKind::Tuple { elements } = &closure.parameter_node.kind { let mut offset = 0; + let mut res = Ok(()); for el in elements { - self.unpack(el, &arg_vals, &mut offset)?; + if let Err(e) = + self.unpack(el, &args_for_unpack, &mut offset) + { + res = Err(e); + break; + } } + res } else { - self.unpack(&closure.parameter_node, &arg_vals, &mut 0)?; + self.unpack(&closure.parameter_node, &args_for_unpack, &mut 0) } - } - let result = self.eval_internal(obs, &closure.exec_node); + }; + + let res = match unpack_res { + Ok(_) => self.eval_internal(obs, &closure.exec_node), + Err(e) => Err(e), + }; + 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, - } + res } else if let Some(series) = obj.as_series() { - // Unified Series Access (Step 1 of Dual Series Architecture) - // This handles RecordSeries, SeriesView, and future SharedSeries polymorphically. - if arg_vals.len() != 1 { - break Err(format!( + let arg_len = self.stack.len() - base; + let res = if arg_len != 1 { + Err(format!( "{} indexer expects exactly 1 argument (the lookback index)", obj.type_name() - )); - } - if let Value::Int(idx) = arg_vals[0] { + )) + } else if let Value::Int(idx) = self.stack[base] { if idx < 0 { - break Err(format!( + Err(format!( "{} lookback index cannot be negative", obj.type_name() - )); - } - if let Some(val) = series.get_item(idx as usize) { - break Ok(val); + )) + } else if let Some(val) = series.get_item(idx as usize) { + Ok(val) } else { - // Out of bounds / not enough data yet - break Ok(Value::Void); + Ok(Value::Void) } } else { - break Err(format!( + Err(format!( "{} index must be an integer", obj.type_name() - )); - } + )) + }; + self.stack.truncate(base); + return res; } else { - break Err(format!("Object is not callable: {}", obj.type_name())); + self.stack.truncate(base); + return Err(format!("Object is not callable: {}", obj.type_name())); } } - _ => break Err(format!("Attempt to call non-function: {}", func_val)), + _ => { + self.stack.truncate(base); + return Err(format!("Attempt to call non-function: {}", current_func)); + } + }; + + match result { + Ok(Value::TailCallRequest(payload)) => { + let (next_obj, next_args) = *payload; + current_func = Value::Object(next_obj); + self.stack.truncate(base); + self.stack.extend(next_args); + continue; + } + res => { + self.stack.truncate(base); + return res; + } } } } 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 base = self.stack.len(); + if let Err(e) = self.eval_args_to_stack(obs, args) { + self.stack.truncate(base); + return Err(e); + } + let arg_vals = self.stack[base..].to_vec(); + self.stack.truncate(base); let frame = self.frames.last().ok_or("No call frame for 'again'")?; if let Some(closure_obj) = &frame.closure { @@ -717,7 +724,19 @@ impl VM { std::rc::Rc::new(evaluated_values), )) } - BoundKind::Expansion { bound_expanded, .. } => self.eval_internal(obs, bound_expanded), + BoundKind::Expansion { bound_expanded, .. } => { + let mut curr = bound_expanded; + if !O::ACTIVE { + while let BoundKind::Expansion { + bound_expanded: next, + .. + } = &curr.kind + { + curr = next; + } + } + self.eval_internal(obs, curr) + } BoundKind::Extension(ext) => Err(format!( "Execution of extension '{}' not implemented yet", ext.display_name() @@ -730,7 +749,7 @@ impl VM { while let Value::TailCallRequest(payload) = result { let (next_obj, next_args) = *payload; if next_obj.as_any().downcast_ref::().is_some() { - result = match self.run_with_args(next_obj, next_args) { + result = match self.run_with_args(next_obj, &next_args) { Ok(v) => v, Err(e) => panic!("Myc Runtime Error (TailCall): {}", e), }; @@ -744,6 +763,74 @@ impl VM { result } + fn eval_args_to_stack( + &mut self, + obs: &mut O, + args: &ExecNode, + ) -> Result<(), String> { + match &args.kind { + BoundKind::Tuple { elements } => { + for e in elements { + let mut curr = e.as_ref(); + if !O::ACTIVE { + while let BoundKind::Expansion { + bound_expanded: next, + .. + } = &curr.kind + { + curr = next; + } + } + + match &curr.kind { + BoundKind::Constant(v) => self.stack.push(v.clone()), + _ => { + let val = self.eval_internal(obs, curr)?; + self.stack.push(val); + } + } + } + Ok(()) + } + BoundKind::Constant(v) => { + if let Some(slice) = v.as_slice() { + self.stack.extend_from_slice(slice); + } else { + self.stack.push(v.clone()); + } + Ok(()) + } + BoundKind::Expansion { bound_expanded, .. } => { + let mut curr = bound_expanded; + if !O::ACTIVE { + while let BoundKind::Expansion { + bound_expanded: next, + .. + } = &curr.kind + { + curr = next; + } + } + let val = self.eval_internal(obs, curr)?; + if let Some(slice) = val.as_slice() { + self.stack.extend_from_slice(slice); + } else { + self.stack.push(val); + } + Ok(()) + } + _ => { + let val = self.eval_internal(obs, args)?; + if let Some(slice) = val.as_slice() { + self.stack.extend_from_slice(slice); + } else { + self.stack.push(val); + } + Ok(()) + } + } + } + fn capture_upvalue(&mut self, addr: Address) -> Result>, String> { match addr { Address::Local(slot) => { @@ -865,43 +952,6 @@ impl VM { } } - 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: &[Rc], - into: &mut Vec, - ) -> Result<(), String> { - for e in elements { - into.push(self.eval_internal(obs, e)?); - } - Ok(()) - } - fn unpack( &mut self, pattern: &Node, T>, diff --git a/src/integration_test.rs b/src/integration_test.rs index f1e54c2..29b4686 100644 --- a/src/integration_test.rs +++ b/src/integration_test.rs @@ -75,7 +75,7 @@ mod tests { .expect("Failed to compile"); let linked = env.link(compiled); let func = env.instantiate(linked); - let result: Result = Ok((func.func)(vec![])); + let result: Result = Ok((func.func)(&[])); match result { Ok(Value::Int(20)) => (), diff --git a/src/utils/tester.rs b/src/utils/tester.rs index aff1246..db2f430 100644 --- a/src/utils/tester.rs +++ b/src/utils/tester.rs @@ -133,7 +133,7 @@ pub fn run_benchmarks(update: bool, filter: Option<&str>) -> Vec