recursion works, so does mutual recursion; function call bugfixes
This commit is contained in:
parent
f4ade4938c
commit
e580d68809
|
@ -367,7 +367,7 @@ fn is_binding(expr: &Spanned<Ast>) -> bool {
|
||||||
let (ast, _) = expr;
|
let (ast, _) = expr;
|
||||||
use Ast::*;
|
use Ast::*;
|
||||||
match ast {
|
match ast {
|
||||||
Let(..) | LBox(..) => true,
|
Let(..) | LBox(..) | FnDeclaration(..) => true,
|
||||||
Fn(name, ..) => !name.is_empty(),
|
Fn(name, ..) => !name.is_empty(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -1209,7 +1209,19 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
MatchClause(..) => unreachable!(),
|
MatchClause(..) => unreachable!(),
|
||||||
Fn(name, body, doc) => {
|
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 {
|
let FnBody(fn_body) = &body.as_ref().0 else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -1268,8 +1280,8 @@ impl<'a> Compiler<'a> {
|
||||||
for idx in tup_jump_idxes {
|
for idx in tup_jump_idxes {
|
||||||
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
||||||
}
|
}
|
||||||
compiler.emit_op(Op::PopN);
|
// compiler.emit_op(Op::PopN);
|
||||||
compiler.emit_byte(arity as usize);
|
// compiler.emit_byte(arity as usize);
|
||||||
compiler.patch_jump(jump_idx, compiler.len() - jump_idx - 3);
|
compiler.patch_jump(jump_idx, compiler.len() - jump_idx - 3);
|
||||||
let mut no_match_jumps = vec![];
|
let mut no_match_jumps = vec![];
|
||||||
no_match_jumps.push(compiler.stub_jump(Op::JumpIfNoMatch));
|
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
|
// 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));
|
let the_fn = Value::Fn(Rc::new(lfn));
|
||||||
self.emit_constant(the_fn);
|
// self.emit_constant(the_fn);
|
||||||
self.bind(name);
|
// 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 {
|
for upvalue in upvalues {
|
||||||
self.emit_op(Op::SetUpvalue);
|
self.emit_op(Op::SetUpvalue);
|
||||||
|
|
|
@ -75,7 +75,11 @@ pub fn run(src: &'static str) {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
let src = "
|
let src = "
|
||||||
|
fn two
|
||||||
|
fn one (x, y) -> two (x, y)
|
||||||
|
fn two (:foo, x) -> (:done, x)
|
||||||
|
|
||||||
|
one (:fool, :bar)
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
}
|
}
|
||||||
|
|
18
src/vm.rs
18
src/vm.rs
|
@ -872,6 +872,7 @@ impl Vm {
|
||||||
for i in 0..arity as usize {
|
for i in 0..arity as usize {
|
||||||
self.return_register[arity as usize - i - 1] = self.pop();
|
self.return_register[arity as usize - i - 1] = self.pop();
|
||||||
}
|
}
|
||||||
|
self.print_stack();
|
||||||
|
|
||||||
// then pop everything back to the current stack frame
|
// then pop everything back to the current stack frame
|
||||||
self.stack.truncate(self.frame.stack_base);
|
self.stack.truncate(self.frame.stack_base);
|
||||||
|
@ -892,11 +893,16 @@ impl Vm {
|
||||||
let gathered_args = Vector::from(splatted_args);
|
let gathered_args = Vector::from(splatted_args);
|
||||||
self.push(Value::List(Box::new(gathered_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 {
|
let mut frame = CallFrame {
|
||||||
function: val,
|
function: val,
|
||||||
arity,
|
arity,
|
||||||
stack_base: self.stack.len() - arity as usize - 1,
|
stack_base: self.stack.len() - arity as usize,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -972,11 +978,15 @@ impl Vm {
|
||||||
let gathered_args = Vector::from(splatted_args);
|
let gathered_args = Vector::from(splatted_args);
|
||||||
self.push(Value::List(Box::new(gathered_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 {
|
let mut frame = CallFrame {
|
||||||
function: val,
|
function: val,
|
||||||
arity,
|
arity,
|
||||||
stack_base: self.stack.len() - arity as usize - 1,
|
stack_base: self.stack.len() - arity as usize,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user