backup commit

This commit is contained in:
2022-10-24 03:16:04 +01:00
parent fbbd6ed256
commit 778c87db77
43 changed files with 1156 additions and 174 deletions

157
src/representations/ast.rs Normal file
View 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)
}
}

View 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)
}
}

View 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),
}
}
}

View File

@@ -0,0 +1,5 @@
pub mod ast;
pub mod typed;
pub mod literal;
pub mod ast_to_typed;
pub use literal::Literal;

View 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)
}
}