tail calls work now? also print stack trace on panic
This commit is contained in:
parent
94b7f98362
commit
2f5dab84a7
|
@ -76,11 +76,11 @@ pub fn main() {
|
|||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
fn nope () -> nil
|
||||
fn foo () -> {
|
||||
fn foo (_, _, _) -> {
|
||||
nope ()
|
||||
:foo
|
||||
}
|
||||
fn bar () -> foo ()
|
||||
fn bar () -> foo (1, 2, 3)
|
||||
|
||||
bar ()
|
||||
";
|
||||
|
|
107
src/vm.rs
107
src/vm.rs
|
@ -164,12 +164,21 @@ impl Vm {
|
|||
self.result.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn print_call_stack(&mut self) {
|
||||
println!("in {}", self.frame.function.as_fn().name());
|
||||
for frame in self.call_stack.iter() {
|
||||
println!(" in {}", frame.function.as_fn().name());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panic(&mut self, msg: &'static str) {
|
||||
self.result = Some(Err(Panic::Str(msg)));
|
||||
self.print_call_stack();
|
||||
}
|
||||
|
||||
pub fn panic_with(&mut self, msg: String) {
|
||||
self.result = Some(Err(Panic::String(msg)));
|
||||
self.print_call_stack();
|
||||
}
|
||||
|
||||
pub fn interpret(&mut self) {
|
||||
|
@ -854,7 +863,103 @@ impl Vm {
|
|||
};
|
||||
self.push(Value::Partial(Rc::new(partial)));
|
||||
}
|
||||
Call | TailCall => {
|
||||
TailCall => {
|
||||
let arity = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip += 2;
|
||||
|
||||
let val = self.pop();
|
||||
|
||||
match val {
|
||||
Value::Fn(_) => {
|
||||
if !val.as_fn().accepts(arity) {
|
||||
return self.panic_with(format!(
|
||||
"wrong number of arguments to {} passing {arity} args",
|
||||
val.show()
|
||||
));
|
||||
}
|
||||
// first put the arguments in the register
|
||||
for i in 0..arity as usize {
|
||||
self.return_register[arity as usize - i - 1] = self.pop();
|
||||
}
|
||||
|
||||
// then pop everything back to the current stack frame
|
||||
self.stack.truncate(self.frame.stack_base);
|
||||
// then push the arguments back on the stack
|
||||
let mut i = 0;
|
||||
while i < 8 && self.return_register[i] != Value::Nothing {
|
||||
let mut value = Value::Nothing;
|
||||
swap(&mut self.return_register[i], &mut value);
|
||||
self.push(value);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let splat_arity = val.as_fn().splat_arity();
|
||||
if splat_arity > 0 && arity >= splat_arity {
|
||||
let splatted_args = self.stack.split_off(
|
||||
self.stack.len() - (arity - splat_arity) as usize - 1,
|
||||
);
|
||||
let gathered_args = Vector::from(splatted_args);
|
||||
self.push(Value::List(Box::new(gathered_args)));
|
||||
}
|
||||
let arity = splat_arity.min(arity);
|
||||
let mut frame = CallFrame {
|
||||
function: val,
|
||||
arity,
|
||||
stack_base: self.stack.len() - arity as usize,
|
||||
ip: 0,
|
||||
};
|
||||
|
||||
swap(&mut self.frame, &mut frame);
|
||||
frame.ip = self.ip;
|
||||
|
||||
self.ip = 0;
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("== tail call into {} ==", self.frame.function.show());
|
||||
}
|
||||
}
|
||||
Value::BaseFn(base_fn) => {
|
||||
let value = match (arity, base_fn) {
|
||||
(0, BaseFn::Nullary(f)) => f(),
|
||||
(1, BaseFn::Unary(f)) => f(&self.pop()),
|
||||
(2, BaseFn::Binary(f)) => f(&self.pop(), &self.pop()),
|
||||
(3, BaseFn::Ternary(f)) => f(&self.pop(), &self.pop(), &self.pop()),
|
||||
_ => return self.panic("internal ludus error"),
|
||||
};
|
||||
self.push(value);
|
||||
}
|
||||
Value::Partial(partial) => {
|
||||
let last_arg = self.pop();
|
||||
let args = &partial.args;
|
||||
for arg in args {
|
||||
if *arg == Value::Nothing {
|
||||
self.push(last_arg.clone());
|
||||
} else {
|
||||
self.push(arg.clone());
|
||||
}
|
||||
}
|
||||
let the_fn = partial.function.clone();
|
||||
let mut frame = CallFrame {
|
||||
function: the_fn,
|
||||
arity: args.len() as u8,
|
||||
stack_base: self.stack.len() - arity as usize - 1,
|
||||
ip: 0,
|
||||
};
|
||||
|
||||
swap(&mut self.frame, &mut frame);
|
||||
frame.ip = self.ip;
|
||||
|
||||
self.call_stack.push(frame);
|
||||
self.ip = 0;
|
||||
|
||||
if crate::DEBUG_RUN {
|
||||
println!("== calling into {} ==", self.frame.function.show());
|
||||
}
|
||||
}
|
||||
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
||||
}
|
||||
}
|
||||
Call => {
|
||||
let arity = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip += 2;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user