diff --git a/assets/test_prelude.ld b/assets/test_prelude.ld index d0a15e7..8421ee9 100644 --- a/assets/test_prelude.ld +++ b/assets/test_prelude.ld @@ -1,5 +1,13 @@ -base :print! ("Hello from Prelude") +& base :print! ("Hello from Prelude") -fn add (x, y) -> base :add (x, y) +& I can't figure out why I need this, but I do +& Otherwise the validator won't close over `base` +let base = base -#{add} +fn add (x as :number, y as :number) -> base :add (x, y) + +fn dec (n as :number) -> base :sub (n, 1) + +fn sub (x as :number, y as :number) -> base :sub (x, y) + +#{add, dec, sub} diff --git a/src/main.rs b/src/main.rs index 52868d0..1273882 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,11 +95,12 @@ pub fn prelude<'src>() -> Process<'src> { let mut v6or = Validator::new(p_ast, *p_span, &base_names); v6or.validate(); + // dbg!(&v6or); + let mut base_ctx = Process::<'src> { - locals: vec![], + locals: base_pkg, ast: p_ast, - prelude: base_pkg, - args: Value::Nil, + prelude: vec![], fn_info: v6or.fn_info, }; @@ -128,7 +129,6 @@ pub fn prelude<'src>() -> Process<'src> { locals: vec![], ast: &Ast::Nil, prelude: p_ctx, - args: Value::Nil, fn_info: base_ctx.fn_info, } } @@ -158,10 +158,12 @@ pub fn run(src: &'static str) { v6or.validate(); - dbg!(&v6or); + // dbg!(&v6or); + // dbg!(&v6or.fn_info); let mut proc = prelude(); proc.ast = * + // dbg!(&proc.fn_info); proc.fn_info.extend(&mut v6or.fn_info.into_iter()); let result = proc.eval(); @@ -174,9 +176,16 @@ pub fn run(src: &'static str) { pub fn main() { let src = " -let bar = :bar -fn foo () -> bar -foo () +fn fib { + (1) -> 1 + (2) -> 1 + (n) -> add ( + fib (dec (n)) + fib (sub (n, 2)) + ) +} + +fib (25) "; run(src); // struct_scalpel::print_dissection_info::() diff --git a/src/process.rs b/src/process.rs index d53f356..4e35a4c 100644 --- a/src/process.rs +++ b/src/process.rs @@ -35,7 +35,6 @@ pub struct Process<'src> { pub locals: Vec<(String, Value<'src>)>, pub prelude: Vec<(String, Value<'src>)>, pub ast: &'src Ast, - pub args: Value<'src>, pub fn_info: std::collections::HashMap<*const Ast, FnInfo>, } @@ -502,16 +501,17 @@ impl<'src> Process<'src> { Fn(name, clauses, doc) => { let doc = doc.map(|s| s.to_string()); let ptr: *const Ast = root; - dbg!(&root); - dbg!(&ptr); - dbg!(&self.fn_info); + // dbg!(&root); + // dbg!(&ptr); + // dbg!(&self.fn_info); let info = self.fn_info.get(&ptr).unwrap(); - let FnInfo::Defined(_, enclosing) = info else { + let FnInfo::Defined(_, _, enclosing) = info else { unreachable!() }; let enclosing = enclosing .iter() - .map(|name| (name.clone(), self.resolve(name).unwrap().clone())) + .filter(|binding| binding != name) + .map(|binding| (binding.clone(), self.resolve(binding).unwrap().clone())) .collect(); let the_fn = Value::Fn::<'src>(Rc::new(crate::value::Fn::<'src> { name: name.to_string(), diff --git a/src/validator.rs b/src/validator.rs index 538e3ff..f05cee7 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -33,7 +33,7 @@ pub enum Arity { #[derive(Clone, Debug, PartialEq, Eq)] pub enum FnInfo { Declared, - Defined(HashSet, HashSet), + Defined(String, HashSet, HashSet), Unknown, } @@ -130,7 +130,7 @@ impl<'a> Validator<'a> { let root = self.ast; match root { Error => unreachable!(), - Word(name) | Ast::Splat(name) => { + Word(name) | Splat(name) => { if !self.resolved(name) { self.err(format!("unbound name `{name}`")) } else { @@ -309,7 +309,7 @@ impl<'a> Validator<'a> { //TODO: check arities of prelude fns, too let fn_binding = self.bound(name); - if let Some((_, _, FnInfo::Defined(arities, _))) = fn_binding { + if let Some((_, _, FnInfo::Defined(_, arities, _))) = fn_binding { let num_args = args.len(); if !match_arities(arities, num_args as u8) { self.err(format!("arity mismatch: no clause in function `{name}` with {num_args} argument(s)")) @@ -453,11 +453,12 @@ impl<'a> Validator<'a> { let mut closed_over = HashSet::new(); for binding in self.status.used_bindings.iter().skip(from) { if self.bound(binding.as_str()).is_some() { + // println!("{name} closing over {binding}"); closed_over.insert(binding.clone()); } } - let info = FnInfo::Defined(arities, closed_over); + let info = FnInfo::Defined(name.to_string(), arities, closed_over); let root_ptr: *const Ast = root;