Refactor function signatures to use slices

This commit is contained in:
Michael Schimmel
2026-03-03 18:13:20 +01:00
parent 7c38dee243
commit 8c4db9a5ba
12 changed files with 262 additions and 209 deletions
+219 -169
View File
@@ -180,7 +180,7 @@ impl VM {
pub fn run_with_args(
&mut self,
closure_obj: Rc<dyn Object>,
args: Vec<Value>,
args: &[Value],
) -> Result<Value, String> {
let closure = closure_obj.as_any().downcast_ref::<Closure>().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<dyn Object>,
args: Vec<Value>,
args: &[Value],
) -> Result<Value, String> {
let closure = closure_obj.as_any().downcast_ref::<Closure>().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<dyn FnMut(Vec<Value>) -> Value> =
Box::new(move |args: Vec<Value>| -> Value {
let executor: Box<crate::ast::types::PipeFn> =
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 &current_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::<crate::ast::rtl::series::RecordSeries>()
{
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::<crate::ast::rtl::series::RecordSeries>()
{
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::<Closure>() {
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::<Closure>().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<O: VMObserver>(
&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<Rc<RefCell<Value>>, String> {
match addr {
Address::Local(slot) => {
@@ -865,43 +952,6 @@ impl VM {
}
}
fn flatten_value(val: Value, into: &mut Vec<Value>) {
if let Some(values) = val.as_slice() {
into.extend_from_slice(values);
} else {
into.push(val);
}
}
fn prepare_args_internal<O: VMObserver>(
&mut self,
obs: &mut O,
args: &ExecNode,
) -> Result<Vec<Value>, 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<O: VMObserver>(
&mut self,
obs: &mut O,
elements: &[Rc<ExecNode>],
into: &mut Vec<Value>,
) -> Result<(), String> {
for e in elements {
into.push(self.eval_internal(obs, e)?);
}
Ok(())
}
fn unpack<T>(
&mut self,
pattern: &Node<BoundKind<T>, T>,