Compare commits

..

2 Commits

Author SHA1 Message Date
Scott Richmond
681176282c basic function calls, still with bugs! 2025-06-03 15:48:13 -04:00
Scott Richmond
22d1ceb3e8 vm.chunk -> vm.callframe.chunk 2025-06-02 13:34:23 -04:00
3 changed files with 597 additions and 509 deletions

View File

@ -286,9 +286,9 @@ fn get_builtin(name: &str, arity: usize) -> Option<Op> {
pub struct Compiler { pub struct Compiler {
pub chunk: Chunk, pub chunk: Chunk,
pub bindings: Vec<Binding>, pub bindings: Vec<Binding>,
scope_depth: isize, pub scope_depth: isize,
match_depth: usize, pub match_depth: usize,
stack_depth: usize, pub stack_depth: usize,
pub spans: Vec<SimpleSpan>, pub spans: Vec<SimpleSpan>,
pub nodes: Vec<&'static Ast>, pub nodes: Vec<&'static Ast>,
pub ast: &'static Ast, pub ast: &'static Ast,
@ -837,10 +837,8 @@ impl Compiler {
// visit all the args // visit all the args
// then store them // then store them
// then call the function // then call the function
for (register_slot, arg) in args.iter().enumerate() { for arg in args {
self.visit(arg); self.visit(arg);
self.emit_op(Op::StoreAt);
self.emit_byte(register_slot);
} }
self.emit_op(Op::PushBinding); self.emit_op(Op::PushBinding);
@ -982,7 +980,7 @@ impl Compiler {
Some(compiler) => compiler, Some(compiler) => compiler,
None => { None => {
let mut compiler = Compiler::new(clause, self.name, self.src); let mut compiler = Compiler::new(clause, self.name, self.src);
compiler.emit_op(Op::Load); // compiler.emit_op(Op::Load);
compiler.stack_depth += arity; compiler.stack_depth += arity;
compiler.scope_depth += 1; compiler.scope_depth += 1;
compiler.emit_op(Op::ResetMatch); compiler.emit_op(Op::ResetMatch);

View File

@ -57,26 +57,30 @@ pub fn run(src: &'static str) {
println!("\n\n") println!("\n\n")
} }
// if DEBUG_RUN { if DEBUG_RUN {
// println!("=== vm run: test ==="); println!("=== vm run: test ===");
// } }
// let mut vm = Vm::new(&compiler.chunk); // TODO: investigate lifeteims and remove this clone
// let result = vm.run(); let show_chunk = compiler.chunk.clone();
// let output = match result { let vm_chunk = compiler.chunk;
// Ok(val) => val.show(&compiler.chunk),
// Err(panic) => format!("Ludus panicked! {panic}"), let mut vm = Vm::new(vm_chunk);
// }; let result = vm.run();
// vm.print_stack(); let output = match result {
// println!("{output}"); Ok(val) => val.show(&show_chunk),
Err(panic) => format!("Ludus panicked! {panic}"),
};
vm.print_stack();
println!("{output}");
} }
pub fn main() { pub fn main() {
env::set_var("RUST_BACKTRACE", "1"); env::set_var("RUST_BACKTRACE", "1");
let src = " let src = "
fn foo () -> :bar fn foo (_) -> [1, 2, 3]
foo () foo (1)
"; ";
run(src); run(src);
} }

286
src/vm.rs
View File

@ -1,10 +1,11 @@
use crate::compiler::{Chunk, Op}; use crate::compiler::{Chunk, Op};
use crate::parser::Ast; use crate::parser::Ast;
use crate::spans::Spanned; use crate::spans::Spanned;
use crate::value::Value; use crate::value::{LFn, Value};
use chumsky::prelude::SimpleSpan; use chumsky::prelude::SimpleSpan;
use imbl::{HashMap, Vector}; use imbl::{HashMap, Vector};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use std::cell::OnceCell;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::mem::swap; use std::mem::swap;
@ -43,9 +44,44 @@ pub struct Trace {
pub src: &'static str, pub src: &'static str,
} }
pub struct Vm<'a> { pub struct CallFrame {
pub function: Value,
pub arity: u8,
pub stack_base: usize,
pub ip: usize,
}
impl CallFrame {
pub fn chunk(&self) -> &Chunk {
let Value::Fn(ref function) = self.function else {
unreachable!()
};
&function
.get()
.unwrap()
.chunks
.iter()
.find(|(arity, _)| *arity == self.arity)
.unwrap()
.1
}
}
impl fmt::Display for CallFrame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Value::Fn(ref function) = self.function else {
unreachable!()
};
let inner_fn = function.get().unwrap();
let name = inner_fn.name;
write!(f, "CallFrame: {name}/{} @ {}", self.arity, self.ip)
}
}
pub struct Vm {
pub stack: Vec<Value>, pub stack: Vec<Value>,
pub chunk: &'a Chunk, pub call_stack: Vec<CallFrame>,
pub frame: CallFrame,
pub ip: usize, pub ip: usize,
pub return_register: [Value; 7], pub return_register: [Value; 7],
pub matches: bool, pub matches: bool,
@ -53,27 +89,39 @@ pub struct Vm<'a> {
pub result: Option<Result<Value, Panic>>, pub result: Option<Result<Value, Panic>>,
} }
impl<'a> Vm<'a> { impl Vm {
pub fn new(chunk: &'a Chunk) -> Vm<'a> { pub fn new(chunk: Chunk) -> Vm {
Vm { let cell = OnceCell::new();
chunk, let lfn = LFn {
stack: vec![], name: "user script",
doc: None,
chunks: vec![(0, chunk)],
closed: vec![],
};
let _ = cell.set(lfn);
let base_fn = Value::Fn(Rc::new(cell));
let base_frame = CallFrame {
function: base_fn.clone(),
stack_base: 0,
ip: 0, ip: 0,
return_register: [ arity: 0,
Value::Nothing, };
Value::Nothing, Vm {
Value::Nothing, stack: vec![],
Value::Nothing, call_stack: Vec::with_capacity(64),
Value::Nothing, frame: base_frame,
Value::Nothing, ip: 0,
Value::Nothing, return_register: [const { Value::Nothing }; 7],
],
matches: false, matches: false,
match_depth: 0, match_depth: 0,
result: None, result: None,
} }
} }
pub fn chunk(&self) -> &Chunk {
self.frame.chunk()
}
pub fn push(&mut self, value: Value) { pub fn push(&mut self, value: Value) {
self.stack.push(value); self.stack.push(value);
} }
@ -105,7 +153,7 @@ impl<'a> Vm<'a> {
fn print_debug(&self) { fn print_debug(&self) {
self.print_stack(); self.print_stack();
let mut ip = self.ip; let mut ip = self.ip;
self.chunk.dissasemble_instr(&mut ip); self.chunk().dissasemble_instr(&mut ip);
} }
pub fn run(&mut self) -> &Result<Value, Panic> { pub fn run(&mut self) -> &Result<Value, Panic> {
@ -124,7 +172,8 @@ impl<'a> Vm<'a> {
} }
pub fn interpret(&mut self) { pub fn interpret(&mut self) {
let Some(byte) = self.chunk.bytecode.get(self.ip) else { loop {
let Some(byte) = self.chunk().bytecode.get(self.ip) else {
self.result = Some(Ok(self.stack.pop().unwrap())); self.result = Some(Ok(self.stack.pop().unwrap()));
return; return;
}; };
@ -150,21 +199,21 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
} }
Constant => { Constant => {
let const_idx = self.chunk.bytecode[self.ip + 1]; let const_idx = self.chunk().bytecode[self.ip + 1];
let value = self.chunk.constants[const_idx as usize].clone(); let value = self.chunk().constants[const_idx as usize].clone();
self.push(value); self.push(value);
self.ip += 2; self.ip += 2;
} }
Jump => { Jump => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk().bytecode[self.ip + 1];
self.ip += jump_len as usize + 2; self.ip += jump_len as usize + 2;
} }
JumpBack => { JumpBack => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk().bytecode[self.ip + 1];
self.ip -= jump_len as usize; self.ip -= jump_len as usize;
} }
JumpIfFalse => { JumpIfFalse => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk().bytecode[self.ip + 1];
let cond = self.pop(); let cond = self.pop();
match cond { match cond {
Value::Nil | Value::False => { Value::Nil | Value::False => {
@ -176,7 +225,7 @@ impl<'a> Vm<'a> {
} }
} }
JumpIfTrue => { JumpIfTrue => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk().bytecode[self.ip + 1];
let cond = self.pop(); let cond = self.pop();
match cond { match cond {
Value::Nil | Value::False => { Value::Nil | Value::False => {
@ -188,18 +237,16 @@ impl<'a> Vm<'a> {
} }
} }
JumpIfZero => { JumpIfZero => {
let jump_len = self.chunk.bytecode[self.ip + 1]; let jump_len = self.chunk().bytecode[self.ip + 1];
let cond = self.pop(); let cond = self.pop();
match cond { match cond {
Value::Number(0.0) => { Value::Number(x) if x <= 0.0 => {
self.ip += jump_len as usize + 2; self.ip += jump_len as usize + 2;
self.interpret()
} }
Value::Number(..) => { Value::Number(..) => {
self.ip += 2; self.ip += 2;
self.interpret()
} }
_ => self.panic("repeat requires a number"), _ => return self.panic("repeat requires a number"),
} }
} }
Pop => { Pop => {
@ -207,12 +254,13 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
} }
PopN => { PopN => {
let n = self.chunk.bytecode[self.ip + 1] as usize; let n = self.chunk().bytecode[self.ip + 1] as usize;
self.stack.truncate(self.stack.len() - n); self.stack.truncate(self.stack.len() - n);
self.ip += 2; self.ip += 2;
} }
PushBinding => { PushBinding => {
let binding_idx = self.chunk.bytecode[self.ip + 1] as usize; let binding_idx =
self.chunk().bytecode[self.ip + 1] as usize + self.frame.stack_base;
let binding_value = self.stack[binding_idx].clone(); let binding_value = self.stack[binding_idx].clone();
self.push(binding_value); self.push(binding_value);
self.ip += 2; self.ip += 2;
@ -223,7 +271,7 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
} }
StoreAt => { StoreAt => {
let i = self.chunk.bytecode[self.ip + 1] as usize; let i = self.chunk().bytecode[self.ip + 1] as usize;
self.return_register[i] = self.pop(); self.return_register[i] = self.pop();
self.ip += 2; self.ip += 2;
} }
@ -254,10 +302,9 @@ impl<'a> Vm<'a> {
let as_type = self.pop(); let as_type = self.pop();
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
let val_type = self.stack[idx].type_of(); let val_type = self.stack[idx].type_of();
let val_type = self.chunk.kw_from(val_type).unwrap(); let val_type = self.chunk().kw_from(val_type).unwrap();
self.matches = val_type == as_type; self.matches = val_type == as_type;
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchNil => { MatchNil => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
@ -265,7 +312,6 @@ impl<'a> Vm<'a> {
self.matches = true; self.matches = true;
}; };
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchTrue => { MatchTrue => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
@ -283,20 +329,20 @@ impl<'a> Vm<'a> {
} }
PanicIfNoMatch => { PanicIfNoMatch => {
if !self.matches { if !self.matches {
self.panic("no match"); return self.panic("no match");
} else { } else {
self.ip += 1; self.ip += 1;
} }
} }
MatchConstant => { MatchConstant => {
let const_idx = self.chunk.bytecode[self.ip + 1]; let const_idx = self.chunk().bytecode[self.ip + 1];
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize]; self.matches = self.stack[idx] == self.chunk().constants[const_idx as usize];
self.ip += 2; self.ip += 2;
} }
MatchTuple => { MatchTuple => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
let tuple_len = self.chunk.bytecode[self.ip + 1]; let tuple_len = self.chunk().bytecode[self.ip + 1];
let scrutinee = self.stack[idx].clone(); let scrutinee = self.stack[idx].clone();
match scrutinee { match scrutinee {
Value::Tuple(members) => self.matches = members.len() == tuple_len as usize, Value::Tuple(members) => self.matches = members.len() == tuple_len as usize,
@ -305,10 +351,10 @@ impl<'a> Vm<'a> {
self.ip += 2; self.ip += 2;
} }
PushTuple => { PushTuple => {
let tuple_len = self.chunk.bytecode[self.ip + 1]; let tuple_len = self.chunk().bytecode[self.ip + 1];
let tuple_members = self.stack.split_off(self.stack.len() - tuple_len as usize); let tuple_members = self.stack.split_off(self.stack.len() - tuple_len as usize);
let tuple = Value::Tuple(Rc::new(tuple_members)); let tuple = Value::Tuple(Rc::new(tuple_members));
self.stack.push(tuple); self.push(tuple);
self.ip += 2; self.ip += 2;
} }
LoadTuple => { LoadTuple => {
@ -320,20 +366,20 @@ impl<'a> Vm<'a> {
self.push(member.clone()); self.push(member.clone());
} }
} }
_ => self.panic("internal error: expected tuple"), _ => return self.panic("internal error: expected tuple"),
}; };
self.ip += 1; self.ip += 1;
} }
PushList => { PushList => {
let list_len = self.chunk.bytecode[self.ip + 1]; let list_len = self.chunk().bytecode[self.ip + 1];
let list_members = self.stack.split_off(self.stack.len() - list_len as usize); let list_members = self.stack.split_off(self.stack.len() - list_len as usize);
let list = Value::List(Box::new(Vector::from(list_members))); let list = Value::List(Box::new(Vector::from(list_members)));
self.stack.push(list); self.push(list);
self.ip += 2; self.ip += 2;
} }
MatchList => { MatchList => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
let tuple_len = self.chunk.bytecode[self.ip + 1]; let tuple_len = self.chunk().bytecode[self.ip + 1];
let scrutinee = self.stack[idx].clone(); let scrutinee = self.stack[idx].clone();
match scrutinee { match scrutinee {
Value::List(members) => self.matches = members.len() == tuple_len as usize, Value::List(members) => self.matches = members.len() == tuple_len as usize,
@ -350,12 +396,12 @@ impl<'a> Vm<'a> {
self.push(member.clone()); self.push(member.clone());
} }
} }
_ => self.panic("internal error: expected tuple"), _ => return self.panic("internal error: expected tuple"),
}; };
self.ip += 1; self.ip += 1;
} }
PushDict => { PushDict => {
let dict_len = self.chunk.bytecode[self.ip + 1] as usize * 2; 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 dict_members = self.stack.split_off(self.stack.len() - dict_len);
let mut dict = HashMap::new(); let mut dict = HashMap::new();
let mut dict_iter = dict_members.iter(); let mut dict_iter = dict_members.iter();
@ -366,11 +412,11 @@ impl<'a> Vm<'a> {
let value = dict_iter.next().unwrap(); let value = dict_iter.next().unwrap();
dict.insert(*key, value.clone()); dict.insert(*key, value.clone());
} }
self.stack.push(Value::Dict(Box::new(dict))); self.push(Value::Dict(Box::new(dict)));
self.ip += 2; self.ip += 2;
} }
LoadDictValue => { LoadDictValue => {
let dict_idx = self.chunk.bytecode[self.ip + 1] as usize; let dict_idx = self.chunk().bytecode[self.ip + 1] as usize;
let Value::Dict(dict) = self.stack[dict_idx].clone() else { let Value::Dict(dict) = self.stack[dict_idx].clone() else {
unreachable!("expected dict, got something else") unreachable!("expected dict, got something else")
}; };
@ -383,7 +429,7 @@ impl<'a> Vm<'a> {
} }
MatchDict => { MatchDict => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;
let dict_len = self.chunk.bytecode[self.ip + 1]; let dict_len = self.chunk().bytecode[self.ip + 1];
let scrutinee = self.stack[idx].clone(); let scrutinee = self.stack[idx].clone();
match scrutinee { match scrutinee {
Value::Dict(members) => self.matches = members.len() == dict_len as usize, Value::Dict(members) => self.matches = members.len() == dict_len as usize,
@ -393,7 +439,7 @@ impl<'a> Vm<'a> {
} }
PushBox => { PushBox => {
let val = self.pop(); let val = self.pop();
self.stack.push(Value::Box(Rc::new(RefCell::new(val)))); self.push(Value::Box(Rc::new(RefCell::new(val))));
self.ip += 1; self.ip += 1;
} }
GetKey => { GetKey => {
@ -410,7 +456,7 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
} }
JumpIfNoMatch => { JumpIfNoMatch => {
let jump_len = self.chunk.bytecode[self.ip + 1] as usize; let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
if !self.matches { if !self.matches {
self.ip += jump_len + 2; self.ip += jump_len + 2;
} else { } else {
@ -418,7 +464,7 @@ impl<'a> Vm<'a> {
} }
} }
JumpIfMatch => { JumpIfMatch => {
let jump_len = self.chunk.bytecode[self.ip + 1] as usize; let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
if self.matches { if self.matches {
self.ip += jump_len + 2; self.ip += jump_len + 2;
} else { } else {
@ -427,7 +473,7 @@ impl<'a> Vm<'a> {
} }
TypeOf => { TypeOf => {
let val = self.pop(); let val = self.pop();
let type_of = self.chunk.kw_from(val.type_of()).unwrap(); let type_of = self.chunk().kw_from(val.type_of()).unwrap();
self.push(type_of); self.push(type_of);
self.ip += 1; self.ip += 1;
} }
@ -437,7 +483,7 @@ impl<'a> Vm<'a> {
self.push(Value::Number(x as usize as f64)); self.push(Value::Number(x as usize as f64));
self.ip += 1; self.ip += 1;
} else { } else {
self.panic("repeat requires a number"); return self.panic("repeat requires a number");
} }
} }
Decrement => { Decrement => {
@ -445,95 +491,93 @@ impl<'a> Vm<'a> {
if let Value::Number(x) = val { if let Value::Number(x) = val {
self.push(Value::Number(x - 1.0)); self.push(Value::Number(x - 1.0));
self.ip += 1; self.ip += 1;
self.interpret()
} else { } else {
self.panic("you may only decrement a number"); return self.panic("you may only decrement a number");
} }
} }
Duplicate => { Duplicate => {
self.push(self.peek().clone()); self.push(self.peek().clone());
self.ip += 1; self.ip += 1;
self.interpret()
} }
MatchDepth => { MatchDepth => {
self.match_depth = self.chunk.bytecode[self.ip + 1]; self.match_depth = self.chunk().bytecode[self.ip + 1];
self.ip += 2; self.ip += 2;
self.interpret()
} }
PanicNoWhen | PanicNoMatch => self.panic("no match"), PanicNoWhen | PanicNoMatch => {
return self.panic("no match");
}
Eq => { Eq => {
let first = self.stack.pop().unwrap(); let first = self.pop();
let second = self.stack.pop().unwrap(); let second = self.pop();
if first == second { if first == second {
self.stack.push(Value::True) self.push(Value::True)
} else { } else {
self.stack.push(Value::False) self.push(Value::False)
} }
self.ip += 1; self.ip += 1;
} }
Add => { Add => {
let first = self.stack.pop().unwrap(); let first = self.pop();
let second = self.stack.pop().unwrap(); let second = self.pop();
if let (Value::Number(x), Value::Number(y)) = (first, second) { if let (Value::Number(x), Value::Number(y)) = (first, second) {
self.stack.push(Value::Number(x + y)) self.push(Value::Number(x + y))
} else { } else {
self.panic("`add` requires two numbers") return self.panic("`add` requires two numbers");
} }
self.ip += 1; self.ip += 1;
} }
Sub => { Sub => {
let first = self.stack.pop().unwrap(); let first = self.pop();
let second = self.stack.pop().unwrap(); let second = self.pop();
if let (Value::Number(x), Value::Number(y)) = (first, second) { if let (Value::Number(x), Value::Number(y)) = (first, second) {
self.stack.push(Value::Number(y - x)) self.push(Value::Number(y - x))
} else { } else {
self.panic("`sub` requires two numbers") return self.panic("`sub` requires two numbers");
} }
self.ip += 1; self.ip += 1;
} }
Mult => { Mult => {
let first = self.stack.pop().unwrap(); let first = self.pop();
let second = self.stack.pop().unwrap(); let second = self.pop();
if let (Value::Number(x), Value::Number(y)) = (first, second) { if let (Value::Number(x), Value::Number(y)) = (first, second) {
self.stack.push(Value::Number(x * y)) self.push(Value::Number(x * y))
} else { } else {
self.panic("`mult` requires two numbers") return self.panic("`mult` requires two numbers");
} }
self.ip += 1; self.ip += 1;
} }
Div => { Div => {
let first = self.stack.pop().unwrap(); let first = self.pop();
let second = self.stack.pop().unwrap(); let second = self.pop();
if let (Value::Number(x), Value::Number(y)) = (first, second) { if let (Value::Number(x), Value::Number(y)) = (first, second) {
if x == 0.0 { if x == 0.0 {
self.panic("division by 0") return self.panic("division by 0");
} }
self.stack.push(Value::Number(y / x)) self.push(Value::Number(y / x))
} else { } else {
self.panic("`div` requires two numbers") return self.panic("`div` requires two numbers");
} }
self.ip += 1; self.ip += 1;
} }
Unbox => { Unbox => {
let the_box = self.stack.pop().unwrap(); let the_box = self.pop();
let inner = if let Value::Box(b) = the_box { let inner = if let Value::Box(b) = the_box {
b.borrow().clone() b.borrow().clone()
} else { } else {
return self.panic("`unbox` requires a box"); return self.panic("`unbox` requires a box");
}; };
self.stack.push(inner); self.push(inner);
self.ip += 1; self.ip += 1;
} }
BoxStore => { BoxStore => {
let new_value = self.stack.pop().unwrap(); let new_value = self.pop();
let the_box = self.stack.pop().unwrap(); let the_box = self.pop();
if let Value::Box(b) = the_box { if let Value::Box(b) = the_box {
b.replace(new_value.clone()); b.replace(new_value.clone());
} else { } else {
return self.panic("`store` requires a box"); return self.panic("`store` requires a box");
} }
self.stack.push(new_value); self.push(new_value);
self.ip += 1; self.ip += 1;
} }
Assert => { Assert => {
@ -544,8 +588,8 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
} }
Get => { Get => {
let key = self.stack.pop().unwrap(); let key = self.pop();
let dict = self.stack.pop().unwrap(); let dict = self.pop();
let value = match (key, dict) { let value = match (key, dict) {
(Value::Keyword(k), Value::Dict(d)) => { (Value::Keyword(k), Value::Dict(d)) => {
d.as_ref().get(&k).unwrap_or(&Value::Nil).clone() d.as_ref().get(&k).unwrap_or(&Value::Nil).clone()
@ -553,12 +597,12 @@ impl<'a> Vm<'a> {
(Value::Keyword(_), _) => Value::Nil, (Value::Keyword(_), _) => Value::Nil,
_ => return self.panic("keys must be keywords"), _ => return self.panic("keys must be keywords"),
}; };
self.stack.push(value); self.push(value);
self.ip += 1; self.ip += 1;
} }
At => { At => {
let idx = self.stack.pop().unwrap(); let idx = self.pop();
let ordered = self.stack.pop().unwrap(); let ordered = self.pop();
let value = match (ordered, idx) { let value = match (ordered, idx) {
(Value::List(l), Value::Number(i)) => { (Value::List(l), Value::Number(i)) => {
l.get(i as usize).unwrap_or(&Value::Nil).clone() l.get(i as usize).unwrap_or(&Value::Nil).clone()
@ -569,7 +613,7 @@ impl<'a> Vm<'a> {
(_, Value::Number(_)) => Value::Nil, (_, Value::Number(_)) => Value::Nil,
_ => return self.panic("indexes must be numbers"), _ => return self.panic("indexes must be numbers"),
}; };
self.stack.push(value); self.push(value);
self.ip += 1; self.ip += 1;
} }
Not => { Not => {
@ -582,8 +626,8 @@ impl<'a> Vm<'a> {
self.ip += 1; self.ip += 1;
} }
Panic => { Panic => {
let msg = self.pop().show(self.chunk); let msg = self.pop().show(self.chunk());
self.panic_with(msg); return self.panic_with(msg);
} }
EmptyString => { EmptyString => {
self.push(Value::String(Rc::new("".to_string()))); self.push(Value::String(Rc::new("".to_string())));
@ -606,13 +650,55 @@ impl<'a> Vm<'a> {
} }
Stringify => { Stringify => {
let to_stringify = self.pop(); let to_stringify = self.pop();
let the_string = to_stringify.stringify(self.chunk); let the_string = to_stringify.stringify(self.chunk());
let stringified = Value::String(Rc::new(the_string)); let stringified = Value::String(Rc::new(the_string));
self.push(stringified); self.push(stringified);
self.ip += 1; self.ip += 1;
} }
Call => todo!(), Call => {
Return => todo!(), let arity = self.chunk().bytecode[self.ip + 1];
self.ip += 2;
let val = self.pop();
let Value::Fn(_) = val else {
return self
.panic_with(format!("{} is not a function", val.show(self.chunk())));
};
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.call_stack.push(frame);
self.ip = 0;
if crate::DEBUG_RUN {
println!(
"== calling into {} ==",
self.frame.function.show(self.chunk())
);
}
}
Return => {
if crate::DEBUG_RUN {
println!(
"== returning from {} ==",
self.frame.function.show(self.chunk())
)
}
self.frame = self.call_stack.pop().unwrap();
self.ip = self.frame.ip;
let mut value = Value::Nothing;
swap(&mut self.return_register[0], &mut value);
self.push(value);
}
}
} }
} }
} }