a slow and brute-force approach to the problem of re-binding closed-over forward declarations

This commit is contained in:
Scott Richmond 2024-12-12 01:19:39 -05:00
parent 5e73c5cb3b
commit 273267f61d
4 changed files with 62 additions and 28 deletions

View File

@ -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> { pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
match f { match f {
Value::Fn(f) => { Value::Fn(f) => {
let name = &f.name; let name = &f.borrow().name;
let doc = &f.doc; let doc = &f.borrow().doc;
if let Some(docstr) = doc { if let Some(docstr) = doc {
Value::AllocatedString(Rc::new(format!("{name}: {docstr}"))) Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
} else { } else {
@ -384,6 +384,7 @@ pub fn r#type<'src>(x: &Value<'src>) -> Value<'src> {
Value::Args(_) => unreachable!("internal Ludus error"), Value::Args(_) => unreachable!("internal Ludus error"),
Value::Base(_) => Value::Keyword("fn"), Value::Base(_) => Value::Keyword("fn"),
Value::Recur(..) => unreachable!("internal Ludus error"), Value::Recur(..) => unreachable!("internal Ludus error"),
Value::FnDecl(_) => Value::Keyword("fn"),
} }
} }

View File

@ -185,16 +185,15 @@ pub fn run(src: &'static str) {
pub fn main() { pub fn main() {
let src = " let src = "
fn foo () -> { fn bar
let 12 = 34 fn foo () -> {:foo}
}
let quux = foo let quux = foo
let fuzz = :asdf let fuzz = :asdf
fn bar () -> quux () fn baz (...) -> bar ()
fn baz (...) -> bar (fuzz)
fn bar () -> quux ()
baz (1, 2, 3) baz (1, 2, 3)
"; ";
run(src); run(src);

View File

@ -249,18 +249,27 @@ impl<'src> Process<'src> {
// can't just use the `caller` value b/c borrow checker nonsense // can't just use the `caller` value b/c borrow checker nonsense
let args = Tuple(args); let args = Tuple(args);
let to = self.locals.len(); 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(); let mut enclosing = f.enclosing.clone();
self.locals.append(&mut enclosing); self.locals.append(&mut enclosing);
let result = self.match_clauses(&args, f.body); let result = self.match_clauses(&args, f.body);
self.locals.truncate(to); 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 result
} }
// TODO: partially applied functions shnould work! In #15 // TODO: partially applied functions shnould work! In #15
@ -479,16 +488,35 @@ impl<'src> Process<'src> {
.filter(|binding| binding != name) .filter(|binding| binding != name)
.map(|binding| (binding.clone(), self.resolve(binding).unwrap().clone())) .map(|binding| (binding.clone(), self.resolve(binding).unwrap().clone()))
.collect(); .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(), name: name.to_string(),
body: clauses, body: clauses,
doc, doc,
enclosing, 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) 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) => { Panic(msg) => {
let msg = self.visit(msg)?; let msg = self.visit(msg)?;
self.panic(format!("{msg}")) self.panic(format!("{msg}"))

View File

@ -30,7 +30,8 @@ pub enum Value<'src> {
List(Vector<Self>), List(Vector<Self>),
Dict(HashMap<&'static str, Self>), Dict(HashMap<&'static str, Self>),
Box(&'static str, Rc<RefCell<Self>>), Box(&'static str, Rc<RefCell<Self>>),
Fn(Rc<Fn<'src>>), Fn(Rc<RefCell<Fn<'src>>>),
FnDecl(&'static str),
Base(BaseFn<'src>), Base(BaseFn<'src>),
Recur(Vec<Self>), Recur(Vec<Self>),
// Set(HashSet<Self>), // Set(HashSet<Self>),
@ -57,6 +58,7 @@ impl<'src> Clone for Value<'src> {
Value::Tuple(t) => Value::Tuple(t.clone()), Value::Tuple(t) => Value::Tuple(t.clone()),
Value::Args(a) => Value::Args(a.clone()), Value::Args(a) => Value::Args(a.clone()),
Value::Fn(f) => Value::Fn(f.clone()), Value::Fn(f) => Value::Fn(f.clone()),
Value::FnDecl(name) => Value::FnDecl(name),
Value::List(l) => Value::List(l.clone()), Value::List(l) => Value::List(l.clone()),
Value::Dict(d) => Value::Dict(d.clone()), Value::Dict(d) => Value::Dict(d.clone()),
Value::Box(name, b) => Value::Box(name, b.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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Value::Nil => write!(f, "nil"), Value::Nil => write!(f, "nil"),
Value::Boolean(b) => write!(f, "{}", b), Value::Boolean(b) => write!(f, "{b}"),
Value::Number(n) => write!(f, "{}", n), Value::Number(n) => write!(f, "{n}"),
Value::Keyword(k) => write!(f, ":{}", k), Value::Keyword(k) => write!(f, ":{k}"),
Value::InternedString(s) => write!(f, "\"{}\"", s), Value::InternedString(s) => write!(f, "\"{s}\""),
Value::AllocatedString(s) => write!(f, "\"{}\"", s), Value::AllocatedString(s) => write!(f, "\"{s}\""),
Value::Fn(fun) => write!(f, "fn {}", fun.name), Value::Fn(fun) => write!(f, "fn {}", fun.borrow().name),
Value::FnDecl(name) => write!(f, "fn {name}"),
Value::Tuple(t) | Value::Args(t) => write!( Value::Tuple(t) | Value::Args(t) => write!(
f, f,
"({})", "({})",
@ -138,7 +141,9 @@ impl<'src> PartialEq for Value<'src> {
(Value::List(x), Value::List(y)) => x == y, (Value::List(x), Value::List(y)) => x == y,
(Value::Dict(x), Value::Dict(y)) => x == y, (Value::Dict(x), Value::Dict(y)) => x == y,
// reference equality types // reference equality types
(Value::Fn(x), Value::Fn(y)) => Rc::<Fn<'_>>::as_ptr(x) == Rc::<Fn<'_>>::as_ptr(y), (Value::Fn(x), Value::Fn(y)) => {
Rc::<RefCell<Fn<'_>>>::as_ptr(x) == Rc::<RefCell<Fn<'_>>>::as_ptr(y)
}
(Value::Box(_, x), Value::Box(_, y)) => { (Value::Box(_, x), Value::Box(_, y)) => {
Rc::<RefCell<Value<'_>>>::as_ptr(x) == Rc::<RefCell<Value<'_>>>::as_ptr(y) Rc::<RefCell<Value<'_>>>::as_ptr(x) == Rc::<RefCell<Value<'_>>>::as_ptr(y)
} }
@ -174,7 +179,8 @@ impl Value<'_> {
.map(|(k, v)| format!(":{} {}", k, v.interpolate())) .map(|(k, v)| format!(":{} {}", k, v.interpolate()))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "), .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::Placeholder => unreachable!(),
Value::Args(_) => unreachable!(), Value::Args(_) => unreachable!(),
Value::Recur(_) => unreachable!(), Value::Recur(_) => unreachable!(),