fix upvalue resolution for forward-declared functions

This commit is contained in:
Scott Richmond 2025-06-23 20:06:40 -04:00
parent f2bae26e1c
commit 42a5f599f7
5 changed files with 271 additions and 10542 deletions

View File

@ -968,8 +968,7 @@ fn err? {
fn unwrap! {
"Takes a result tuple. If it's :ok, then returns the value. If it's not :ok, then it panics. If it's not a result tuple, it also panics."
((:ok, value)) -> value
((:err, msg)) -> panic! string ("Unwrapped :err! ", msg)
(_) -> panic! "Cannot unwrap something that's not an error tuple."
((:err, msg)) -> panic! "Unwrapped :err! {msg}"
}
fn unwrap_or {

View File

@ -494,6 +494,7 @@ Here's a list of things that need doing:
- I need this fixed for optimization reasons.
- I _think_ I just fixed this by fixing tail position tracking in collections
- [ ] test this
- I did not fix it.
* [x] Dict patterns are giving me stack discipline grief. Why is stack discipline so hard?
* [ ] This is in the service of getting turtle graphics working
* Other forms in the language need help:
@ -505,4 +506,15 @@ My solution to closures wasn't quite right.
I can't use Uncle Bob's strategy of the recursive call, since Rust's ownership semantics make this onerous at best.
My solution: introduce the concept of a "compiler depth," with 0 being the global scope.
If the compiler's at 0 depth, we can pull it out of the environment.
If the compiler's at a depth > 0, then we can ask the enclosing
If the compiler's at a depth > 0, then we can ask the enclosing compiler to stash the upvalue.
And thus we get what we need.
But: some functions in prelude aren't properly getting their closures, and I don't know why, since they *are* getting them properly in user scripts.
Take `apply_command`.
Next step: sort out if any other functions aren't getting things closed over properly.
PROBLEM: forward-declared functions weren't at the top of the stack when `Op::SetUpvalue` was called.
So all of `apply_command`'s upvalues were being attached to the function declared before it (which was sitting right there at the top of the stack.)
SOLUTION: test to see if the function has been forward-declared, and if it has, bring it to the top fo the stack.

View File

@ -1,9 +1,2 @@
let nil? = :foo
let mult = :bar
fn foo () -> {
let fold = :baz
fn quux () -> (nil?, mult, fold)
}
foo () ()
let state = unbox (turtle_state)
apply_command(state, (:penup))

File diff suppressed because it is too large Load Diff

View File

@ -1197,7 +1197,6 @@ impl Compiler {
closed: RefCell::new(vec![]),
};
// 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);
@ -1219,6 +1218,10 @@ impl Compiler {
})
.unwrap();
self.chunk.constants[declaration_idx] = the_fn;
// if the function been forward-declared, bring it to the top of the stack
if declaration_idx < self.chunk.constants.len() - 1 {
self.resolve_binding(name);
}
} else {
self.emit_constant(the_fn)
}