first draft of partial application, is working in easy cases

This commit is contained in:
Scott Richmond 2025-06-05 16:45:23 -04:00
parent dee9bcfc33
commit f8adaa7971
4 changed files with 50 additions and 7 deletions

View File

@ -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);

View File

@ -203,7 +203,7 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>()
.join("\n")
),
Placeholder => todo!(),
Placeholder => write!(f, "Placeholder"),
LBox(_name, _rhs) => todo!(),
Match(value, clauses) => {
write!(

View File

@ -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<Value>,
name: &'static str,
function: Value,
pub args: Vec<Value>,
pub name: &'static str,
pub function: Value,
}
#[derive(Clone, Debug)]

View File

@ -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())),
}
}