executor, mostly

This commit is contained in:
2022-11-07 15:15:38 +00:00
parent d9c35c3591
commit 6900d1213a
18 changed files with 444 additions and 61 deletions

View File

@@ -0,0 +1,67 @@
use mappable_rc::Mrc;
use super::super::representations::typed::{Clause, Expr};
pub fn apply_lambda(body: Mrc<Expr>, arg: Mrc<Expr>) -> Mrc<Expr> {
apply_lambda_expr_rec(Mrc::clone(&body), arg, 0)
.unwrap_or(body)
}
fn apply_lambda_expr_rec(
item: Mrc<Expr>, arg: Mrc<Expr>, depth: usize
) -> Option<Mrc<Expr>> {
let Expr(clause, typ) = item.as_ref();
apply_lambda_clause_rec(clause.clone(), arg, depth)
.map(|c| Mrc::new(Expr(c, Mrc::clone(typ))))
}
fn apply_lambda_clause_rec(
clause: Clause, arg: Mrc<Expr>, depth: usize
) -> Option<Clause> {
match clause {
// Only element actually manipulated
Clause::Argument(d) => {
if d == depth {Some(arg.0.clone())} // Resolve reference
// Application eliminates a layer of indirection
else if d > depth {Some(Clause::Argument(d - 1))}
else {None} // Undisturbed ancestry
}
// Traverse, yield Some if either had changed.
Clause::Apply(f, x) => apply_lambda__traverse_call(arg, depth, f, x, Clause::Apply),
Clause::Explicit(f, t) => apply_lambda__traverse_call(arg, depth, f, t, Clause::Explicit),
Clause::Lambda(t, b) => apply_lambda__traverse_param(arg, depth, t, b, Clause::Lambda),
Clause::Auto(t, b) => apply_lambda__traverse_param(arg, depth, t, b, Clause::Auto),
// Leaf nodes
Clause::Atom(_) | Clause::ExternFn(_) | Clause::Literal(_) => None
}
}
fn apply_lambda__traverse_call(
arg: Mrc<Expr>, depth: usize, f: Mrc<Expr>, x: Mrc<Expr>,
wrap: impl Fn(Mrc<Expr>, Mrc<Expr>) -> Clause
) -> Option<Clause> {
let new_f = apply_lambda_expr_rec(Mrc::clone(&f), Mrc::clone(&arg), depth);
let new_x = apply_lambda_expr_rec(Mrc::clone(&x), arg, depth);
match (new_f, new_x) {
(None, None) => None,
(None, Some(x)) => Some(wrap(f, x)),
(Some(f), None) => Some(wrap(f, x)),
(Some(f), Some(x)) => Some(wrap(f, x))
}
}
fn apply_lambda__traverse_param(
arg: Mrc<Expr>, depth: usize, t: Option<Mrc<Clause>>, b: Mrc<Expr>,
wrap: impl Fn(Option<Mrc<Clause>>, Mrc<Expr>) -> Clause
) -> Option<Clause> {
let new_t = t.as_ref().and_then(|t| {
apply_lambda_clause_rec(t.as_ref().clone(), Mrc::clone(&arg), depth)
});
let new_b = apply_lambda_expr_rec(Mrc::clone(&b), arg, depth + 1);
match (new_t, new_b) {
(None, None) => None,
(None, Some(b)) => Some(Clause::Lambda(t, b)),
(Some(t), None) => Some(Clause::Lambda(Some(Mrc::new(t)), b)),
(Some(t), Some(b)) => Some(Clause::Lambda(Some(Mrc::new(t)), b))
}
}

View File

@@ -10,7 +10,6 @@ pub trait ExternError: Display {}
/// Represents an externally defined function from the perspective of the executor
/// Since Orchid lacks basic numerical operations, these are also external functions.
#[derive(Eq)]
pub struct ExternFn {
name: String, param: Mrc<Expr>, rttype: Mrc<Expr>,
function: Mrc<dyn Fn(Clause) -> Result<Clause, Mrc<dyn ExternError>>>
@@ -27,8 +26,8 @@ impl ExternFn {
})
}
}
fn name(&self) -> &str {&self.name}
fn apply(&self, arg: Clause) -> Result<Clause, Mrc<dyn ExternError>> {(self.function)(arg)}
pub fn name(&self) -> &str {&self.name}
pub fn apply(&self, arg: Clause) -> Result<Clause, Mrc<dyn ExternError>> {(self.function)(arg)}
}
impl Clone for ExternFn { fn clone(&self) -> Self { Self {
@@ -37,7 +36,10 @@ impl Clone for ExternFn { fn clone(&self) -> Self { Self {
rttype: Mrc::clone(&self.rttype),
function: Mrc::clone(&self.function)
}}}
impl PartialEq for ExternFn { fn eq(&self, other: &Self) -> bool { self.name() == other.name() }}
impl Eq for ExternFn {}
impl PartialEq for ExternFn {
fn eq(&self, other: &Self) -> bool { self.name() == other.name() }
}
impl Hash for ExternFn {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.name.hash(state) }
}
@@ -58,7 +60,6 @@ pub trait Atomic: Any + Debug where Self: 'static {
/// information in the universe of types or kinds such as the type of signed integers or
/// the kind of types. Ad absurdum it can also be just a number, although Literal is
/// preferable for types it's defined on.
#[derive(Eq)]
pub struct Atom {
typ: Mrc<Expr>,
data: Mrc<dyn Atomic>
@@ -95,6 +96,7 @@ impl Debug for Atom {
write!(f, "##ATOM[{:?}]:{:?}##", self.data(), self.typ)
}
}
impl Eq for Atom {}
impl PartialEq for Atom {
fn eq(&self, other: &Self) -> bool {
self.data().definitely_eq(other.data().as_any())

View File

@@ -1,3 +1,7 @@
mod foreign;
// mod normalize;
mod partial_hash;
mod reduction_tree;
mod apply_lambda;
pub use foreign::ExternFn;
pub use foreign::Atom;

30
src/executor/normalize.rs Normal file
View File

@@ -0,0 +1,30 @@
use mappable_rc::Mrc;
use crate::utils::collect_to_mrc;
use super::super::representations::typed::{Clause, Expr};
fn normalize(Expr(clause, typ): Expr) -> Expr {
todo!()
}
fn collect_autos(
Expr(clause, typ): Expr,
arg_types: Vec<Mrc<[Clause]>>,
indirect_argt_trees: Vec<Mrc<[Clause]>>,
sunk_types: &mut dyn Iterator<Item = Clause>
) -> (Vec<Mrc<[Clause]>>, Expr) {
if let Clause::Auto(argt, body) = clause {
}
else {(
arg_types,
Expr(
clause,
collect_to_mrc(
typ.iter().cloned()
.chain(sunk_types)
)
)
)}
}

View File

@@ -0,0 +1,38 @@
use std::hash::{Hasher, Hash};
use super::super::representations::typed::{Clause, Expr};
use super::super::utils::Stackframe;
/// Hash the parts of an expression that are required to be equal for syntactic equality.
pub fn partial_hash_rec<H: Hasher>(Expr(clause, _): &Expr, state: &mut H, is_auto: Stackframe<bool>) {
match clause {
// Skip autos and explicits
Clause::Auto(_, body) => partial_hash_rec(body, state, is_auto.push(true)),
Clause::Explicit(f, _) => partial_hash_rec(f, state, is_auto),
// Annotate everything else with a prefix
// - Recurse into the tree of lambdas and calls - classic lambda calc
Clause::Lambda(_, body) => {
state.write_u8(0);
partial_hash_rec(body, state, is_auto.push(false))
}
Clause::Apply(f, x) => {
state.write_u8(1);
partial_hash_rec(f, state, is_auto);
partial_hash_rec(x, state, is_auto);
}
// - Only recognize the depth of an argument if it refers to a non-auto parameter
Clause::Argument(depth) => {
// If the argument references an auto, acknowledge its existence
if *is_auto.iter().nth(*depth).unwrap_or(&false) {
state.write_u8(2)
} else {
state.write_u8(3);
state.write_usize(*depth)
}
}
// - Hash leaves like normal
Clause::Literal(lit) => { state.write_u8(4); lit.hash(state) }
Clause::Atom(at) => { state.write_u8(5); at.hash(state) }
Clause::ExternFn(f) => { state.write_u8(6); f.hash(state) }
}
}

View File

@@ -0,0 +1,102 @@
use mappable_rc::Mrc;
use crate::box_chain;
use crate::utils::BoxedIter;
use crate::utils::iter::{box_once, box_empty};
use super::apply_lambda::apply_lambda;
use super::super::representations::typed::{Clause, Expr};
/// Call the function with the first Expression that isn't an Auto,
/// wrap all elements in the returned iterator back in the original sequence of Autos.
fn skip_autos<'a,
F: 'a + FnOnce(Mrc<Expr>, usize) -> I,
I: Iterator<Item = Mrc<Expr>> + 'static
>(
depth: usize, expr: Mrc<Expr>, function: F
) -> BoxedIter<'static, Mrc<Expr>> {
match expr.as_ref() {
Expr(Clause::Auto(arg, body), typ) => {
return Box::new(skip_autos(depth + 1, Mrc::clone(body), function).map({
let arg = arg.as_ref().map(Mrc::clone);
let typ = Mrc::clone(typ);
move |body| {
Mrc::new(Expr(Clause::Auto(
arg.as_ref().map(Mrc::clone),
body
), Mrc::clone(&typ)))
}
})) as BoxedIter<'static, Mrc<Expr>>
}
Expr(Clause::Explicit(expr, targ), typ) => {
return Box::new(skip_autos(depth, Mrc::clone(expr), function).map({
let (targ, typ) = (Mrc::clone(targ), Mrc::clone(typ));
move |expr| {
Mrc::new(Expr(Clause::Explicit(expr, Mrc::clone(&targ)), Mrc::clone(&typ)))
}
})) as BoxedIter<'static, Mrc<Expr>>
}
_ => ()
}
Box::new(function(expr, depth))
}
/// Produces an iterator of every expression that can be produced from this one through B-reduction.
fn direct_reductions(ex: Mrc<Expr>) -> impl Iterator<Item = Mrc<Expr>> {
skip_autos(0, ex, |mexpr, _| {
let Expr(clause, typ_ref) = mexpr.as_ref();
match clause {
Clause::Apply(f, x) => box_chain!(
skip_autos(0, Mrc::clone(f), |mexpr, _| {
let Expr(f, _) = mexpr.as_ref();
match f {
Clause::Lambda(_, body) => box_once(
apply_lambda(Mrc::clone(body), Mrc::clone(x))
),
Clause::ExternFn(xfn) => {
let Expr(xval, xtyp) = x.as_ref();
xfn.apply(xval.clone())
.map(|ret| box_once(Mrc::new(Expr(ret, Mrc::clone(xtyp)))))
.unwrap_or(box_empty())
},
// Parametric newtypes are atoms of function type
Clause::Atom(..) | Clause::Argument(..) | Clause::Apply(..) => box_empty(),
Clause::Literal(lit) =>
panic!("Literal expression {lit:?} can't be applied as function"),
Clause::Auto(..) | Clause::Explicit(..) =>
unreachable!("skip_autos should have filtered these"),
}
}),
direct_reductions(Mrc::clone(f)).map({
let typ = Mrc::clone(typ_ref);
let x = Mrc::clone(x);
move |f| Mrc::new(Expr(Clause::Apply(
f,
Mrc::clone(&x)
), Mrc::clone(&typ)))
}),
direct_reductions(Mrc::clone(x)).map({
let typ = Mrc::clone(typ_ref);
let f = Mrc::clone(f);
move |x| Mrc::new(Expr(Clause::Apply(
Mrc::clone(&f),
x
), Mrc::clone(&typ)))
})
),
Clause::Lambda(argt, body) => Box::new(direct_reductions(Mrc::clone(body)).map({
let typ = Mrc::clone(typ_ref);
let argt = argt.as_ref().map(Mrc::clone);
move |body| Mrc::new(Expr(Clause::Lambda(
argt.as_ref().map(Mrc::clone),
body
), Mrc::clone(&typ)))
})),
Clause::Literal(..) | Clause::ExternFn(..) | Clause::Atom(..) | Clause::Argument(..) =>
box_empty(),
Clause::Auto(..) | Clause::Explicit(..) =>
unreachable!("skip_autos should have filtered these"),
}
})
}

41
src/executor/syntax_eq.rs Normal file
View File

@@ -0,0 +1,41 @@
use std::hash::{Hasher, Hash};
use super::super::representations::typed::{Clause, Expr};
use super::super::utils::Stackframe;
/// Hash the parts of an expression that are required to be equal for syntactic equality.
pub fn syntax_eq_rec<H: Hasher>(
ex1: &Expr, ex1_stack: Stackframe<bool>,
ex2: &Expr, ex2_stack: Stackframe<bool>
) -> bool {
match clause {
// Skip autos and explicits
Clause::Auto(_, body) => partial_hash_rec(body, state, is_auto.push(true)),
Clause::Explicit(f, _) => partial_hash_rec(f, state, is_auto),
// Annotate everything else with a prefix
// - Recurse into the tree of lambdas and calls - classic lambda calc
Clause::Lambda(_, body) => {
state.write_u8(0);
partial_hash_rec(body, state, is_auto.push(false))
}
Clause::Apply(f, x) => {
state.write_u8(1);
partial_hash_rec(f, state, is_auto);
partial_hash_rec(x, state, is_auto);
}
// - Only recognize the depth of an argument if it refers to a non-auto parameter
Clause::Argument(depth) => {
// If the argument references an auto, acknowledge its existence
if *is_auto.iter().nth(*depth).unwrap_or(&false) {
state.write_u8(2)
} else {
state.write_u8(3);
state.write_usize(*depth)
}
}
// - Hash leaves like normal
Clause::Literal(lit) => { state.write_u8(4); lit.hash(state) }
Clause::Atom(at) => { state.write_u8(5); at.hash(state) }
Clause::ExternFn(f) => { state.write_u8(6); f.hash(state) }
}
}

View File

@@ -1,4 +1,5 @@
#![feature(specialization)]
#![feature(core_intrinsics)]
use std::env::current_dir;

View File

@@ -1,4 +1,5 @@
use chumsky::{self, prelude::*, Parser};
use mappable_rc::Mrc;
use crate::enum_parser;
use crate::representations::{Literal, ast::{Clause, Expr}};
use crate::utils::{to_mrc_slice, one_mrc_slice};
@@ -112,9 +113,8 @@ pub fn xpr_parser() -> impl Parser<Lexeme, Expr, Error = Simple<Lexeme>> {
sexpr_parser(expr.clone()),
lambda_parser(expr.clone()),
auto_parser(expr.clone()),
just(Lexeme::At).to(Clause::Name {
local: Some("@".to_string()),
qualified: one_mrc_slice("@".to_string())
just(Lexeme::At).ignore_then(expr.clone()).map(|arg| {
Clause::Explicit(Mrc::new(arg))
})
))).then_ignore(enum_parser!(Lexeme::Comment).repeated());
clause.clone().then(

View File

@@ -157,8 +157,13 @@ where
.filter_map(|ent| {
if let FileEntry::Rule(Rule{source, prio, target}, _) = ent {
Some(Rule {
source: source.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
target: target.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
source: source.iter()
.map(|ex| {
prefix_expr(ex, Mrc::clone(&path))
}).collect(),
target: target.iter().map(|ex| {
prefix_expr(ex, Mrc::clone(&path))
}).collect(),
prio: *prio,
})
} else { None }

View File

@@ -1,15 +1,22 @@
use mappable_rc::Mrc;
use itertools::Itertools;
use ordered_float::NotNan;
use std::hash::Hash;
use std::{hash::Hash, intrinsics::likely};
use std::fmt::Debug;
use crate::executor::{ExternFn, Atom};
use crate::utils::mrc_empty_slice;
use crate::{executor::{ExternFn, Atom}, utils::one_mrc_slice};
use super::Literal;
/// An S-expression with a type
#[derive(PartialEq, Eq, Hash)]
pub struct Expr(pub Clause, pub Mrc<[Clause]>);
impl Expr {
pub fn into_clause(self) -> Clause {
if likely(self.1.len() == 0) { self.0 }
else { Clause::S('(', one_mrc_slice(self)) }
}
}
impl Clone for Expr {
fn clone(&self) -> Self {
@@ -37,6 +44,7 @@ pub enum Clause {
qualified: Mrc<[String]>
},
S(char, Mrc<[Expr]>),
Explicit(Mrc<Expr>),
Lambda(String, Mrc<[Expr]>, Mrc<[Expr]>),
Auto(Option<String>, Mrc<[Expr]>, Mrc<[Expr]>),
ExternFn(ExternFn),
@@ -53,37 +61,49 @@ pub enum Clause {
impl Clause {
pub fn body(&self) -> Option<Mrc<[Expr]>> {
match self {
Clause::Auto(_, _, body) |
Clause::Lambda(_, _, body) |
Clause::S(_, body) => Some(Mrc::clone(body)),
Self::Auto(_, _, body) |
Self::Lambda(_, _, body) |
Self::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)),
Self::Auto(_, typ, _) | Self::Lambda(_, typ, _) => Some(Mrc::clone(typ)),
_ => None
}
}
pub fn into_expr(self) -> Expr {
if let Self::S('(', body) = &self {
if body.len() == 1 { body[0].clone() }
else { Expr(self, mrc_empty_slice()) }
} else { Expr(self, mrc_empty_slice()) }
}
pub fn from_exprv(exprv: Mrc<[Expr]>) -> Option<Clause> {
if exprv.len() == 0 { None }
else if exprv.len() == 1 { Some(exprv[0].clone().into_clause()) }
else { Some(Self::S('(', exprv)) }
}
}
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(
Self::S(c, b) => Self::S(*c, Mrc::clone(b)),
Self::Auto(n, t, b) => Self::Auto(
n.clone(), Mrc::clone(t), Mrc::clone(b)
),
Clause::Name { local: l, qualified: q } => Clause::Name {
Self::Name { local: l, qualified: q } => Self::Name {
local: l.clone(), qualified: Mrc::clone(q)
},
Clause::Lambda(n, t, b) => Clause::Lambda(
Self::Lambda(n, t, b) => Self::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())
Self::Placeh{key, vec} => Self::Placeh{key: key.clone(), vec: *vec},
Self::Literal(l) => Self::Literal(l.clone()),
Self::ExternFn(nc) => Self::ExternFn(nc.clone()),
Self::Atom(a) => Self::Atom(a.clone()),
Self::Explicit(expr) => Self::Explicit(Mrc::clone(expr))
}
}
}
@@ -127,7 +147,8 @@ impl Debug for Clause {
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:?}")
Self::Atom(a) => write!(f, "{a:?}"),
Self::Explicit(expr) => write!(f, "@{:?}", expr.as_ref())
}
}
}

View File

@@ -1,6 +1,6 @@
use mappable_rc::Mrc;
use crate::utils::{Stackframe, to_mrc_slice};
use crate::utils::{Stackframe, to_mrc_slice, mrc_empty_slice};
use super::{ast, typed};
@@ -26,7 +26,9 @@ pub enum Error {
///
/// [expr] handles this case, so it's only really possible to get this
/// error if you're calling [clause] directly
ExprToClause(typed::Expr)
ExprToClause(typed::Expr),
/// @ tokens only ever occur between a function and a parameter
NonInfixAt
}
/// Try to convert an expression from AST format to typed lambda
@@ -44,21 +46,37 @@ pub fn exprv(exprv: &[ast::Expr]) -> Result<typed::Expr, Error> {
exprv_rec(exprv, Stackframe::new(None))
}
fn apply_rec(f: typed::Expr, x: &ast::Expr, names: Stackframe<Option<&str>>)
-> Result<typed::Clause, Error> {
if let ast::Expr(ast::Clause::Explicit(inner), empty_slice) = x {
assert!(empty_slice.len() == 0,
"It is assumed that Explicit nodes can never have type annotations as the \
wrapped expression node matches all trailing colons."
);
let x = expr_rec(inner.as_ref(), names)?;
Ok(typed::Clause::Explicit(Mrc::new(f), Mrc::new(x)))
} else {
let x = expr_rec(x, names)?;
Ok(typed::Clause::Apply(Mrc::new(f), Mrc::new(x)))
}
}
/// 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)?;
let x = &head[1];
// 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![])))
tail.iter().fold(
apply_rec(f, x, names),
|acc, e| apply_rec(
typed::Expr(acc?, mrc_empty_slice()),
e,
names
)
).map(|cls| typed::Expr(cls, mrc_empty_slice()))
}
/// Recursive state of [expr]
@@ -115,6 +133,7 @@ fn clause_rec(cls: &ast::Clause, names: Stackframe<Option<&str>>)
else {Err(Error::ExprToClause(typed::Expr(val, typ)))}
},
ast::Clause::Name { local: None, .. } => Err(Error::Symbol),
ast::Clause::Placeh { .. } => Err(Error::Placeholder)
ast::Clause::Placeh { .. } => Err(Error::Placeholder),
ast::Clause::Explicit(..) => Err(Error::NonInfixAt)
}
}

View File

@@ -1,8 +1,13 @@
use hashbrown::HashMap;
use mappable_rc::Mrc;
use crate::{ast::{Expr, Clause}, utils::{iter::{box_once, into_boxed_iter}, to_mrc_slice, one_mrc_slice}, unwrap_or};
use super::{super::RuleError, state::{State, Entry}, slice_matcher::SliceMatcherDnC};
use crate::unwrap_or;
use crate::utils::{to_mrc_slice, one_mrc_slice, mrc_empty_slice};
use crate::utils::iter::{box_once, into_boxed_iter};
use crate::ast::{Expr, Clause};
use super::slice_matcher::SliceMatcherDnC;
use super::state::{State, Entry};
use super::super::RuleError;
fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>)
-> Result<(), String> {
@@ -86,10 +91,14 @@ where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
None
}
/// Fill in a template from a state as produced by a pattern
fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
eprintln!("Writing {tpl:?} with state {state:?}");
tpl.iter().flat_map(|Expr(clause, xpr_typ)| match clause {
// fn write_clause_rec(state: &State, clause: &Clause) ->
fn write_expr_rec(state: &State, Expr(tpl_clause, tpl_typ): &Expr) -> Box<dyn Iterator<Item = Expr>> {
let out_typ = tpl_typ.iter()
.flat_map(|c| write_expr_rec(state, &c.clone().into_expr()))
.map(Expr::into_clause)
.collect::<Mrc<[Clause]>>();
match tpl_clause {
Clause::Auto(name_opt, typ, body) => box_once(Expr(Clause::Auto(
name_opt.as_ref().and_then(|name| {
if let Some(state_key) = name.strip_prefix('$') {
@@ -102,9 +111,9 @@ fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
Some(name.to_owned())
}
}),
write_slice(state, typ),
write_slice(state, body)
), xpr_typ.to_owned())),
write_slice_rec(state, typ),
write_slice_rec(state, body)
), out_typ.to_owned())),
Clause::Lambda(name, typ, body) => box_once(Expr(Clause::Lambda(
if let Some(state_key) = name.strip_prefix('$') {
if let Entry::Name(name) = &state[state_key] {
@@ -113,13 +122,13 @@ fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
} else {
name.to_owned()
},
write_slice(state, typ),
write_slice(state, body)
), xpr_typ.to_owned())),
write_slice_rec(state, typ),
write_slice_rec(state, body)
), out_typ.to_owned())),
Clause::S(c, body) => box_once(Expr(Clause::S(
*c,
write_slice(state, body)
), xpr_typ.to_owned())),
write_slice_rec(state, body)
), out_typ.to_owned())),
Clause::Placeh{key, vec: None} => {
let real_key = unwrap_or!(key.strip_prefix('_'); key);
match &state[real_key] {
@@ -127,17 +136,30 @@ fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
Entry::Name(n) => box_once(Expr(Clause::Name {
local: Some(n.as_ref().to_owned()),
qualified: one_mrc_slice(n.as_ref().to_owned())
}, to_mrc_slice(vec![]))),
}, mrc_empty_slice())),
_ => panic!("Scalar template may only be derived from scalar placeholder"),
}
},
Clause::Placeh{key, vec: Some(_)} => if let Entry::Vec(v) = &state[key] {
into_boxed_iter(v.as_ref().to_owned())
} else {panic!("Vectorial template may only be derived from vectorial placeholder")},
Clause::Explicit(param) => {
assert!(out_typ.len() == 0, "Explicit should never have a type annotation");
box_once(Clause::Explicit(Mrc::new(
Clause::from_exprv(write_expr_rec(state, param).collect())
.expect("Result shorter than template").into_expr()
)).into_expr())
},
// Explicit base case so that we get an error if Clause gets new values
c@Clause::Literal(_) | c@Clause::Name { .. } | c@Clause::ExternFn(_) | c@Clause::Atom(_) =>
box_once(Expr(c.to_owned(), xpr_typ.to_owned()))
}).collect()
box_once(Expr(c.to_owned(), out_typ.to_owned()))
}
}
/// Fill in a template from a state as produced by a pattern
fn write_slice_rec(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
eprintln!("Writing {tpl:?} with state {state:?}");
tpl.iter().flat_map(|xpr| write_expr_rec(state, xpr)).collect()
}
/// Apply a rule (a pair of pattern and template) to an expression
@@ -156,6 +178,6 @@ pub fn execute(mut src: Mrc<[Expr]>, mut tgt: Mrc<[Expr]>, input: Mrc<[Expr]>)
let matcher_cache = SliceMatcherDnC::get_matcher_cache();
Ok(update_all_seqs(Mrc::clone(&input), &mut |p| {
let state = matcher.match_range_cached(p, &matcher_cache)?;
Some(write_slice(&state, &tgt))
Some(write_slice_rec(&state, &tgt))
}))
}

View File

@@ -28,6 +28,10 @@ where P: for<'a> FnOnce(&'a T) -> Option<&'a U> {
Mrc::try_map(Mrc::clone(m), p).ok()
}
pub fn mrc_empty_slice<T>() -> Mrc<[T]> {
mrc_derive_slice(&Mrc::new(Vec::new()))
}
pub fn to_mrc_slice<T>(v: Vec<T>) -> Mrc<[T]> {
Mrc::map(Mrc::new(v), |v| v.as_slice())
}