Refactor function signatures to use slices
This commit is contained in:
+219
-169
@@ -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 ¤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::<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>,
|
||||
|
||||
Reference in New Issue
Block a user