diff --git a/src/main.rs b/src/main.rs index c3c6528..cb02108 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,7 +76,9 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " - + fn add2 (x, y) -> add (x, y) + + add2 (_, 2) (2) "; run(src); diff --git a/src/parser.rs b/src/parser.rs index d698e1b..e826015 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -203,7 +203,7 @@ impl fmt::Display for Ast { .collect::>() .join("\n") ), - Placeholder => todo!(), + Placeholder => write!(f, "Placeholder"), LBox(_name, _rhs) => todo!(), Match(value, clauses) => { write!( diff --git a/src/value.rs b/src/value.rs index bae3389..ba13b28 100644 --- a/src/value.rs +++ b/src/value.rs @@ -52,6 +52,7 @@ impl LFn { } pub fn chunk(&self, arity: u8) -> &Chunk { + // println!("Getting chunk of {arity} from {:?}", self); match self { LFn::Declared { .. } => unreachable!(), LFn::Defined { chunks, .. } => &chunks.iter().find(|(a, _)| *a == arity).unwrap().1, @@ -68,9 +69,9 @@ impl LFn { #[derive(Clone, Debug, PartialEq)] pub struct Partial { - args: Vec, - name: &'static str, - function: Value, + pub args: Vec, + pub name: &'static str, + pub function: Value, } #[derive(Clone, Debug)] diff --git a/src/vm.rs b/src/vm.rs index 8ff12a2..e284908 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -2,7 +2,7 @@ use crate::base::BaseFn; use crate::compiler::{Chunk, Op}; use crate::parser::Ast; use crate::spans::Spanned; -use crate::value::{LFn, Value}; +use crate::value::{LFn, Partial, Value}; use chumsky::prelude::SimpleSpan; use imbl::{HashMap, Vector}; use num_traits::FromPrimitive; @@ -705,7 +705,19 @@ impl Vm { self.ip += 1; } Partial => { - todo!(); + let arity = self.chunk().bytecode[self.ip + 1]; + self.ip += 2; + let the_fn = self.pop(); + let Value::Fn(ref inner) = the_fn else { + return self.panic("only functions may be partially applied"); + }; + let args = self.stack.split_off(self.stack.len() - arity as usize); + let partial = crate::value::Partial { + args, + name: inner.name(), + function: the_fn, + }; + self.push(Value::Partial(Rc::new(partial))); } Call => { let arity = self.chunk().bytecode[self.ip + 1]; @@ -742,6 +754,34 @@ impl Vm { }; 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())), } }