a slow and brute-force approach to the problem of re-binding closed-over forward declarations
This commit is contained in:
parent
5e73c5cb3b
commit
273267f61d
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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}"))
|
||||||
|
|
24
src/value.rs
24
src/value.rs
|
@ -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!(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user