fix upvalue resolution, hopefully for real this time

This commit is contained in:
Scott Richmond 2025-06-23 19:17:53 -04:00
parent 987cc172c1
commit f2bae26e1c
4 changed files with 30 additions and 20 deletions

View File

@ -499,3 +499,10 @@ Here's a list of things that need doing:
* Other forms in the language need help:
* [ ] repeat needs its stack discipline updated, it currently crashes the compiler
### More closure problems
#### 2025-06-23
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

View File

@ -1,6 +1,9 @@
let add = :foo
let nil? = :bar
let nil? = :foo
let mult = :bar
fn baz () -> (add, nil?)
fn foo () -> {
let fold = :baz
fn quux () -> (nil?, mult, fold)
}
baz()
foo () ()

View File

@ -63,7 +63,7 @@ fn get_builtin(name: &str, arity: usize) -> Option<Op> {
}
#[derive(Debug, Clone)]
pub struct Compiler<'a> {
pub struct Compiler {
pub chunk: Chunk,
pub bindings: Vec<Binding>,
pub scope_depth: isize,
@ -75,7 +75,7 @@ pub struct Compiler<'a> {
pub span: SimpleSpan,
pub src: &'static str,
pub name: &'static str,
pub enclosing: Option<&'a Compiler<'a>>,
pub depth: usize,
pub upvalues: Vec<&'static str>,
loop_info: Vec<LoopInfo>,
tail_pos: bool,
@ -96,15 +96,15 @@ fn has_placeholder(args: &[Spanned<Ast>]) -> bool {
args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _)))
}
impl<'a> Compiler<'a> {
impl Compiler {
pub fn new(
ast: &'static Spanned<Ast>,
name: &'static str,
src: &'static str,
enclosing: Option<&'a Compiler>,
depth: usize,
env: imbl::HashMap<&'static str, Value>,
debug: bool,
) -> Compiler<'a> {
) -> Compiler {
let chunk = Chunk {
constants: vec![],
bytecode: vec![],
@ -116,6 +116,7 @@ impl<'a> Compiler<'a> {
Compiler {
chunk,
bindings: vec![],
depth,
scope_depth: -1,
match_depth: 0,
stack_depth: 0,
@ -124,7 +125,6 @@ impl<'a> Compiler<'a> {
ast: &ast.0,
span: ast.1,
loop_info: vec![],
enclosing,
upvalues: vec![],
src,
name,
@ -297,17 +297,17 @@ impl<'a> Compiler<'a> {
self.stack_depth += 1;
return;
}
if self.chunk.env.contains_key(name) {
if self.depth == 0 {
self.msg("as global".to_string());
self.emit_constant(Value::Keyword(name));
self.emit_op(Op::PushGlobal);
return;
} else {
self.msg(format!("as enclosing upvalue {}", self.upvalues.len()));
self.emit_op(Op::GetUpvalue);
self.emit_byte(self.upvalues.len());
self.upvalues.push(name);
self.stack_depth += 1;
}
self.msg(format!("as enclosing upvalue {}", self.upvalues.len()));
self.emit_op(Op::GetUpvalue);
self.emit_byte(self.upvalues.len());
self.upvalues.push(name);
self.stack_depth += 1;
}
fn duplicate(&mut self) {
@ -1096,7 +1096,7 @@ impl<'a> Compiler<'a> {
clause,
name,
self.src,
Some(self),
self.depth + 1,
self.chunk.env.clone(),
self.debug,
);

View File

@ -73,7 +73,7 @@ pub fn prelude() -> HashMap<&'static str, Value> {
parsed,
"prelude",
PRELUDE,
None,
0,
HashMap::new(),
DEBUG_PRELUDE_COMPILE,
);
@ -124,7 +124,7 @@ pub fn run(src: &'static str) {
return;
}
let mut compiler = Compiler::new(parsed, "sandbox", src, None, prelude, DEBUG_SCRIPT_COMPILE);
let mut compiler = Compiler::new(parsed, "sandbox", src, 0, prelude, DEBUG_SCRIPT_COMPILE);
// let base = base::make_base();
// compiler.emit_constant(base);
// compiler.bind("base");