Compare commits

..

2 Commits

Author SHA1 Message Date
Scott Richmond
273267f61d a slow and brute-force approach to the problem of re-binding closed-over forward declarations 2024-12-12 01:19:39 -05:00
Scott Richmond
5e73c5cb3b ariadne hooked up to panic messages 2024-12-12 00:31:57 -05:00
4 changed files with 122 additions and 61 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> {
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"),
}
}

View File

@ -59,6 +59,9 @@ use crate::validator::*;
mod process;
use crate::process::*;
mod errors;
use crate::errors::*;
#[derive(Embed)]
#[folder = "assets/"]
struct Asset;
@ -176,17 +179,22 @@ pub fn run(src: &'static str) {
match result {
Ok(result) => println!("{}", result),
Err(LErr { msg, .. }) => println!("Ludus panicked!\n{}", msg),
Err(err) => report_panic(err, src),
}
}
pub fn main() {
let src = "
let guard = :nil
match :foo with {
:foo if guard -> :guarded
_ -> :unguarded
}
fn bar
fn foo () -> {:foo}
let quux = foo
let fuzz = :asdf
fn baz (...) -> bar ()
fn bar () -> quux ()
baz (1, 2, 3)
";
run(src);
// struct_scalpel::print_dissection_info::<value::Value>()

View File

@ -10,26 +10,23 @@ use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
pub struct LErr {
pub struct LErr<'src> {
pub msg: String,
pub trace: Vec<String>,
pub span: SimpleSpan,
pub trace: Vec<(Spanned<Ast>, Spanned<Ast>, Value<'src>, Value<'src>)>,
}
impl LErr {
pub fn new(msg: String) -> LErr {
impl<'src> LErr<'src> {
pub fn new(msg: String, span: SimpleSpan) -> LErr<'src> {
LErr {
msg: msg.to_string(),
msg,
span,
trace: vec![],
}
}
pub fn add_trace(mut self, fn_name: String) -> LErr {
self.trace.push(fn_name);
self
}
}
type LResult<'src> = Result<Value<'src>, LErr>;
type LResult<'src> = Result<Value<'src>, LErr<'src>>;
#[derive(Debug)]
pub struct Process<'src> {
@ -50,12 +47,16 @@ impl<'src> Process<'src> {
let resolved_prelude = self.prelude.iter().rev().find(|(name, _)| word == name);
match resolved_prelude {
Some((_, value)) => Ok(value.clone()),
None => Err(LErr::new(format!("unbound name {word}"))),
None => Err(LErr::new(format!("unbound name `{word}`"), self.span)),
}
}
}
}
pub fn panic(&self, msg: String) -> LResult<'src> {
Err(LErr::new(msg, self.span))
}
pub fn bind(&mut self, word: String, value: &Value<'src>) {
self.locals.push((word, value.clone()));
}
@ -223,7 +224,7 @@ impl<'src> Process<'src> {
return result;
}
}
Err(LErr::new("no match".to_string()))
self.panic("no match".to_string())
}
}
@ -245,8 +246,26 @@ impl<'src> Process<'src> {
}
}
(Fn(f), Tuple(args)) => {
// 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);
@ -256,14 +275,15 @@ impl<'src> Process<'src> {
// TODO: partially applied functions shnould work! In #15
(Fn(_f), Args(_args)) => todo!(),
(_, Keyword(_)) => Ok(Nil),
(_, Args(_)) => Err(LErr::new("you may only call a function".to_string())),
(_, Args(_)) => Err(LErr::new(
"you may only call a function".to_string(),
self.span,
)),
(Base(f), Tuple(args)) => match f {
BaseFn::Nullary(f) => {
let num_args = args.len();
if num_args != 0 {
Err(LErr::new(format!(
"wrong arity: expected 0 arguments, got {num_args}"
)))
self.panic(format!("wrong arity: expected 0 arguments, got {num_args}"))
} else {
Ok(f())
}
@ -271,9 +291,7 @@ impl<'src> Process<'src> {
BaseFn::Unary(f) => {
let num_args = args.len();
if num_args != 1 {
Err(LErr::new(format!(
"wrong arity: expected 1 argument, got {num_args}"
)))
self.panic(format!("wrong arity: expected 1 argument, got {num_args}"))
} else {
Ok(f(&args[0]))
}
@ -281,9 +299,7 @@ impl<'src> Process<'src> {
BaseFn::Binary(r#fn) => {
let num_args = args.len();
if num_args != 2 {
Err(LErr::new(format!(
"wrong arity: expected 2 arguments, got {num_args}"
)))
self.panic(format!("wrong arity: expected 2 arguments, got {num_args}"))
} else {
Ok(r#fn(&args[0], &args[1]))
}
@ -291,9 +307,7 @@ impl<'src> Process<'src> {
BaseFn::Ternary(f) => {
let num_args = args.len();
if num_args != 3 {
Err(LErr::new(format!(
"wrong arity: expected 3 arguments, got {num_args}"
)))
self.panic(format!("wrong arity: expected 3 arguments, got {num_args}"))
} else {
Ok(f(&args[0], &args[1], &args[2]))
}
@ -355,9 +369,8 @@ impl<'src> Process<'src> {
Ast::Splat(_) => match member_value {
Value::List(list) => vect.append(list),
_ => {
return Err(LErr::new(
"only lists may be splatted into lists".to_string(),
))
return self
.panic("only lists may be splatted into lists".to_string())
}
},
_ => vect.push_back(member_value),
@ -380,7 +393,7 @@ impl<'src> Process<'src> {
let val = self.visit(expr)?;
let result = match self.match_pattern(&patt.0, &val) {
Some(_) => Ok(val),
None => Err(LErr::new("no match".to_string())),
None => self.panic("no match".to_string()),
};
result
}
@ -407,9 +420,7 @@ impl<'src> Process<'src> {
(Ast::Splat(_), _) => {
let resolved = self.visit(term)?;
let Value::Dict(to_splat) = resolved else {
return Err(LErr::new(
"cannot splat non-dict into dict".to_string(),
));
return self.panic("cannot splat non-dict into dict".to_string());
};
dict = to_splat.union(dict);
}
@ -427,12 +438,28 @@ impl<'src> Process<'src> {
Synthetic(root, first, rest) => {
let root_val = self.visit(root)?;
let first_val = self.visit(first)?;
let mut curr = self.apply(root_val, first_val)?;
let mut result = self.apply(root_val.clone(), first_val.clone());
if let Err(mut err) = result {
err.trace
.push((*root.clone(), *first.clone(), root_val, first_val));
return Err(err);
};
let mut prev_node;
let mut this_node = first.as_ref();
for term in rest.iter() {
let next = self.visit(term)?;
curr = self.apply(curr, next)?;
prev_node = this_node;
this_node = term;
let caller = self.visit(term)?;
let callee = result.unwrap();
result = self.apply(callee.clone(), caller.clone());
if let Err(mut err) = result {
err.trace
.push((prev_node.clone(), this_node.clone(), caller, callee));
return Err(err);
}
}
Ok(curr)
result
}
When(clauses) => {
for clause in clauses.iter() {
@ -443,7 +470,7 @@ impl<'src> Process<'src> {
return self.visit(body);
};
}
Err(LErr::new("no match".to_string()))
self.panic("no match".to_string())
}
Match(scrutinee, clauses) => {
let value = self.visit(scrutinee)?;
@ -461,24 +488,43 @@ 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)?;
Err(LErr::new(format!("{msg}")))
self.panic(format!("{msg}"))
}
Repeat(times, body) => {
let times_num = match self.visit(times) {
Ok(Value::Number(n)) => n as usize,
_ => return Err(LErr::new("`repeat` may only take numbers".to_string())),
_ => return self.panic("`repeat` may only take numbers".to_string()),
};
for _ in 0..times_num {
self.visit(body)?;

View File

@ -30,7 +30,8 @@ pub enum Value<'src> {
List(Vector<Self>),
Dict(HashMap<&'static str, Self>),
Box(&'static str, Rc<RefCell<Self>>),
Fn(Rc<Fn<'src>>),
Fn(Rc<RefCell<Fn<'src>>>),
FnDecl(&'static str),
Base(BaseFn<'src>),
Recur(Vec<Self>),
// Set(HashSet<Self>),
@ -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::<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)) => {
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()))
.collect::<Vec<_>>()
.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!(),