diff --git a/may_2025_thoughts.md b/may_2025_thoughts.md index 1864101..8ed5d12 100644 --- a/may_2025_thoughts.md +++ b/may_2025_thoughts.md @@ -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 diff --git a/sandbox.ld b/sandbox.ld index 2590afc..50a1a2d 100644 --- a/sandbox.ld +++ b/sandbox.ld @@ -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 () () diff --git a/src/compiler.rs b/src/compiler.rs index 424b094..9ec26c5 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -63,7 +63,7 @@ fn get_builtin(name: &str, arity: usize) -> Option { } #[derive(Debug, Clone)] -pub struct Compiler<'a> { +pub struct Compiler { pub chunk: Chunk, pub bindings: Vec, 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, tail_pos: bool, @@ -96,15 +96,15 @@ fn has_placeholder(args: &[Spanned]) -> bool { args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _))) } -impl<'a> Compiler<'a> { +impl Compiler { pub fn new( ast: &'static Spanned, 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, ); diff --git a/src/main.rs b/src/main.rs index a34dcd1..3b26244 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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");