Compare commits
No commits in common. "7e4ddd3dc457bddcc66c01fbbb387b469c28cbb8" and "94b7f983627a50a37a02ccf627c48005378c4a82" have entirely different histories.
7e4ddd3dc4
...
94b7f98362
10
src/main.rs
10
src/main.rs
|
@ -75,12 +75,14 @@ pub fn run(src: &'static str) {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
let src = "
|
let src = "
|
||||||
fn recursive {
|
fn nope () -> nil
|
||||||
(0) -> :done
|
fn foo () -> {
|
||||||
(n) -> recursive (0)
|
nope ()
|
||||||
|
:foo
|
||||||
}
|
}
|
||||||
|
fn bar () -> foo ()
|
||||||
|
|
||||||
recursive (1)
|
bar ()
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
}
|
}
|
||||||
|
|
132
src/vm.rs
132
src/vm.rs
|
@ -164,27 +164,11 @@ impl Vm {
|
||||||
self.result.as_ref().unwrap()
|
self.result.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_stack(&mut self) -> String {
|
|
||||||
let mut stack = format!(" calling {}", self.frame.function.show());
|
|
||||||
for frame in self.call_stack.iter().rev() {
|
|
||||||
let mut name = frame.function.show();
|
|
||||||
name = if name == "fn user script" {
|
|
||||||
"user script".to_string()
|
|
||||||
} else {
|
|
||||||
name
|
|
||||||
};
|
|
||||||
stack = format!("{stack}\n from {name}");
|
|
||||||
}
|
|
||||||
stack
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn panic(&mut self, msg: &'static str) {
|
pub fn panic(&mut self, msg: &'static str) {
|
||||||
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
|
self.result = Some(Err(Panic::Str(msg)));
|
||||||
self.result = Some(Err(Panic::String(msg)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panic_with(&mut self, msg: String) {
|
pub fn panic_with(&mut self, msg: String) {
|
||||||
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
|
|
||||||
self.result = Some(Err(Panic::String(msg)));
|
self.result = Some(Err(Panic::String(msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,6 +530,21 @@ impl Vm {
|
||||||
self.push(splatted);
|
self.push(splatted);
|
||||||
self.ip += 2;
|
self.ip += 2;
|
||||||
}
|
}
|
||||||
|
// PushDict => {
|
||||||
|
// let dict_len = self.chunk().bytecode[self.ip + 1] as usize * 2;
|
||||||
|
// let dict_members = self.stack.split_off(self.stack.len() - dict_len);
|
||||||
|
// let mut dict = HashMap::new();
|
||||||
|
// let mut dict_iter = dict_members.iter();
|
||||||
|
// while let Some(kw) = dict_iter.next() {
|
||||||
|
// let Value::Keyword(key) = kw else {
|
||||||
|
// unreachable!()
|
||||||
|
// };
|
||||||
|
// let value = dict_iter.next().unwrap();
|
||||||
|
// dict.insert(*key, value.clone());
|
||||||
|
// }
|
||||||
|
// self.push(Value::Dict(Box::new(dict)));
|
||||||
|
// self.ip += 2;
|
||||||
|
// }
|
||||||
PushDict => {
|
PushDict => {
|
||||||
self.push(Value::Dict(Box::new(HashMap::new())));
|
self.push(Value::Dict(Box::new(HashMap::new())));
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
|
@ -649,6 +648,7 @@ impl Vm {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let high = self.chunk().bytecode[self.ip + 1];
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
let low = self.chunk().bytecode[self.ip + 2];
|
||||||
let jump_len = combine_bytes(high, low);
|
let jump_len = combine_bytes(high, low);
|
||||||
|
// let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
|
||||||
if self.matches {
|
if self.matches {
|
||||||
self.ip += jump_len + 3;
|
self.ip += jump_len + 3;
|
||||||
} else {
|
} else {
|
||||||
|
@ -854,103 +854,7 @@ impl Vm {
|
||||||
};
|
};
|
||||||
self.push(Value::Partial(Rc::new(partial)));
|
self.push(Value::Partial(Rc::new(partial)));
|
||||||
}
|
}
|
||||||
TailCall => {
|
Call | 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];
|
let arity = self.chunk().bytecode[self.ip + 1];
|
||||||
self.ip += 2;
|
self.ip += 2;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user