fix upvalue resolution, hopefully for real this time
This commit is contained in:
parent
987cc172c1
commit
f2bae26e1c
|
@ -499,3 +499,10 @@ Here's a list of things that need doing:
|
||||||
* Other forms in the language need help:
|
* Other forms in the language need help:
|
||||||
* [ ] repeat needs its stack discipline updated, it currently crashes the compiler
|
* [ ] 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
|
||||||
|
|
11
sandbox.ld
11
sandbox.ld
|
@ -1,6 +1,9 @@
|
||||||
let add = :foo
|
let nil? = :foo
|
||||||
let nil? = :bar
|
let mult = :bar
|
||||||
|
|
||||||
fn baz () -> (add, nil?)
|
fn foo () -> {
|
||||||
|
let fold = :baz
|
||||||
|
fn quux () -> (nil?, mult, fold)
|
||||||
|
}
|
||||||
|
|
||||||
baz()
|
foo () ()
|
||||||
|
|
|
@ -63,7 +63,7 @@ fn get_builtin(name: &str, arity: usize) -> Option<Op> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Compiler<'a> {
|
pub struct Compiler {
|
||||||
pub chunk: Chunk,
|
pub chunk: Chunk,
|
||||||
pub bindings: Vec<Binding>,
|
pub bindings: Vec<Binding>,
|
||||||
pub scope_depth: isize,
|
pub scope_depth: isize,
|
||||||
|
@ -75,7 +75,7 @@ pub struct Compiler<'a> {
|
||||||
pub span: SimpleSpan,
|
pub span: SimpleSpan,
|
||||||
pub src: &'static str,
|
pub src: &'static str,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub enclosing: Option<&'a Compiler<'a>>,
|
pub depth: usize,
|
||||||
pub upvalues: Vec<&'static str>,
|
pub upvalues: Vec<&'static str>,
|
||||||
loop_info: Vec<LoopInfo>,
|
loop_info: Vec<LoopInfo>,
|
||||||
tail_pos: bool,
|
tail_pos: bool,
|
||||||
|
@ -96,15 +96,15 @@ fn has_placeholder(args: &[Spanned<Ast>]) -> bool {
|
||||||
args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _)))
|
args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _)))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Compiler<'a> {
|
impl Compiler {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ast: &'static Spanned<Ast>,
|
ast: &'static Spanned<Ast>,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
src: &'static str,
|
src: &'static str,
|
||||||
enclosing: Option<&'a Compiler>,
|
depth: usize,
|
||||||
env: imbl::HashMap<&'static str, Value>,
|
env: imbl::HashMap<&'static str, Value>,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
) -> Compiler<'a> {
|
) -> Compiler {
|
||||||
let chunk = Chunk {
|
let chunk = Chunk {
|
||||||
constants: vec![],
|
constants: vec![],
|
||||||
bytecode: vec![],
|
bytecode: vec![],
|
||||||
|
@ -116,6 +116,7 @@ impl<'a> Compiler<'a> {
|
||||||
Compiler {
|
Compiler {
|
||||||
chunk,
|
chunk,
|
||||||
bindings: vec![],
|
bindings: vec![],
|
||||||
|
depth,
|
||||||
scope_depth: -1,
|
scope_depth: -1,
|
||||||
match_depth: 0,
|
match_depth: 0,
|
||||||
stack_depth: 0,
|
stack_depth: 0,
|
||||||
|
@ -124,7 +125,6 @@ impl<'a> Compiler<'a> {
|
||||||
ast: &ast.0,
|
ast: &ast.0,
|
||||||
span: ast.1,
|
span: ast.1,
|
||||||
loop_info: vec![],
|
loop_info: vec![],
|
||||||
enclosing,
|
|
||||||
upvalues: vec![],
|
upvalues: vec![],
|
||||||
src,
|
src,
|
||||||
name,
|
name,
|
||||||
|
@ -297,17 +297,17 @@ impl<'a> Compiler<'a> {
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.chunk.env.contains_key(name) {
|
if self.depth == 0 {
|
||||||
self.msg("as global".to_string());
|
self.msg("as global".to_string());
|
||||||
self.emit_constant(Value::Keyword(name));
|
self.emit_constant(Value::Keyword(name));
|
||||||
self.emit_op(Op::PushGlobal);
|
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) {
|
fn duplicate(&mut self) {
|
||||||
|
@ -1096,7 +1096,7 @@ impl<'a> Compiler<'a> {
|
||||||
clause,
|
clause,
|
||||||
name,
|
name,
|
||||||
self.src,
|
self.src,
|
||||||
Some(self),
|
self.depth + 1,
|
||||||
self.chunk.env.clone(),
|
self.chunk.env.clone(),
|
||||||
self.debug,
|
self.debug,
|
||||||
);
|
);
|
||||||
|
|
|
@ -73,7 +73,7 @@ pub fn prelude() -> HashMap<&'static str, Value> {
|
||||||
parsed,
|
parsed,
|
||||||
"prelude",
|
"prelude",
|
||||||
PRELUDE,
|
PRELUDE,
|
||||||
None,
|
0,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
DEBUG_PRELUDE_COMPILE,
|
DEBUG_PRELUDE_COMPILE,
|
||||||
);
|
);
|
||||||
|
@ -124,7 +124,7 @@ pub fn run(src: &'static str) {
|
||||||
return;
|
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();
|
// let base = base::make_base();
|
||||||
// compiler.emit_constant(base);
|
// compiler.emit_constant(base);
|
||||||
// compiler.bind("base");
|
// compiler.bind("base");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user