Most files suffered major changes
- Less ambiguous syntax - Better parser (Chumsky only does tokenization now) - Tidy(|ier) error handling - Facade for simplified embedding - External code grouped in (fairly) self-contained Systems - Dynamic action dispatch - Many STL additions
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::location::Location;
|
||||
use super::{ast, postmacro};
|
||||
use crate::utils::Substack;
|
||||
use crate::Sym;
|
||||
use crate::error::{ErrorPosition, ProjectError};
|
||||
use crate::utils::iter::box_once;
|
||||
use crate::utils::{BoxedIter, Substack};
|
||||
use crate::{Interner, Sym};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Error {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ErrorKind {
|
||||
/// `()` as a clause is meaningless in lambda calculus
|
||||
EmptyS,
|
||||
/// Only `(...)` may be converted to typed lambdas. `[...]` and `{...}`
|
||||
@@ -16,29 +17,44 @@ pub enum Error {
|
||||
/// Placeholders shouldn't even occur in the code during macro
|
||||
/// execution. Something is clearly terribly wrong
|
||||
Placeholder,
|
||||
/// Arguments can only be [ast::Clause::Name]
|
||||
/// Arguments can only be a single [ast::Clause::Name]
|
||||
InvalidArg,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Error::EmptyS => {
|
||||
write!(f, "`()` as a clause is meaningless in lambda calculus")
|
||||
},
|
||||
Error::BadGroup(_) => write!(
|
||||
f,
|
||||
"Only `(...)` may be converted to typed lambdas. `[...]` and \
|
||||
`{{...}}` left in the code are signs of incomplete macro execution"
|
||||
),
|
||||
Error::Placeholder => write!(
|
||||
f,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Error {
|
||||
pub location: Location,
|
||||
pub kind: ErrorKind,
|
||||
}
|
||||
impl Error {
|
||||
pub fn new(kind: ErrorKind, location: &Location) -> Self {
|
||||
Self { location: location.clone(), kind }
|
||||
}
|
||||
}
|
||||
impl ProjectError for Error {
|
||||
fn description(&self) -> &str {
|
||||
match self.kind {
|
||||
ErrorKind::BadGroup(_) =>
|
||||
"Only `(...)` may be converted to typed lambdas. `[...]` and `{{...}}` \
|
||||
left in the code are signs of incomplete macro execution",
|
||||
ErrorKind::EmptyS => "`()` as a clause is meaningless in lambda calculus",
|
||||
ErrorKind::InvalidArg => "Argument names can only be Name nodes",
|
||||
ErrorKind::Placeholder =>
|
||||
"Placeholders shouldn't even appear in the code during macro \
|
||||
execution, this is likely a compiler bug"
|
||||
),
|
||||
Error::InvalidArg => write!(f, "Arguments can only be Name nodes"),
|
||||
execution,this is likely a compiler bug",
|
||||
}
|
||||
}
|
||||
|
||||
fn message(&self, _i: &Interner) -> String {
|
||||
match self.kind {
|
||||
ErrorKind::BadGroup(char) => format!("{} block found in the code", char),
|
||||
_ => self.description().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to convert an expression from AST format to typed lambda
|
||||
@@ -66,14 +82,16 @@ impl<'a> Context<'a> {
|
||||
|
||||
/// Process an expression sequence
|
||||
fn exprv_rec<'a>(
|
||||
location: &'a Location,
|
||||
v: &'a [ast::Expr<Sym>],
|
||||
ctx: Context<'a>,
|
||||
) -> Result<postmacro::Expr, Error> {
|
||||
let (last, rest) = v.split_last().ok_or(Error::EmptyS)?;
|
||||
let (last, rest) =
|
||||
(v.split_last()).ok_or_else(|| Error::new(ErrorKind::EmptyS, location))?;
|
||||
if rest.is_empty() {
|
||||
return expr_rec(&v[0], ctx);
|
||||
}
|
||||
let f = exprv_rec(rest, ctx)?;
|
||||
let f = exprv_rec(location, rest, ctx)?;
|
||||
let x = expr_rec(last, ctx)?;
|
||||
let value = postmacro::Clause::Apply(Rc::new(f), Rc::new(x));
|
||||
Ok(postmacro::Expr { value, location: Location::Unknown })
|
||||
@@ -86,52 +104,44 @@ fn expr_rec<'a>(
|
||||
) -> Result<postmacro::Expr, Error> {
|
||||
if let ast::Clause::S(paren, body) = value {
|
||||
if *paren != '(' {
|
||||
return Err(Error::BadGroup(*paren));
|
||||
return Err(Error::new(ErrorKind::BadGroup(*paren), location));
|
||||
}
|
||||
let expr = exprv_rec(body.as_ref(), ctx)?;
|
||||
let expr = exprv_rec(location, body.as_ref(), ctx)?;
|
||||
Ok(postmacro::Expr { value: expr.value, location: location.clone() })
|
||||
} else {
|
||||
let value = clause_rec(value, ctx)?;
|
||||
let value = match value {
|
||||
ast::Clause::P(p) => postmacro::Clause::P(p.clone()),
|
||||
ast::Clause::Lambda(arg, b) => {
|
||||
let name = match &arg[..] {
|
||||
[ast::Expr { value: ast::Clause::Name(name), .. }] => name,
|
||||
[ast::Expr { value: ast::Clause::Placeh { .. }, .. }] =>
|
||||
return Err(Error::new(ErrorKind::Placeholder, location)),
|
||||
_ => return Err(Error::new(ErrorKind::InvalidArg, location)),
|
||||
};
|
||||
let body_ctx = ctx.w_name(*name);
|
||||
let body = exprv_rec(location, b.as_ref(), body_ctx)?;
|
||||
postmacro::Clause::Lambda(Rc::new(body))
|
||||
},
|
||||
ast::Clause::Name(name) => {
|
||||
let lvl_opt = (ctx.names.iter())
|
||||
.enumerate()
|
||||
.find(|(_, n)| *n == name)
|
||||
.map(|(lvl, _)| lvl);
|
||||
match lvl_opt {
|
||||
Some(lvl) => postmacro::Clause::LambdaArg(lvl),
|
||||
None => postmacro::Clause::Constant(*name),
|
||||
}
|
||||
},
|
||||
ast::Clause::S(paren, entries) => {
|
||||
if *paren != '(' {
|
||||
return Err(Error::new(ErrorKind::BadGroup(*paren), location));
|
||||
}
|
||||
let expr = exprv_rec(location, entries.as_ref(), ctx)?;
|
||||
expr.value
|
||||
},
|
||||
ast::Clause::Placeh { .. } =>
|
||||
return Err(Error::new(ErrorKind::Placeholder, location)),
|
||||
};
|
||||
Ok(postmacro::Expr { value, location: location.clone() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a clause
|
||||
fn clause_rec<'a>(
|
||||
cls: &'a ast::Clause<Sym>,
|
||||
ctx: Context<'a>,
|
||||
) -> Result<postmacro::Clause, Error> {
|
||||
match cls {
|
||||
ast::Clause::P(p) => Ok(postmacro::Clause::P(p.clone())),
|
||||
ast::Clause::Lambda(expr, b) => {
|
||||
let name = match expr.value {
|
||||
ast::Clause::Name(name) => name,
|
||||
ast::Clause::Placeh { .. } => return Err(Error::Placeholder),
|
||||
_ => return Err(Error::InvalidArg),
|
||||
};
|
||||
let body_ctx = ctx.w_name(name);
|
||||
let body = exprv_rec(b.as_ref(), body_ctx)?;
|
||||
Ok(postmacro::Clause::Lambda(Rc::new(body)))
|
||||
},
|
||||
ast::Clause::Name(name) => {
|
||||
let lvl_opt = ctx
|
||||
.names
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, n)| *n == name)
|
||||
.map(|(lvl, _)| lvl);
|
||||
Ok(match lvl_opt {
|
||||
Some(lvl) => postmacro::Clause::LambdaArg(lvl),
|
||||
None => postmacro::Clause::Constant(*name),
|
||||
})
|
||||
},
|
||||
ast::Clause::S(paren, entries) => {
|
||||
if *paren != '(' {
|
||||
return Err(Error::BadGroup(*paren));
|
||||
}
|
||||
let expr = exprv_rec(entries.as_ref(), ctx)?;
|
||||
Ok(expr.value)
|
||||
},
|
||||
ast::Clause::Placeh { .. } => Err(Error::Placeholder),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user