forked from Orchid/orchid
backup commit
This commit is contained in:
157
src/representations/ast.rs
Normal file
157
src/representations/ast.rs
Normal file
@@ -0,0 +1,157 @@
|
||||
use mappable_rc::Mrc;
|
||||
use itertools::Itertools;
|
||||
use ordered_float::NotNan;
|
||||
use std::hash::Hash;
|
||||
use std::fmt::Debug;
|
||||
use crate::executor::{ExternFn, Atom};
|
||||
|
||||
use super::Literal;
|
||||
|
||||
/// An S-expression with a type
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct Expr(pub Clause, pub Mrc<[Clause]>);
|
||||
|
||||
impl Clone for Expr {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone(), Mrc::clone(&self.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Expr(val, typ) = self;
|
||||
write!(f, "{:?}", val)?;
|
||||
for typ in typ.as_ref() {
|
||||
write!(f, ":{:?}", typ)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An S-expression as read from a source file
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub enum Clause {
|
||||
Literal(Literal),
|
||||
Name{
|
||||
local: Option<String>,
|
||||
qualified: Mrc<[String]>
|
||||
},
|
||||
S(char, Mrc<[Expr]>),
|
||||
Lambda(String, Mrc<[Expr]>, Mrc<[Expr]>),
|
||||
Auto(Option<String>, Mrc<[Expr]>, Mrc<[Expr]>),
|
||||
ExternFn(ExternFn),
|
||||
Atom(Atom),
|
||||
Placeh{
|
||||
key: String,
|
||||
/// None => matches one token
|
||||
/// Some((prio, nonzero)) =>
|
||||
/// prio is the sizing priority for the vectorial (higher prio grows first)
|
||||
/// nonzero is whether the vectorial matches 1..n or 0..n tokens
|
||||
vec: Option<(usize, bool)>
|
||||
},
|
||||
}
|
||||
impl Clause {
|
||||
pub fn body(&self) -> Option<Mrc<[Expr]>> {
|
||||
match self {
|
||||
Clause::Auto(_, _, body) |
|
||||
Clause::Lambda(_, _, body) |
|
||||
Clause::S(_, body) => Some(Mrc::clone(body)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn typ(&self) -> Option<Mrc<[Expr]>> {
|
||||
match self {
|
||||
Clause::Auto(_, typ, _) | Clause::Lambda(_, typ, _) => Some(Mrc::clone(typ)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Clause {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Clause::S(c, b) => Clause::S(*c, Mrc::clone(b)),
|
||||
Clause::Auto(n, t, b) => Clause::Auto(
|
||||
n.clone(), Mrc::clone(t), Mrc::clone(b)
|
||||
),
|
||||
Clause::Name { local: l, qualified: q } => Clause::Name {
|
||||
local: l.clone(), qualified: Mrc::clone(q)
|
||||
},
|
||||
Clause::Lambda(n, t, b) => Clause::Lambda(
|
||||
n.clone(), Mrc::clone(t), Mrc::clone(b)
|
||||
),
|
||||
Clause::Placeh{key, vec} => Clause::Placeh{key: key.clone(), vec: *vec},
|
||||
Clause::Literal(l) => Clause::Literal(l.clone()),
|
||||
Clause::ExternFn(nc) => Clause::ExternFn(nc.clone()),
|
||||
Clause::Atom(a) => Clause::Atom(a.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_expr_seq(it: &mut dyn Iterator<Item = &Expr>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for item in Itertools::intersperse(it.map(Some), None) { match item {
|
||||
Some(expr) => write!(f, "{:?}", expr),
|
||||
None => f.write_str(" "),
|
||||
}? }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Debug for Clause {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Literal(arg0) => write!(f, "{:?}", arg0),
|
||||
Self::Name{local, qualified} =>
|
||||
if let Some(local) = local {write!(f, "{}`{}`", qualified.join("::"), local)}
|
||||
else {write!(f, "{}", qualified.join("::"))},
|
||||
Self::S(del, items) => {
|
||||
f.write_str(&del.to_string())?;
|
||||
fmt_expr_seq(&mut items.iter(), f)?;
|
||||
f.write_str(match del {
|
||||
'(' => ")", '[' => "]", '{' => "}",
|
||||
_ => "CLOSING_DELIM"
|
||||
})
|
||||
},
|
||||
Self::Lambda(name, argtyp, body) => {
|
||||
f.write_str("\\")?;
|
||||
f.write_str(name)?;
|
||||
f.write_str(":")?; fmt_expr_seq(&mut argtyp.iter(), f)?; f.write_str(".")?;
|
||||
fmt_expr_seq(&mut body.iter(), f)
|
||||
},
|
||||
Self::Auto(name, argtyp, body) => {
|
||||
f.write_str("@")?;
|
||||
f.write_str(&name.clone().unwrap_or_default())?;
|
||||
f.write_str(":")?; fmt_expr_seq(&mut argtyp.iter(), f)?; f.write_str(".")?;
|
||||
fmt_expr_seq(&mut body.iter(), f)
|
||||
},
|
||||
Self::Placeh{key, vec: None} => write!(f, "${key}"),
|
||||
Self::Placeh{key, vec: Some((prio, true))} => write!(f, "...${key}:{prio}"),
|
||||
Self::Placeh{key, vec: Some((prio, false))} => write!(f, "..${key}:{prio}"),
|
||||
Self::ExternFn(nc) => write!(f, "{nc:?}"),
|
||||
Self::Atom(a) => write!(f, "{a:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A substitution rule as read from the source
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct Rule {
|
||||
pub source: Mrc<[Expr]>,
|
||||
pub prio: NotNan<f64>,
|
||||
pub target: Mrc<[Expr]>
|
||||
}
|
||||
|
||||
impl Clone for Rule {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
source: Mrc::clone(&self.source),
|
||||
prio: self.prio,
|
||||
target: Mrc::clone(&self.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Rule {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?} ={}=> {:?}", self.source, self.prio, self.target)
|
||||
}
|
||||
}
|
||||
120
src/representations/ast_to_typed.rs
Normal file
120
src/representations/ast_to_typed.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
use mappable_rc::Mrc;
|
||||
|
||||
use crate::utils::{Stackframe, to_mrc_slice};
|
||||
|
||||
use super::{ast, typed};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Error {
|
||||
/// `()` as a clause is meaningless in lambda calculus
|
||||
EmptyS,
|
||||
/// Only `(...)` may be converted to typed lambdas. `[...]` and `{...}` left in the code are
|
||||
/// signs of incomplete macro execution
|
||||
BadGroup(char),
|
||||
/// `foo:bar:baz` will be parsed as `(foo:bar):baz`, explicitly specifying `foo:(bar:baz)`
|
||||
/// is forbidden and it's also meaningless since `baz` can only ever be the kind of types
|
||||
ExplicitBottomKind,
|
||||
/// Name never bound in an enclosing scope - indicates incomplete macro substitution
|
||||
Unbound(String),
|
||||
/// Namespaced names can never occur in the code, these are signs of incomplete macro execution
|
||||
Symbol,
|
||||
/// Placeholders shouldn't even occur in the code during macro execution. Something is clearly
|
||||
/// terribly wrong
|
||||
Placeholder,
|
||||
/// It's possible to try and transform the clause `(foo:bar)` into a typed clause,
|
||||
/// however the correct value of this ast clause is a typed expression (included in the error)
|
||||
///
|
||||
/// [expr] handles this case, so it's only really possible to get this
|
||||
/// error if you're calling [clause] directly
|
||||
ExprToClause(typed::Expr)
|
||||
}
|
||||
|
||||
/// Try to convert an expression from AST format to typed lambda
|
||||
pub fn expr(expr: &ast::Expr) -> Result<typed::Expr, Error> {
|
||||
expr_rec(expr, Stackframe::new(None))
|
||||
}
|
||||
|
||||
/// Try and convert a single clause from AST format to typed lambda
|
||||
pub fn clause(clause: &ast::Clause) -> Result<typed::Clause, Error> {
|
||||
clause_rec(clause, Stackframe::new(None))
|
||||
}
|
||||
|
||||
/// Try and convert a sequence of expressions from AST format to typed lambda
|
||||
pub fn exprv(exprv: &[ast::Expr]) -> Result<typed::Expr, Error> {
|
||||
exprv_rec(exprv, Stackframe::new(None))
|
||||
}
|
||||
|
||||
/// Recursive state of [exprv]
|
||||
fn exprv_rec(v: &[ast::Expr], names: Stackframe<Option<&str>>) -> Result<typed::Expr, Error> {
|
||||
if v.len() == 0 {return Err(Error::EmptyS)}
|
||||
if v.len() == 1 {return expr_rec(&v[0], names)}
|
||||
let (head, tail) = v.split_at(2);
|
||||
let f = expr_rec(&head[0], names)?;
|
||||
let x = expr_rec(&head[1], names)?;
|
||||
// TODO this could probably be normalized, it's a third copy.
|
||||
tail.iter().map(|e| expr_rec(e, names)).fold(
|
||||
Ok(typed::Clause::Apply(Mrc::new(f), Mrc::new(x))),
|
||||
|acc, e| Ok(typed::Clause::Apply(
|
||||
Mrc::new(typed::Expr(acc?, to_mrc_slice(vec![]))),
|
||||
Mrc::new(e?)
|
||||
))
|
||||
).map(|cls| typed::Expr(cls, to_mrc_slice(vec![])))
|
||||
}
|
||||
|
||||
/// Recursive state of [expr]
|
||||
fn expr_rec(ast::Expr(val, typ): &ast::Expr, names: Stackframe<Option<&str>>)
|
||||
-> Result<typed::Expr, Error> {
|
||||
let typ: Vec<typed::Clause> = typ.iter()
|
||||
.map(|c| clause_rec(c, names))
|
||||
.collect::<Result<_, _>>()?;
|
||||
if let ast::Clause::S(paren, body) = val {
|
||||
if *paren != '(' {return Err(Error::BadGroup(*paren))}
|
||||
let typed::Expr(inner, inner_t) = exprv_rec(body.as_ref(), names)?;
|
||||
let new_t = if typ.len() == 0 { inner_t } else {
|
||||
to_mrc_slice(if inner_t.len() == 0 { typ } else {
|
||||
inner_t.iter().chain(typ.iter()).cloned().collect()
|
||||
})
|
||||
};
|
||||
Ok(typed::Expr(inner, new_t))
|
||||
} else {
|
||||
Ok(typed::Expr(clause_rec(&val, names)?, to_mrc_slice(typ)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursive state of [clause]
|
||||
fn clause_rec(cls: &ast::Clause, names: Stackframe<Option<&str>>)
|
||||
-> Result<typed::Clause, Error> {
|
||||
match cls {
|
||||
ast::Clause::ExternFn(e) => Ok(typed::Clause::ExternFn(e.clone())),
|
||||
ast::Clause::Atom(a) => Ok(typed::Clause::Atom(a.clone())),
|
||||
ast::Clause::Auto(no, t, b) => Ok(typed::Clause::Auto(
|
||||
if t.len() == 0 {None} else {
|
||||
let typed::Expr(c, t) = exprv_rec(t.as_ref(), names)?;
|
||||
if t.len() > 0 {return Err(Error::ExplicitBottomKind)}
|
||||
else {Some(Mrc::new(c))}
|
||||
},
|
||||
Mrc::new(exprv_rec(b.as_ref(), names.push(no.as_ref().map(|n| &**n)))?)
|
||||
)),
|
||||
ast::Clause::Lambda(n, t, b) => Ok(typed::Clause::Lambda(
|
||||
if t.len() == 0 {None} else {
|
||||
let typed::Expr(c, t) = exprv_rec(t.as_ref(), names)?;
|
||||
if t.len() > 0 {return Err(Error::ExplicitBottomKind)}
|
||||
else {Some(Mrc::new(c))}
|
||||
},
|
||||
Mrc::new(exprv_rec(b.as_ref(), names.push(Some(&**n)))?)
|
||||
)),
|
||||
ast::Clause::Literal(l) => Ok(typed::Clause::Literal(l.clone())),
|
||||
ast::Clause::Name { local: Some(arg), .. } => Ok(typed::Clause::Argument(
|
||||
names.iter().position(|no| no == &Some(&**arg))
|
||||
.ok_or_else(|| Error::Unbound(arg.clone()))?
|
||||
)),
|
||||
ast::Clause::S(paren, entries) => {
|
||||
if *paren != '(' {return Err(Error::BadGroup(*paren))}
|
||||
let typed::Expr(val, typ) = exprv_rec(entries.as_ref(), names)?;
|
||||
if typ.len() == 0 {Ok(val)}
|
||||
else {Err(Error::ExprToClause(typed::Expr(val, typ)))}
|
||||
},
|
||||
ast::Clause::Name { local: None, .. } => Err(Error::Symbol),
|
||||
ast::Clause::Placeh { .. } => Err(Error::Placeholder)
|
||||
}
|
||||
}
|
||||
22
src/representations/literal.rs
Normal file
22
src/representations/literal.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use ordered_float::NotNan;
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// An exact value, read from the AST and unmodified in shape until compilation
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Literal {
|
||||
Num(NotNan<f64>),
|
||||
Int(u64),
|
||||
Char(char),
|
||||
Str(String),
|
||||
}
|
||||
|
||||
impl Debug for Literal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Num(arg0) => write!(f, "{:?}", arg0),
|
||||
Self::Int(arg0) => write!(f, "{:?}", arg0),
|
||||
Self::Char(arg0) => write!(f, "{:?}", arg0),
|
||||
Self::Str(arg0) => write!(f, "{:?}", arg0),
|
||||
}
|
||||
}
|
||||
}
|
||||
5
src/representations/mod.rs
Normal file
5
src/representations/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub mod ast;
|
||||
pub mod typed;
|
||||
pub mod literal;
|
||||
pub mod ast_to_typed;
|
||||
pub use literal::Literal;
|
||||
147
src/representations/typed.rs
Normal file
147
src/representations/typed.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
use mappable_rc::Mrc;
|
||||
use crate::executor::Atom;
|
||||
use crate::utils::{to_mrc_slice, one_mrc_slice};
|
||||
use crate::{executor::ExternFn, utils::string_from_charset};
|
||||
|
||||
use super::{Literal, ast_to_typed};
|
||||
use super::ast;
|
||||
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
/// Indicates whether either side needs to be wrapped. Syntax whose end is ambiguous on that side
|
||||
/// must use parentheses, or forward the flag
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct Wrap(bool, bool);
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct Expr(pub Clause, pub Mrc<[Clause]>);
|
||||
impl Expr {
|
||||
fn deep_fmt(&self, f: &mut std::fmt::Formatter<'_>, depth: usize, tr: Wrap) -> std::fmt::Result {
|
||||
let Expr(val, typ) = self;
|
||||
if typ.len() > 0 {
|
||||
val.deep_fmt(f, depth, Wrap(true, true))?;
|
||||
for typ in typ.as_ref() {
|
||||
f.write_char(':')?;
|
||||
typ.deep_fmt(f, depth, Wrap(true, true))?;
|
||||
}
|
||||
} else {
|
||||
val.deep_fmt(f, depth, tr)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Expr {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone(), Mrc::clone(&self.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.deep_fmt(f, 0, Wrap(false, false))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub enum Clause {
|
||||
Literal(Literal),
|
||||
Apply(Mrc<Expr>, Mrc<Expr>),
|
||||
/// Explicit specification of an Auto value
|
||||
Explicit(Mrc<Expr>, Mrc<Expr>),
|
||||
Lambda(Option<Mrc<Clause>>, Mrc<Expr>),
|
||||
Auto(Option<Mrc<Clause>>, Mrc<Expr>),
|
||||
Argument(usize),
|
||||
ExternFn(ExternFn),
|
||||
Atom(Atom)
|
||||
}
|
||||
|
||||
const ARGNAME_CHARSET: &str = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
fn parametric_fmt(
|
||||
f: &mut std::fmt::Formatter<'_>,
|
||||
prefix: &str, argtyp: Option<Mrc<Clause>>, body: Mrc<Expr>, depth: usize, wrap_right: bool
|
||||
) -> std::fmt::Result {
|
||||
if wrap_right { f.write_char('(')?; }
|
||||
f.write_str(prefix)?;
|
||||
f.write_str(&string_from_charset(depth, ARGNAME_CHARSET))?;
|
||||
if let Some(typ) = argtyp {
|
||||
f.write_str(":")?;
|
||||
typ.deep_fmt(f, depth, Wrap(false, false))?;
|
||||
}
|
||||
f.write_str(".")?;
|
||||
body.deep_fmt(f, depth + 1, Wrap(false, false))?;
|
||||
if wrap_right { f.write_char(')')?; }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Clause {
|
||||
fn deep_fmt(&self, f: &mut std::fmt::Formatter<'_>, depth: usize, Wrap(wl, wr): Wrap)
|
||||
-> std::fmt::Result {
|
||||
match self {
|
||||
Self::Literal(arg0) => write!(f, "{arg0:?}"),
|
||||
Self::ExternFn(nc) => write!(f, "{nc:?}"),
|
||||
Self::Atom(a) => write!(f, "{a:?}"),
|
||||
Self::Lambda(argtyp, body) => parametric_fmt(f,
|
||||
"\\", argtyp.as_ref().map(Mrc::clone), Mrc::clone(body), depth, wr
|
||||
),
|
||||
Self::Auto(argtyp, body) => parametric_fmt(f,
|
||||
"@", argtyp.as_ref().map(Mrc::clone), Mrc::clone(body), depth, wr
|
||||
),
|
||||
Self::Argument(up) => f.write_str(&string_from_charset(depth - up - 1, ARGNAME_CHARSET)),
|
||||
Self::Explicit(expr, param) => {
|
||||
if wl { f.write_char('(')?; }
|
||||
expr.deep_fmt(f, depth, Wrap(false, true))?;
|
||||
f.write_str(" @")?;
|
||||
param.deep_fmt(f, depth, Wrap(true, wr && !wl))?;
|
||||
if wl { f.write_char(')')?; }
|
||||
Ok(())
|
||||
}
|
||||
Self::Apply(func, x) => {
|
||||
if wl { f.write_char('(')?; }
|
||||
func.deep_fmt(f, depth, Wrap(false, true) )?;
|
||||
f.write_char(' ')?;
|
||||
x.deep_fmt(f, depth, Wrap(true, wr && !wl) )?;
|
||||
if wl { f.write_char(')')?; }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn wrap(self) -> Mrc<Expr> { Mrc::new(Expr(self, to_mrc_slice(vec![]))) }
|
||||
pub fn wrap_t(self, t: Clause) -> Mrc<Expr> { Mrc::new(Expr(self, one_mrc_slice(t))) }
|
||||
}
|
||||
|
||||
impl Clone for Clause {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Clause::Auto(t, b) => Clause::Auto(t.as_ref().map(Mrc::clone), Mrc::clone(b)),
|
||||
Clause::Lambda(t, b) => Clause::Lambda(t.as_ref().map(Mrc::clone), Mrc::clone(b)),
|
||||
Clause::Literal(l) => Clause::Literal(l.clone()),
|
||||
Clause::ExternFn(nc) => Clause::ExternFn(nc.clone()),
|
||||
Clause::Atom(a) => Clause::Atom(a.clone()),
|
||||
Clause::Apply(f, x) => Clause::Apply(Mrc::clone(f), Mrc::clone(x)),
|
||||
Clause::Explicit(f, x) => Clause::Explicit(Mrc::clone(f), Mrc::clone(x)),
|
||||
Clause::Argument(lvl) => Clause::Argument(*lvl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Clause {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.deep_fmt(f, 0, Wrap(false, false))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ast::Expr> for Expr {
|
||||
type Error = ast_to_typed::Error;
|
||||
fn try_from(value: &ast::Expr) -> Result<Self, Self::Error> {
|
||||
ast_to_typed::expr(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ast::Clause> for Clause {
|
||||
type Error = ast_to_typed::Error;
|
||||
fn try_from(value: &ast::Clause) -> Result<Self, Self::Error> {
|
||||
ast_to_typed::clause(value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user