diff --git a/may_2025_thoughts.md b/may_2025_thoughts.md index 3c15c47..e78570a 100644 --- a/may_2025_thoughts.md +++ b/may_2025_thoughts.md @@ -296,14 +296,14 @@ _Edited to add: all the above is, I think, fixed._ #### Later So this is my near-term TODO: -* [ ] recursive calls - - [ ] direct recursive calls - * [ ] stash a function declaration before compiling the function, hang onto that declaration - * [ ] update that declaration to a definition after compiling the function - - [ ] mutual recursive - * [ ] check to make sure a function has already been declared, hang onto that declaration - * [ ] update that declaration to a definition after compiling the function... - * [ ] but BEFORE we close over any upvalues, so the function will be an upvalue for itself +* [x] recursive calls + - [x] direct recursive calls + * [x] stash a function declaration before compiling the function, hang onto that declaration + * [x] update that declaration to a definition after compiling the function + - [x] mutual recursive + * [x] check to make sure a function has already been declared, hang onto that declaration + * [x] update that declaration to a definition after compiling the function... + * [x] but BEFORE we close over any upvalues, so the function will be an upvalue for itself - I suspect this can be done not using anything other than an index into a chunk's `constants` vec--no fancy memory swapping or anything; and also--done in the compiler rather than the VM. * [ ] getting to prelude - [ ] `base` should load into Prelude diff --git a/src/base.rs b/src/base.rs index b3f2f88..405f9f8 100644 --- a/src/base.rs +++ b/src/base.rs @@ -61,7 +61,7 @@ pub fn doc(f: &Value) -> Value { pub fn assoc(dict: &Value, key: &Value, value: &Value) -> Value { match (dict, key) { (Value::Dict(d), Value::Keyword(k)) => Value::Dict(Box::new(d.update(k, value.clone()))), - _ => unreachable!("internal Ludus error"), + _ => unreachable!("internal Ludus error calling assoc with ({dict}, {key}, {value})"), } } @@ -579,7 +579,7 @@ pub fn r#mod(x: &Value, y: &Value) -> Value { } } -pub fn base() -> Value { +pub fn make_base() -> Value { let members = vec![ ("add", Value::BaseFn(BaseFn::Binary(add))), ("append", Value::BaseFn(BaseFn::Binary(append))), diff --git a/src/compiler.rs b/src/compiler.rs index 930a637..b097383 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -443,7 +443,7 @@ impl<'a> Compiler<'a> { self.chunk.bytecode[i + 2] = low; } - fn emit_constant(&mut self, val: Value) { + pub fn emit_constant(&mut self, val: Value) { let const_idx = if let Some(idx) = self.chunk.constants.iter().position(|v| *v == val) { idx } else { @@ -494,7 +494,7 @@ impl<'a> Compiler<'a> { self.chunk.bytecode.len() } - fn bind(&mut self, name: &'static str) { + pub fn bind(&mut self, name: &'static str) { let binding = Binding { name, depth: self.scope_depth, diff --git a/src/main.rs b/src/main.rs index c3ac9f4..ff2b3a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,7 +47,12 @@ pub fn run(src: &'static str) { // in any event, the AST should live forever let parsed: &'static Spanned = Box::leak(Box::new(parse_result.unwrap())); + let base = base::make_base(); + let mut compiler = Compiler::new(parsed, "test", src, None); + compiler.emit_constant(base); + compiler.bind("base"); + compiler.compile(); if DEBUG_COMPILE { println!("=== source code ==="); @@ -75,11 +80,7 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " -fn two -fn one (x, y) -> two (x, y) -fn two (:foo, x) -> (:done, x) - -one (:fool, :bar) +base :assoc (#{:a 1}, :b, 2) "; run(src); } diff --git a/src/vm.rs b/src/vm.rs index 3d33dd1..b61f78e 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1004,8 +1004,17 @@ impl Vm { let value = match (arity, base_fn) { (0, BaseFn::Nullary(f)) => f(), (1, BaseFn::Unary(f)) => f(&self.pop()), - (2, BaseFn::Binary(f)) => f(&self.pop(), &self.pop()), - (3, BaseFn::Ternary(f)) => f(&self.pop(), &self.pop(), &self.pop()), + (2, BaseFn::Binary(f)) => { + let y = &self.pop(); + let x = &self.pop(); + f(x, y) + } + (3, BaseFn::Ternary(f)) => { + let z = &self.pop(); + let y = &self.pop(); + let x = &self.pop(); + f(x, y, z) + } _ => return self.panic("internal ludus error"), }; self.push(value);