From 681176282cdd7da697f1f7e6fdb4d7a80c86924e Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Tue, 3 Jun 2025 15:48:13 -0400 Subject: [PATCH] basic function calls, still with bugs! --- src/compiler.rs | 12 +- src/main.rs | 4 +- src/vm.rs | 992 +++++++++++++++++++++++++----------------------- 3 files changed, 519 insertions(+), 489 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 1184630..0470138 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -286,9 +286,9 @@ fn get_builtin(name: &str, arity: usize) -> Option { pub struct Compiler { pub chunk: Chunk, pub bindings: Vec, - scope_depth: isize, - match_depth: usize, - stack_depth: usize, + pub scope_depth: isize, + pub match_depth: usize, + pub stack_depth: usize, pub spans: Vec, pub nodes: Vec<&'static Ast>, pub ast: &'static Ast, @@ -837,10 +837,8 @@ impl Compiler { // visit all the args // then store them // then call the function - for (register_slot, arg) in args.iter().enumerate() { + for arg in args { self.visit(arg); - self.emit_op(Op::StoreAt); - self.emit_byte(register_slot); } self.emit_op(Op::PushBinding); @@ -982,7 +980,7 @@ impl Compiler { Some(compiler) => compiler, None => { 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.scope_depth += 1; compiler.emit_op(Op::ResetMatch); diff --git a/src/main.rs b/src/main.rs index 3ef0eec..c356c78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,7 +78,9 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " -(1, 2, 3) +fn foo (_) -> [1, 2, 3] + +foo (1) "; run(src); } diff --git a/src/vm.rs b/src/vm.rs index 79bcb10..a3b9a70 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -102,7 +102,7 @@ impl Vm { let base_fn = Value::Fn(Rc::new(cell)); let base_frame = CallFrame { function: base_fn.clone(), - stack_base: 1, + stack_base: 0, ip: 0, arity: 0, }; @@ -111,15 +111,7 @@ impl Vm { call_stack: Vec::with_capacity(64), frame: base_frame, ip: 0, - return_register: [ - Value::Nothing, - Value::Nothing, - Value::Nothing, - Value::Nothing, - Value::Nothing, - Value::Nothing, - Value::Nothing, - ], + return_register: [const { Value::Nothing }; 7], matches: false, match_depth: 0, result: None, @@ -180,495 +172,533 @@ impl Vm { } pub fn interpret(&mut self) { - let Some(byte) = self.chunk().bytecode.get(self.ip) else { - self.result = Some(Ok(self.stack.pop().unwrap())); - return; - }; - if crate::DEBUG_RUN { - self.print_debug(); - } - let op = Op::from_u8(*byte).unwrap(); - use Op::*; - match op { - Noop => { - self.ip += 1; + loop { + let Some(byte) = self.chunk().bytecode.get(self.ip) else { + self.result = Some(Ok(self.stack.pop().unwrap())); + return; + }; + if crate::DEBUG_RUN { + self.print_debug(); } - Nil => { - self.push(Value::Nil); - self.ip += 1; - } - True => { - self.push(Value::True); - self.ip += 1; - } - False => { - self.push(Value::False); - self.ip += 1; - } - Constant => { - let const_idx = self.chunk().bytecode[self.ip + 1]; - let value = self.chunk().constants[const_idx as usize].clone(); - self.push(value); - self.ip += 2; - } - Jump => { - let jump_len = self.chunk().bytecode[self.ip + 1]; - self.ip += jump_len as usize + 2; - } - JumpBack => { - let jump_len = self.chunk().bytecode[self.ip + 1]; - self.ip -= jump_len as usize; - } - JumpIfFalse => { - let jump_len = self.chunk().bytecode[self.ip + 1]; - let cond = self.pop(); - match cond { - Value::Nil | Value::False => { - self.ip += jump_len as usize + 2; - } - _ => { - self.ip += 2; - } - } - } - JumpIfTrue => { - let jump_len = self.chunk().bytecode[self.ip + 1]; - let cond = self.pop(); - match cond { - Value::Nil | Value::False => { - self.ip += 2; - } - _ => { - self.ip += jump_len as usize + 2; - } - } - } - JumpIfZero => { - let jump_len = self.chunk().bytecode[self.ip + 1]; - let cond = self.pop(); - match cond { - Value::Number(0.0) => { - self.ip += jump_len as usize + 2; - self.interpret() - } - Value::Number(..) => { - self.ip += 2; - self.interpret() - } - _ => self.panic("repeat requires a number"), - } - } - Pop => { - self.pop(); - self.ip += 1; - } - PopN => { - let n = self.chunk().bytecode[self.ip + 1] as usize; - self.stack.truncate(self.stack.len() - n); - self.ip += 2; - } - PushBinding => { - let binding_idx = self.chunk().bytecode[self.ip + 1] as usize; - let binding_value = self.stack[binding_idx].clone(); - self.push(binding_value); - self.ip += 2; - } - Store => { - self.return_register[0] = self.pop(); - self.push(Value::Nothing); - self.ip += 1; - } - StoreAt => { - let i = self.chunk().bytecode[self.ip + 1] as usize; - self.return_register[i] = self.pop(); - self.ip += 2; - } - Stash => { - self.return_register[0] = self.peek().clone(); - self.ip += 1; - } - Load => { - 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; - } - self.ip += 1; - } - ResetMatch => { - self.matches = false; - self.match_depth = 0; - self.ip += 1; - } - MatchWord => { - self.matches = true; - self.ip += 1; - } - MatchType => { - let as_type = self.pop(); - let idx = self.stack.len() - self.match_depth as usize - 1; - let val_type = self.stack[idx].type_of(); - let val_type = self.chunk().kw_from(val_type).unwrap(); - self.matches = val_type == as_type; - self.ip += 1; - self.interpret() - } - MatchNil => { - let idx = self.stack.len() - self.match_depth as usize - 1; - if self.stack[idx] == Value::Nil { - self.matches = true; - }; - self.ip += 1; - self.interpret() - } - MatchTrue => { - let idx = self.stack.len() - self.match_depth as usize - 1; - if self.stack[idx] == Value::True { - self.matches = true; - }; - self.ip += 1; - } - MatchFalse => { - let idx = self.stack.len() - self.match_depth as usize - 1; - if self.stack[idx] == Value::False { - self.matches = true; - } - self.ip += 1; - } - PanicIfNoMatch => { - if !self.matches { - self.panic("no match"); - } else { + let op = Op::from_u8(*byte).unwrap(); + use Op::*; + match op { + Noop => { self.ip += 1; } - } - MatchConstant => { - let const_idx = self.chunk().bytecode[self.ip + 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.ip += 2; - } - MatchTuple => { - let idx = self.stack.len() - self.match_depth as usize - 1; - let tuple_len = self.chunk().bytecode[self.ip + 1]; - let scrutinee = self.stack[idx].clone(); - match scrutinee { - Value::Tuple(members) => self.matches = members.len() == tuple_len as usize, - _ => self.matches = false, - }; - self.ip += 2; - } - PushTuple => { - 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 = Value::Tuple(Rc::new(tuple_members)); - self.stack.push(tuple); - self.ip += 2; - } - LoadTuple => { - let idx = self.stack.len() - self.match_depth as usize - 1; - let tuple = self.stack[idx].clone(); - match tuple { - Value::Tuple(members) => { - for member in members.iter() { - self.push(member.clone()); + Nil => { + self.push(Value::Nil); + self.ip += 1; + } + True => { + self.push(Value::True); + self.ip += 1; + } + False => { + self.push(Value::False); + self.ip += 1; + } + Constant => { + let const_idx = self.chunk().bytecode[self.ip + 1]; + let value = self.chunk().constants[const_idx as usize].clone(); + self.push(value); + self.ip += 2; + } + Jump => { + let jump_len = self.chunk().bytecode[self.ip + 1]; + self.ip += jump_len as usize + 2; + } + JumpBack => { + let jump_len = self.chunk().bytecode[self.ip + 1]; + self.ip -= jump_len as usize; + } + JumpIfFalse => { + let jump_len = self.chunk().bytecode[self.ip + 1]; + let cond = self.pop(); + match cond { + Value::Nil | Value::False => { + self.ip += jump_len as usize + 2; + } + _ => { + self.ip += 2; } } - _ => self.panic("internal error: expected tuple"), - }; - self.ip += 1; - } - PushList => { - 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 = Value::List(Box::new(Vector::from(list_members))); - self.stack.push(list); - self.ip += 2; - } - MatchList => { - let idx = self.stack.len() - self.match_depth as usize - 1; - let tuple_len = self.chunk().bytecode[self.ip + 1]; - let scrutinee = self.stack[idx].clone(); - match scrutinee { - Value::List(members) => self.matches = members.len() == tuple_len as usize, - _ => self.matches = false, - }; - self.ip += 2; - } - LoadList => { - let idx = self.stack.len() - self.match_depth as usize - 1; - let tuple = self.stack[idx].clone(); - match tuple { - Value::List(members) => { - for member in members.iter() { - self.push(member.clone()); + } + JumpIfTrue => { + let jump_len = self.chunk().bytecode[self.ip + 1]; + let cond = self.pop(); + match cond { + Value::Nil | Value::False => { + self.ip += 2; + } + _ => { + self.ip += jump_len as usize + 2; } } - _ => self.panic("internal error: expected tuple"), - }; - self.ip += 1; - } - 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 { + } + JumpIfZero => { + let jump_len = self.chunk().bytecode[self.ip + 1]; + let cond = self.pop(); + match cond { + Value::Number(x) if x <= 0.0 => { + self.ip += jump_len as usize + 2; + } + Value::Number(..) => { + self.ip += 2; + } + _ => return self.panic("repeat requires a number"), + } + } + Pop => { + self.pop(); + self.ip += 1; + } + PopN => { + let n = self.chunk().bytecode[self.ip + 1] as usize; + self.stack.truncate(self.stack.len() - n); + self.ip += 2; + } + PushBinding => { + let binding_idx = + self.chunk().bytecode[self.ip + 1] as usize + self.frame.stack_base; + let binding_value = self.stack[binding_idx].clone(); + self.push(binding_value); + self.ip += 2; + } + Store => { + self.return_register[0] = self.pop(); + self.push(Value::Nothing); + self.ip += 1; + } + StoreAt => { + let i = self.chunk().bytecode[self.ip + 1] as usize; + self.return_register[i] = self.pop(); + self.ip += 2; + } + Stash => { + self.return_register[0] = self.peek().clone(); + self.ip += 1; + } + Load => { + 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; + } + self.ip += 1; + } + ResetMatch => { + self.matches = false; + self.match_depth = 0; + self.ip += 1; + } + MatchWord => { + self.matches = true; + self.ip += 1; + } + MatchType => { + let as_type = self.pop(); + let idx = self.stack.len() - self.match_depth as usize - 1; + let val_type = self.stack[idx].type_of(); + let val_type = self.chunk().kw_from(val_type).unwrap(); + self.matches = val_type == as_type; + self.ip += 1; + } + MatchNil => { + let idx = self.stack.len() - self.match_depth as usize - 1; + if self.stack[idx] == Value::Nil { + self.matches = true; + }; + self.ip += 1; + } + MatchTrue => { + let idx = self.stack.len() - self.match_depth as usize - 1; + if self.stack[idx] == Value::True { + self.matches = true; + }; + self.ip += 1; + } + MatchFalse => { + let idx = self.stack.len() - self.match_depth as usize - 1; + if self.stack[idx] == Value::False { + self.matches = true; + } + self.ip += 1; + } + PanicIfNoMatch => { + if !self.matches { + return self.panic("no match"); + } else { + self.ip += 1; + } + } + MatchConstant => { + let const_idx = self.chunk().bytecode[self.ip + 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.ip += 2; + } + MatchTuple => { + let idx = self.stack.len() - self.match_depth as usize - 1; + let tuple_len = self.chunk().bytecode[self.ip + 1]; + let scrutinee = self.stack[idx].clone(); + match scrutinee { + Value::Tuple(members) => self.matches = members.len() == tuple_len as usize, + _ => self.matches = false, + }; + self.ip += 2; + } + PushTuple => { + 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 = Value::Tuple(Rc::new(tuple_members)); + self.push(tuple); + self.ip += 2; + } + LoadTuple => { + let idx = self.stack.len() - self.match_depth as usize - 1; + let tuple = self.stack[idx].clone(); + match tuple { + Value::Tuple(members) => { + for member in members.iter() { + self.push(member.clone()); + } + } + _ => return self.panic("internal error: expected tuple"), + }; + self.ip += 1; + } + PushList => { + 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 = Value::List(Box::new(Vector::from(list_members))); + self.push(list); + self.ip += 2; + } + MatchList => { + let idx = self.stack.len() - self.match_depth as usize - 1; + let tuple_len = self.chunk().bytecode[self.ip + 1]; + let scrutinee = self.stack[idx].clone(); + match scrutinee { + Value::List(members) => self.matches = members.len() == tuple_len as usize, + _ => self.matches = false, + }; + self.ip += 2; + } + LoadList => { + let idx = self.stack.len() - self.match_depth as usize - 1; + let tuple = self.stack[idx].clone(); + match tuple { + Value::List(members) => { + for member in members.iter() { + self.push(member.clone()); + } + } + _ => return self.panic("internal error: expected tuple"), + }; + self.ip += 1; + } + 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; + } + LoadDictValue => { + let dict_idx = self.chunk().bytecode[self.ip + 1] as usize; + let Value::Dict(dict) = self.stack[dict_idx].clone() else { + unreachable!("expected dict, got something else") + }; + let Value::Keyword(key) = self.pop() else { + unreachable!("expected keyword, got something else") + }; + let value = dict.get(&key).unwrap_or(&Value::Nil); + self.push(value.clone()); + self.ip += 2; + } + MatchDict => { + let idx = self.stack.len() - self.match_depth as usize - 1; + let dict_len = self.chunk().bytecode[self.ip + 1]; + let scrutinee = self.stack[idx].clone(); + match scrutinee { + Value::Dict(members) => self.matches = members.len() == dict_len as usize, + _ => self.matches = false, + }; + self.ip += 2; + } + PushBox => { + let val = self.pop(); + self.push(Value::Box(Rc::new(RefCell::new(val)))); + self.ip += 1; + } + GetKey => { + let key = self.pop(); + let Value::Keyword(idx) = key else { unreachable!() }; - let value = dict_iter.next().unwrap(); - dict.insert(*key, value.clone()); + let dict = self.pop(); + let value = match dict { + Value::Dict(d) => d.as_ref().get(&idx).unwrap_or(&Value::Nil).clone(), + _ => Value::Nil, + }; + self.push(value); + self.ip += 1; } - self.stack.push(Value::Dict(Box::new(dict))); - self.ip += 2; - } - LoadDictValue => { - let dict_idx = self.chunk().bytecode[self.ip + 1] as usize; - let Value::Dict(dict) = self.stack[dict_idx].clone() else { - unreachable!("expected dict, got something else") - }; - let Value::Keyword(key) = self.pop() else { - unreachable!("expected keyword, got something else") - }; - let value = dict.get(&key).unwrap_or(&Value::Nil); - self.push(value.clone()); - self.ip += 2; - } - MatchDict => { - let idx = self.stack.len() - self.match_depth as usize - 1; - let dict_len = self.chunk().bytecode[self.ip + 1]; - let scrutinee = self.stack[idx].clone(); - match scrutinee { - Value::Dict(members) => self.matches = members.len() == dict_len as usize, - _ => self.matches = false, - }; - self.ip += 2; - } - PushBox => { - let val = self.pop(); - self.stack.push(Value::Box(Rc::new(RefCell::new(val)))); - self.ip += 1; - } - GetKey => { - let key = self.pop(); - let Value::Keyword(idx) = key else { - unreachable!() - }; - let dict = self.pop(); - let value = match dict { - Value::Dict(d) => d.as_ref().get(&idx).unwrap_or(&Value::Nil).clone(), - _ => Value::Nil, - }; - self.push(value); - self.ip += 1; - } - JumpIfNoMatch => { - let jump_len = self.chunk().bytecode[self.ip + 1] as usize; - if !self.matches { - self.ip += jump_len + 2; - } else { + JumpIfNoMatch => { + let jump_len = self.chunk().bytecode[self.ip + 1] as usize; + if !self.matches { + self.ip += jump_len + 2; + } else { + self.ip += 2; + } + } + JumpIfMatch => { + let jump_len = self.chunk().bytecode[self.ip + 1] as usize; + if self.matches { + self.ip += jump_len + 2; + } else { + self.ip += 2; + } + } + TypeOf => { + let val = self.pop(); + let type_of = self.chunk().kw_from(val.type_of()).unwrap(); + self.push(type_of); + self.ip += 1; + } + Truncate => { + let val = self.pop(); + if let Value::Number(x) = val { + self.push(Value::Number(x as usize as f64)); + self.ip += 1; + } else { + return self.panic("repeat requires a number"); + } + } + Decrement => { + let val = self.pop(); + if let Value::Number(x) = val { + self.push(Value::Number(x - 1.0)); + self.ip += 1; + } else { + return self.panic("you may only decrement a number"); + } + } + Duplicate => { + self.push(self.peek().clone()); + self.ip += 1; + } + MatchDepth => { + self.match_depth = self.chunk().bytecode[self.ip + 1]; self.ip += 2; } - } - JumpIfMatch => { - let jump_len = self.chunk().bytecode[self.ip + 1] as usize; - if self.matches { - self.ip += jump_len + 2; - } else { + PanicNoWhen | PanicNoMatch => { + return self.panic("no match"); + } + Eq => { + let first = self.pop(); + let second = self.pop(); + if first == second { + self.push(Value::True) + } else { + self.push(Value::False) + } + self.ip += 1; + } + Add => { + let first = self.pop(); + let second = self.pop(); + if let (Value::Number(x), Value::Number(y)) = (first, second) { + self.push(Value::Number(x + y)) + } else { + return self.panic("`add` requires two numbers"); + } + self.ip += 1; + } + Sub => { + let first = self.pop(); + let second = self.pop(); + if let (Value::Number(x), Value::Number(y)) = (first, second) { + self.push(Value::Number(y - x)) + } else { + return self.panic("`sub` requires two numbers"); + } + self.ip += 1; + } + Mult => { + let first = self.pop(); + let second = self.pop(); + if let (Value::Number(x), Value::Number(y)) = (first, second) { + self.push(Value::Number(x * y)) + } else { + return self.panic("`mult` requires two numbers"); + } + self.ip += 1; + } + Div => { + let first = self.pop(); + let second = self.pop(); + if let (Value::Number(x), Value::Number(y)) = (first, second) { + if x == 0.0 { + return self.panic("division by 0"); + } + self.push(Value::Number(y / x)) + } else { + return self.panic("`div` requires two numbers"); + } + self.ip += 1; + } + Unbox => { + let the_box = self.pop(); + let inner = if let Value::Box(b) = the_box { + b.borrow().clone() + } else { + return self.panic("`unbox` requires a box"); + }; + self.push(inner); + self.ip += 1; + } + BoxStore => { + let new_value = self.pop(); + let the_box = self.pop(); + if let Value::Box(b) = the_box { + b.replace(new_value.clone()); + } else { + return self.panic("`store` requires a box"); + } + self.push(new_value); + self.ip += 1; + } + Assert => { + let value = self.stack.last().unwrap(); + if let Value::Nil | Value::False = value { + return self.panic("asserted falsy value"); + } + self.ip += 1; + } + Get => { + let key = self.pop(); + let dict = self.pop(); + let value = match (key, dict) { + (Value::Keyword(k), Value::Dict(d)) => { + d.as_ref().get(&k).unwrap_or(&Value::Nil).clone() + } + (Value::Keyword(_), _) => Value::Nil, + _ => return self.panic("keys must be keywords"), + }; + self.push(value); + self.ip += 1; + } + At => { + let idx = self.pop(); + let ordered = self.pop(); + let value = match (ordered, idx) { + (Value::List(l), Value::Number(i)) => { + l.get(i as usize).unwrap_or(&Value::Nil).clone() + } + (Value::Tuple(t), Value::Number(i)) => { + t.get(i as usize).unwrap_or(&Value::Nil).clone() + } + (_, Value::Number(_)) => Value::Nil, + _ => return self.panic("indexes must be numbers"), + }; + self.push(value); + self.ip += 1; + } + Not => { + let value = self.pop(); + let negated = match value { + Value::Nil | Value::False => Value::True, + _ => Value::False, + }; + self.push(negated); + self.ip += 1; + } + Panic => { + let msg = self.pop().show(self.chunk()); + return self.panic_with(msg); + } + EmptyString => { + self.push(Value::String(Rc::new("".to_string()))); + self.ip += 1; + } + //TODO: don't use the schlemiel's algo here + ConcatStrings => { + let second = self.pop(); + let first = self.pop(); + let combined = match (first, second) { + (Value::String(first), Value::String(second)) => { + let mut new = first.as_ref().clone(); + new.push_str(second.as_str()); + Value::String(Rc::new(new)) + } + _ => unreachable!(), + }; + self.push(combined); + self.ip += 1; + } + Stringify => { + let to_stringify = self.pop(); + let the_string = to_stringify.stringify(self.chunk()); + let stringified = Value::String(Rc::new(the_string)); + self.push(stringified); + self.ip += 1; + } + Call => { + let arity = self.chunk().bytecode[self.ip + 1]; self.ip += 2; - } - } - TypeOf => { - let val = self.pop(); - let type_of = self.chunk().kw_from(val.type_of()).unwrap(); - self.push(type_of); - self.ip += 1; - } - Truncate => { - let val = self.pop(); - if let Value::Number(x) = val { - self.push(Value::Number(x as usize as f64)); - self.ip += 1; - } else { - self.panic("repeat requires a number"); - } - } - Decrement => { - let val = self.pop(); - if let Value::Number(x) = val { - self.push(Value::Number(x - 1.0)); - self.ip += 1; - self.interpret() - } else { - self.panic("you may only decrement a number"); - } - } - Duplicate => { - self.push(self.peek().clone()); - self.ip += 1; - self.interpret() - } - MatchDepth => { - self.match_depth = self.chunk().bytecode[self.ip + 1]; - self.ip += 2; - self.interpret() - } - PanicNoWhen | PanicNoMatch => self.panic("no match"), - Eq => { - let first = self.stack.pop().unwrap(); - let second = self.stack.pop().unwrap(); - if first == second { - self.stack.push(Value::True) - } else { - self.stack.push(Value::False) - } - self.ip += 1; - } - Add => { - let first = self.stack.pop().unwrap(); - let second = self.stack.pop().unwrap(); - if let (Value::Number(x), Value::Number(y)) = (first, second) { - self.stack.push(Value::Number(x + y)) - } else { - self.panic("`add` requires two numbers") - } - self.ip += 1; - } - Sub => { - let first = self.stack.pop().unwrap(); - let second = self.stack.pop().unwrap(); - if let (Value::Number(x), Value::Number(y)) = (first, second) { - self.stack.push(Value::Number(y - x)) - } else { - self.panic("`sub` requires two numbers") - } - self.ip += 1; - } - Mult => { - let first = self.stack.pop().unwrap(); - let second = self.stack.pop().unwrap(); - if let (Value::Number(x), Value::Number(y)) = (first, second) { - self.stack.push(Value::Number(x * y)) - } else { - self.panic("`mult` requires two numbers") - } - self.ip += 1; - } - Div => { - let first = self.stack.pop().unwrap(); - let second = self.stack.pop().unwrap(); - if let (Value::Number(x), Value::Number(y)) = (first, second) { - if x == 0.0 { - self.panic("division by 0") + 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()) + ); } - self.stack.push(Value::Number(y / x)) - } else { - self.panic("`div` requires two numbers") } - self.ip += 1; - } - Unbox => { - let the_box = self.stack.pop().unwrap(); - let inner = if let Value::Box(b) = the_box { - b.borrow().clone() - } else { - return self.panic("`unbox` requires a box"); - }; - self.stack.push(inner); - self.ip += 1; - } - BoxStore => { - let new_value = self.stack.pop().unwrap(); - let the_box = self.stack.pop().unwrap(); - if let Value::Box(b) = the_box { - b.replace(new_value.clone()); - } else { - return self.panic("`store` requires a box"); + 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); } - self.stack.push(new_value); - self.ip += 1; } - Assert => { - let value = self.stack.last().unwrap(); - if let Value::Nil | Value::False = value { - return self.panic("asserted falsy value"); - } - self.ip += 1; - } - Get => { - let key = self.stack.pop().unwrap(); - let dict = self.stack.pop().unwrap(); - let value = match (key, dict) { - (Value::Keyword(k), Value::Dict(d)) => { - d.as_ref().get(&k).unwrap_or(&Value::Nil).clone() - } - (Value::Keyword(_), _) => Value::Nil, - _ => return self.panic("keys must be keywords"), - }; - self.stack.push(value); - self.ip += 1; - } - At => { - let idx = self.stack.pop().unwrap(); - let ordered = self.stack.pop().unwrap(); - let value = match (ordered, idx) { - (Value::List(l), Value::Number(i)) => { - l.get(i as usize).unwrap_or(&Value::Nil).clone() - } - (Value::Tuple(t), Value::Number(i)) => { - t.get(i as usize).unwrap_or(&Value::Nil).clone() - } - (_, Value::Number(_)) => Value::Nil, - _ => return self.panic("indexes must be numbers"), - }; - self.stack.push(value); - self.ip += 1; - } - Not => { - let value = self.pop(); - let negated = match value { - Value::Nil | Value::False => Value::True, - _ => Value::False, - }; - self.push(negated); - self.ip += 1; - } - Panic => { - let msg = self.pop().show(self.chunk()); - self.panic_with(msg); - } - EmptyString => { - self.push(Value::String(Rc::new("".to_string()))); - self.ip += 1; - } - //TODO: don't use the schlemiel's algo here - ConcatStrings => { - let second = self.pop(); - let first = self.pop(); - let combined = match (first, second) { - (Value::String(first), Value::String(second)) => { - let mut new = first.as_ref().clone(); - new.push_str(second.as_str()); - Value::String(Rc::new(new)) - } - _ => unreachable!(), - }; - self.push(combined); - self.ip += 1; - } - Stringify => { - let to_stringify = self.pop(); - let the_string = to_stringify.stringify(self.chunk()); - let stringified = Value::String(Rc::new(the_string)); - self.push(stringified); - self.ip += 1; - } - Call => todo!(), - Return => todo!(), } } }