diff --git a/src/base.rs b/src/base.rs index 687401a..edee9a7 100644 --- a/src/base.rs +++ b/src/base.rs @@ -50,8 +50,8 @@ pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> Value<'src> { pub fn doc<'src>(f: &Value<'src>) -> Value<'src> { match f { Value::Fn(f) => { - let name = &f.name; - let doc = &f.doc; + let name = &f.borrow().name; + let doc = &f.borrow().doc; if let Some(docstr) = doc { Value::AllocatedString(Rc::new(format!("{name}: {docstr}"))) } else { @@ -384,6 +384,7 @@ pub fn r#type<'src>(x: &Value<'src>) -> Value<'src> { Value::Args(_) => unreachable!("internal Ludus error"), Value::Base(_) => Value::Keyword("fn"), Value::Recur(..) => unreachable!("internal Ludus error"), + Value::FnDecl(_) => Value::Keyword("fn"), } } diff --git a/src/main.rs b/src/main.rs index 6396abe..0784892 100644 --- a/src/main.rs +++ b/src/main.rs @@ -185,16 +185,15 @@ pub fn run(src: &'static str) { pub fn main() { let src = " -fn foo () -> { - let 12 = 34 -} +fn bar +fn foo () -> {:foo} let quux = foo let fuzz = :asdf -fn bar () -> quux () -fn baz (...) -> bar (fuzz) +fn baz (...) -> bar () +fn bar () -> quux () baz (1, 2, 3) "; run(src); diff --git a/src/process.rs b/src/process.rs index 069f162..177a9a8 100644 --- a/src/process.rs +++ b/src/process.rs @@ -249,18 +249,27 @@ impl<'src> Process<'src> { // can't just use the `caller` value b/c borrow checker nonsense let args = Tuple(args); let to = self.locals.len(); + let mut f = f.borrow_mut(); + for i in 0..f.enclosing.len() { + let (name, value) = f.enclosing[i].clone(); + if matches!(value, Value::FnDecl(_)) { + let defined = self.resolve(&name); + match defined { + Ok(Value::Fn(defined)) => f.enclosing[i] = (name.clone(), Fn(defined)), + Ok(Value::FnDecl(_)) => { + return self.panic(format!( + "function `{name}` called before it was defined" + )) + } + + _ => unreachable!("internal Ludus error"), + } + } + } let mut enclosing = f.enclosing.clone(); self.locals.append(&mut enclosing); let result = self.match_clauses(&args, f.body); self.locals.truncate(to); - // match result { - // Err(mut err) => { - // let r#fn = Fn(f); - // err.trace.push(r#fn); - // Err(err) - // } - // Ok(res) => Ok(res), - // } result } // TODO: partially applied functions shnould work! In #15 @@ -479,16 +488,35 @@ impl<'src> Process<'src> { .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> { + let the_fn = Value::Fn::<'src>(Rc::new(RefCell::new(crate::value::Fn::<'src> { name: name.to_string(), body: clauses, doc, enclosing, - })); - self.bind(name.to_string(), &the_fn); + }))); + + let maybe_decl_i = self.locals.iter().position(|(binding, _)| binding == name); + + match maybe_decl_i { + None => self.bind(name.to_string(), &the_fn), + Some(i) => { + let declared = &self.locals[i].1; + match declared { + Value::FnDecl(_) => { + self.locals[i] = (name.to_string(), the_fn.clone()); + } + _ => unreachable!("internal Ludus error"), + } + } + } + Ok(the_fn) } - FnDeclaration(_name) => Ok(Value::Nil), + FnDeclaration(name) => { + let decl = Value::FnDecl(name); + self.bind(name.to_string(), &decl); + Ok(decl) + } Panic(msg) => { let msg = self.visit(msg)?; self.panic(format!("{msg}")) diff --git a/src/value.rs b/src/value.rs index 07e671b..5490547 100644 --- a/src/value.rs +++ b/src/value.rs @@ -30,7 +30,8 @@ pub enum Value<'src> { List(Vector), Dict(HashMap<&'static str, Self>), Box(&'static str, Rc>), - Fn(Rc>), + Fn(Rc>>), + FnDecl(&'static str), Base(BaseFn<'src>), Recur(Vec), // Set(HashSet), @@ -57,6 +58,7 @@ impl<'src> Clone for Value<'src> { Value::Tuple(t) => Value::Tuple(t.clone()), Value::Args(a) => Value::Args(a.clone()), Value::Fn(f) => Value::Fn(f.clone()), + Value::FnDecl(name) => Value::FnDecl(name), Value::List(l) => Value::List(l.clone()), Value::Dict(d) => Value::Dict(d.clone()), Value::Box(name, b) => Value::Box(name, b.clone()), @@ -71,12 +73,13 @@ impl fmt::Display for Value<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Value::Nil => write!(f, "nil"), - Value::Boolean(b) => write!(f, "{}", b), - Value::Number(n) => write!(f, "{}", n), - Value::Keyword(k) => write!(f, ":{}", k), - Value::InternedString(s) => write!(f, "\"{}\"", s), - Value::AllocatedString(s) => write!(f, "\"{}\"", s), - Value::Fn(fun) => write!(f, "fn {}", fun.name), + Value::Boolean(b) => write!(f, "{b}"), + Value::Number(n) => write!(f, "{n}"), + Value::Keyword(k) => write!(f, ":{k}"), + Value::InternedString(s) => write!(f, "\"{s}\""), + Value::AllocatedString(s) => write!(f, "\"{s}\""), + Value::Fn(fun) => write!(f, "fn {}", fun.borrow().name), + Value::FnDecl(name) => write!(f, "fn {name}"), Value::Tuple(t) | Value::Args(t) => write!( f, "({})", @@ -138,7 +141,9 @@ impl<'src> PartialEq for Value<'src> { (Value::List(x), Value::List(y)) => x == y, (Value::Dict(x), Value::Dict(y)) => x == y, // reference equality types - (Value::Fn(x), Value::Fn(y)) => Rc::>::as_ptr(x) == Rc::>::as_ptr(y), + (Value::Fn(x), Value::Fn(y)) => { + Rc::>>::as_ptr(x) == Rc::>>::as_ptr(y) + } (Value::Box(_, x), Value::Box(_, y)) => { Rc::>>::as_ptr(x) == Rc::>>::as_ptr(y) } @@ -174,7 +179,8 @@ impl Value<'_> { .map(|(k, v)| format!(":{} {}", k, v.interpolate())) .collect::>() .join(", "), - Value::Fn(x) => format!("fn {}", x.name), + Value::Fn(x) => format!("fn {}", x.borrow().name), + Value::FnDecl(name) => format!("fn {name}"), Value::Placeholder => unreachable!(), Value::Args(_) => unreachable!(), Value::Recur(_) => unreachable!(),