From e580d68809b8430f9ecf207a496536333fa58664 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Fri, 20 Jun 2025 12:32:15 -0400 Subject: [PATCH] recursion works, so does mutual recursion; function call bugfixes --- src/compiler.rs | 39 +++++++++++++++++++++++++++++++++------ src/main.rs | 4 ++++ src/vm.rs | 18 ++++++++++++++---- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index e4e267a..930a637 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -367,7 +367,7 @@ fn is_binding(expr: &Spanned) -> bool { let (ast, _) = expr; use Ast::*; match ast { - Let(..) | LBox(..) => true, + Let(..) | LBox(..) | FnDeclaration(..) => true, Fn(name, ..) => !name.is_empty(), _ => false, } @@ -1209,7 +1209,19 @@ impl<'a> Compiler<'a> { } MatchClause(..) => unreachable!(), Fn(name, body, doc) => { - let name = if name.is_empty() { "anonymous" } else { name }; + let is_anon = name.is_empty(); + + if !is_anon { + let declared = self.chunk.constants.iter().any(|val| match val { + Value::Fn(lfn) => lfn.name() == *name, + _ => false, + }); + if !declared { + let declaration = Value::Fn(Rc::new(LFn::Declared { name })); + self.emit_constant(declaration); + self.bind(name); + } + } let FnBody(fn_body) = &body.as_ref().0 else { unreachable!() @@ -1268,8 +1280,8 @@ impl<'a> Compiler<'a> { for idx in tup_jump_idxes { compiler.patch_jump(idx, compiler.len() - idx - 3); } - compiler.emit_op(Op::PopN); - compiler.emit_byte(arity as usize); + // compiler.emit_op(Op::PopN); + // compiler.emit_byte(arity as usize); compiler.patch_jump(jump_idx, compiler.len() - jump_idx - 3); let mut no_match_jumps = vec![]; no_match_jumps.push(compiler.stub_jump(Op::JumpIfNoMatch)); @@ -1337,8 +1349,23 @@ impl<'a> Compiler<'a> { // TODO: check if the function is already declared, and pull out the relevant OnceCell if need be let the_fn = Value::Fn(Rc::new(lfn)); - self.emit_constant(the_fn); - self.bind(name); + // self.emit_constant(the_fn); + // self.bind(name); + + if !is_anon { + let declaration_idx = self + .chunk + .constants + .iter() + .position(|val| match val { + Value::Fn(declaration) => declaration.name() == *name, + _ => false, + }) + .unwrap(); + self.chunk.constants[declaration_idx] = the_fn; + } else { + self.emit_constant(the_fn) + } for upvalue in upvalues { self.emit_op(Op::SetUpvalue); diff --git a/src/main.rs b/src/main.rs index f673ee9..c3ac9f4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,11 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " +fn two +fn one (x, y) -> two (x, y) +fn two (:foo, x) -> (:done, x) +one (:fool, :bar) "; run(src); } diff --git a/src/vm.rs b/src/vm.rs index cec144f..3d33dd1 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -872,6 +872,7 @@ impl Vm { for i in 0..arity as usize { self.return_register[arity as usize - i - 1] = self.pop(); } + self.print_stack(); // then pop everything back to the current stack frame self.stack.truncate(self.frame.stack_base); @@ -892,11 +893,16 @@ impl Vm { let gathered_args = Vector::from(splatted_args); self.push(Value::List(Box::new(gathered_args))); } - let arity = splat_arity.min(arity); + let arity = if splat_arity > 0 { + splat_arity.min(arity) + } else { + arity + }; + let mut frame = CallFrame { function: val, arity, - stack_base: self.stack.len() - arity as usize - 1, + stack_base: self.stack.len() - arity as usize, ip: 0, }; @@ -972,11 +978,15 @@ impl Vm { let gathered_args = Vector::from(splatted_args); self.push(Value::List(Box::new(gathered_args))); } - let arity = splat_arity.min(arity); + let arity = if splat_arity > 0 { + splat_arity.min(arity) + } else { + arity + }; let mut frame = CallFrame { function: val, arity, - stack_base: self.stack.len() - arity as usize - 1, + stack_base: self.stack.len() - arity as usize, ip: 0, };