executor, mostly
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -158,6 +158,7 @@ dependencies = [
|
|||||||
"derivative",
|
"derivative",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"mappable-rc",
|
"mappable-rc",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ mappable-rc = "0.1"
|
|||||||
ordered-float = "3.0"
|
ordered-float = "3.0"
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
smallvec = "1.10.0"
|
smallvec = "1.10.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
## Type definitions
|
## Type definitions
|
||||||
|
|
||||||
|
A new type can be created with the define expression, which associates a templated expression of
|
||||||
|
type `type` with a name and a template. The name allocated in this fashion is always representedas
|
||||||
|
an Atom of type `type` or some function that eventually returns `type`. The kind of the template
|
||||||
|
parameters is always inferred to be `type` rather than deduced from context.
|
||||||
|
|
||||||
|
The following type definition
|
||||||
|
|
||||||
```orc
|
```orc
|
||||||
define Cons as \T:type. loop \r. Option (Pair T r)
|
define Cons $T as loop \r. Option (Pair $T r)
|
||||||
```
|
```
|
||||||
|
|
||||||
Results in
|
results in these conditions:
|
||||||
- (Cons Int) is not assignable to @T. Option T
|
|
||||||
|
- (Cons Int) is not assignable to @T. Option T, or any other type expression that its
|
||||||
|
definitions would be assignable to, and vice versa.
|
||||||
- An instance of (Cons Int) can be constructed with `categorise @(Cons Int) (some (pair 1 none))`
|
- An instance of (Cons Int) can be constructed with `categorise @(Cons Int) (some (pair 1 none))`
|
||||||
but the type parameter can also be inferred from the expected return type
|
but the type parameter can also be inferred from the expected return type
|
||||||
- An instance of (Cons Int) can be deconstructed with `generalise @(Cons Int) numbers`
|
- An instance of (Cons Int) can be deconstructed with `generalise @(Cons Int) numbers`
|
||||||
@@ -28,8 +37,18 @@ The following must unify:
|
|||||||
Mult Int (Cons Int) (Cons Int)
|
Mult Int (Cons Int) (Cons Int)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Impls for types
|
## Typeclasses
|
||||||
|
|
||||||
Impls for types are generally not a good idea as autos with types like Int can
|
Typeclasses and types use the same define syntax. In fact, much like a type is nothing but a
|
||||||
often be used in dependent typing to represent eg. an index into a type-level conslist to be
|
distinguished instance of the underlying type with added meaning and constraints, a typeclass is
|
||||||
deduced by the compiler, and impls take precedence over resolution by unification.
|
nothing but a distinguished instance of the underlying function (or collection of functions) with
|
||||||
|
added meaning and constraints. A typeclass definition is therefore perfectly identical to a type
|
||||||
|
definition:
|
||||||
|
|
||||||
|
```
|
||||||
|
define Add $T $U $R as $T -> $U -> $R
|
||||||
|
```
|
||||||
|
|
||||||
|
It is clear that the definition of this type would match many, many functions, including
|
||||||
|
multiplication, so functions that should be considered addition are [impls](./impls.md) of the
|
||||||
|
typeclass Add.
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ An impl candidate can be used to resolve an auto if
|
|||||||
- it is not present in any other matching impl's override tree
|
- it is not present in any other matching impl's override tree
|
||||||
- all other candidates are present in its override tree
|
- all other candidates are present in its override tree
|
||||||
|
|
||||||
|
### Impls for types
|
||||||
|
|
||||||
|
Impls for types are generally not a good idea as autos with types like Int can
|
||||||
|
often be used in dependent typing to represent eg. an index into a type-level conslist to be
|
||||||
|
deduced by the compiler, and impls take precedence over resolution by unification.
|
||||||
|
|
||||||
In Rust impls can be placed in one of two modules; the trait owner, and the type owner. In orchid
|
In Rust impls can be placed in one of two modules; the trait owner, and the type owner. In orchid
|
||||||
that is not the case, so two additional possibilities arise that Rust's orphan rules prevent.
|
that is not the case, so two additional possibilities arise that Rust's orphan rules prevent.
|
||||||
|
|
||||||
|
|||||||
67
src/executor/apply_lambda.rs
Normal file
67
src/executor/apply_lambda.rs
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@ pub trait ExternError: Display {}
|
|||||||
|
|
||||||
/// Represents an externally defined function from the perspective of the executor
|
/// Represents an externally defined function from the perspective of the executor
|
||||||
/// Since Orchid lacks basic numerical operations, these are also external functions.
|
/// Since Orchid lacks basic numerical operations, these are also external functions.
|
||||||
#[derive(Eq)]
|
|
||||||
pub struct ExternFn {
|
pub struct ExternFn {
|
||||||
name: String, param: Mrc<Expr>, rttype: Mrc<Expr>,
|
name: String, param: Mrc<Expr>, rttype: Mrc<Expr>,
|
||||||
function: Mrc<dyn Fn(Clause) -> Result<Clause, Mrc<dyn ExternError>>>
|
function: Mrc<dyn Fn(Clause) -> Result<Clause, Mrc<dyn ExternError>>>
|
||||||
@@ -27,8 +26,8 @@ impl ExternFn {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn name(&self) -> &str {&self.name}
|
pub fn name(&self) -> &str {&self.name}
|
||||||
fn apply(&self, arg: Clause) -> Result<Clause, Mrc<dyn ExternError>> {(self.function)(arg)}
|
pub fn apply(&self, arg: Clause) -> Result<Clause, Mrc<dyn ExternError>> {(self.function)(arg)}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ExternFn { fn clone(&self) -> Self { Self {
|
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),
|
rttype: Mrc::clone(&self.rttype),
|
||||||
function: Mrc::clone(&self.function)
|
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 {
|
impl Hash for ExternFn {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.name.hash(state) }
|
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
|
/// 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
|
/// the kind of types. Ad absurdum it can also be just a number, although Literal is
|
||||||
/// preferable for types it's defined on.
|
/// preferable for types it's defined on.
|
||||||
#[derive(Eq)]
|
|
||||||
pub struct Atom {
|
pub struct Atom {
|
||||||
typ: Mrc<Expr>,
|
typ: Mrc<Expr>,
|
||||||
data: Mrc<dyn Atomic>
|
data: Mrc<dyn Atomic>
|
||||||
@@ -95,6 +96,7 @@ impl Debug for Atom {
|
|||||||
write!(f, "##ATOM[{:?}]:{:?}##", self.data(), self.typ)
|
write!(f, "##ATOM[{:?}]:{:?}##", self.data(), self.typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Eq for Atom {}
|
||||||
impl PartialEq for Atom {
|
impl PartialEq for Atom {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.data().definitely_eq(other.data().as_any())
|
self.data().definitely_eq(other.data().as_any())
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
mod foreign;
|
mod foreign;
|
||||||
|
// mod normalize;
|
||||||
|
mod partial_hash;
|
||||||
|
mod reduction_tree;
|
||||||
|
mod apply_lambda;
|
||||||
pub use foreign::ExternFn;
|
pub use foreign::ExternFn;
|
||||||
pub use foreign::Atom;
|
pub use foreign::Atom;
|
||||||
30
src/executor/normalize.rs
Normal file
30
src/executor/normalize.rs
Normal 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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
}
|
||||||
38
src/executor/partial_hash.rs
Normal file
38
src/executor/partial_hash.rs
Normal 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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/executor/reduction_tree.rs
Normal file
102
src/executor/reduction_tree.rs
Normal 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
41
src/executor/syntax_eq.rs
Normal 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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use chumsky::{self, prelude::*, Parser};
|
use chumsky::{self, prelude::*, Parser};
|
||||||
|
use mappable_rc::Mrc;
|
||||||
use crate::enum_parser;
|
use crate::enum_parser;
|
||||||
use crate::representations::{Literal, ast::{Clause, Expr}};
|
use crate::representations::{Literal, ast::{Clause, Expr}};
|
||||||
use crate::utils::{to_mrc_slice, one_mrc_slice};
|
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()),
|
sexpr_parser(expr.clone()),
|
||||||
lambda_parser(expr.clone()),
|
lambda_parser(expr.clone()),
|
||||||
auto_parser(expr.clone()),
|
auto_parser(expr.clone()),
|
||||||
just(Lexeme::At).to(Clause::Name {
|
just(Lexeme::At).ignore_then(expr.clone()).map(|arg| {
|
||||||
local: Some("@".to_string()),
|
Clause::Explicit(Mrc::new(arg))
|
||||||
qualified: one_mrc_slice("@".to_string())
|
|
||||||
})
|
})
|
||||||
))).then_ignore(enum_parser!(Lexeme::Comment).repeated());
|
))).then_ignore(enum_parser!(Lexeme::Comment).repeated());
|
||||||
clause.clone().then(
|
clause.clone().then(
|
||||||
|
|||||||
@@ -157,8 +157,13 @@ where
|
|||||||
.filter_map(|ent| {
|
.filter_map(|ent| {
|
||||||
if let FileEntry::Rule(Rule{source, prio, target}, _) = ent {
|
if let FileEntry::Rule(Rule{source, prio, target}, _) = ent {
|
||||||
Some(Rule {
|
Some(Rule {
|
||||||
source: source.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
|
source: source.iter()
|
||||||
target: target.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
|
.map(|ex| {
|
||||||
|
prefix_expr(ex, Mrc::clone(&path))
|
||||||
|
}).collect(),
|
||||||
|
target: target.iter().map(|ex| {
|
||||||
|
prefix_expr(ex, Mrc::clone(&path))
|
||||||
|
}).collect(),
|
||||||
prio: *prio,
|
prio: *prio,
|
||||||
})
|
})
|
||||||
} else { None }
|
} else { None }
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
use mappable_rc::Mrc;
|
use mappable_rc::Mrc;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use std::hash::Hash;
|
use std::{hash::Hash, intrinsics::likely};
|
||||||
use std::fmt::Debug;
|
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;
|
use super::Literal;
|
||||||
|
|
||||||
/// An S-expression with a type
|
/// An S-expression with a type
|
||||||
#[derive(PartialEq, Eq, Hash)]
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
pub struct Expr(pub Clause, pub Mrc<[Clause]>);
|
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 {
|
impl Clone for Expr {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
@@ -37,6 +44,7 @@ pub enum Clause {
|
|||||||
qualified: Mrc<[String]>
|
qualified: Mrc<[String]>
|
||||||
},
|
},
|
||||||
S(char, Mrc<[Expr]>),
|
S(char, Mrc<[Expr]>),
|
||||||
|
Explicit(Mrc<Expr>),
|
||||||
Lambda(String, Mrc<[Expr]>, Mrc<[Expr]>),
|
Lambda(String, Mrc<[Expr]>, Mrc<[Expr]>),
|
||||||
Auto(Option<String>, Mrc<[Expr]>, Mrc<[Expr]>),
|
Auto(Option<String>, Mrc<[Expr]>, Mrc<[Expr]>),
|
||||||
ExternFn(ExternFn),
|
ExternFn(ExternFn),
|
||||||
@@ -53,37 +61,49 @@ pub enum Clause {
|
|||||||
impl Clause {
|
impl Clause {
|
||||||
pub fn body(&self) -> Option<Mrc<[Expr]>> {
|
pub fn body(&self) -> Option<Mrc<[Expr]>> {
|
||||||
match self {
|
match self {
|
||||||
Clause::Auto(_, _, body) |
|
Self::Auto(_, _, body) |
|
||||||
Clause::Lambda(_, _, body) |
|
Self::Lambda(_, _, body) |
|
||||||
Clause::S(_, body) => Some(Mrc::clone(body)),
|
Self::S(_, body) => Some(Mrc::clone(body)),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn typ(&self) -> Option<Mrc<[Expr]>> {
|
pub fn typ(&self) -> Option<Mrc<[Expr]>> {
|
||||||
match self {
|
match self {
|
||||||
Clause::Auto(_, typ, _) | Clause::Lambda(_, typ, _) => Some(Mrc::clone(typ)),
|
Self::Auto(_, typ, _) | Self::Lambda(_, typ, _) => Some(Mrc::clone(typ)),
|
||||||
_ => None
|
_ => 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 {
|
impl Clone for Clause {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Clause::S(c, b) => Clause::S(*c, Mrc::clone(b)),
|
Self::S(c, b) => Self::S(*c, Mrc::clone(b)),
|
||||||
Clause::Auto(n, t, b) => Clause::Auto(
|
Self::Auto(n, t, b) => Self::Auto(
|
||||||
n.clone(), Mrc::clone(t), Mrc::clone(b)
|
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)
|
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)
|
n.clone(), Mrc::clone(t), Mrc::clone(b)
|
||||||
),
|
),
|
||||||
Clause::Placeh{key, vec} => Clause::Placeh{key: key.clone(), vec: *vec},
|
Self::Placeh{key, vec} => Self::Placeh{key: key.clone(), vec: *vec},
|
||||||
Clause::Literal(l) => Clause::Literal(l.clone()),
|
Self::Literal(l) => Self::Literal(l.clone()),
|
||||||
Clause::ExternFn(nc) => Clause::ExternFn(nc.clone()),
|
Self::ExternFn(nc) => Self::ExternFn(nc.clone()),
|
||||||
Clause::Atom(a) => Clause::Atom(a.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, true))} => write!(f, "...${key}:{prio}"),
|
||||||
Self::Placeh{key, vec: Some((prio, false))} => write!(f, "..${key}:{prio}"),
|
Self::Placeh{key, vec: Some((prio, false))} => write!(f, "..${key}:{prio}"),
|
||||||
Self::ExternFn(nc) => write!(f, "{nc:?}"),
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use mappable_rc::Mrc;
|
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};
|
use super::{ast, typed};
|
||||||
|
|
||||||
@@ -26,7 +26,9 @@ pub enum Error {
|
|||||||
///
|
///
|
||||||
/// [expr] handles this case, so it's only really possible to get this
|
/// [expr] handles this case, so it's only really possible to get this
|
||||||
/// error if you're calling [clause] directly
|
/// 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
|
/// 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))
|
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]
|
/// Recursive state of [exprv]
|
||||||
fn exprv_rec(v: &[ast::Expr], names: Stackframe<Option<&str>>) -> Result<typed::Expr, Error> {
|
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() == 0 {return Err(Error::EmptyS)}
|
||||||
if v.len() == 1 {return expr_rec(&v[0], names)}
|
if v.len() == 1 {return expr_rec(&v[0], names)}
|
||||||
let (head, tail) = v.split_at(2);
|
let (head, tail) = v.split_at(2);
|
||||||
let f = expr_rec(&head[0], names)?;
|
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.
|
// TODO this could probably be normalized, it's a third copy.
|
||||||
tail.iter().map(|e| expr_rec(e, names)).fold(
|
tail.iter().fold(
|
||||||
Ok(typed::Clause::Apply(Mrc::new(f), Mrc::new(x))),
|
apply_rec(f, x, names),
|
||||||
|acc, e| Ok(typed::Clause::Apply(
|
|acc, e| apply_rec(
|
||||||
Mrc::new(typed::Expr(acc?, to_mrc_slice(vec![]))),
|
typed::Expr(acc?, mrc_empty_slice()),
|
||||||
Mrc::new(e?)
|
e,
|
||||||
))
|
names
|
||||||
).map(|cls| typed::Expr(cls, to_mrc_slice(vec![])))
|
)
|
||||||
|
).map(|cls| typed::Expr(cls, mrc_empty_slice()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursive state of [expr]
|
/// 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)))}
|
else {Err(Error::ExprToClause(typed::Expr(val, typ)))}
|
||||||
},
|
},
|
||||||
ast::Clause::Name { local: None, .. } => Err(Error::Symbol),
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use mappable_rc::Mrc;
|
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 crate::unwrap_or;
|
||||||
use super::{super::RuleError, state::{State, Entry}, slice_matcher::SliceMatcherDnC};
|
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>)
|
fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>)
|
||||||
-> Result<(), String> {
|
-> Result<(), String> {
|
||||||
@@ -86,10 +91,14 @@ where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill in a template from a state as produced by a pattern
|
// fn write_clause_rec(state: &State, clause: &Clause) ->
|
||||||
fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
|
|
||||||
eprintln!("Writing {tpl:?} with state {state:?}");
|
fn write_expr_rec(state: &State, Expr(tpl_clause, tpl_typ): &Expr) -> Box<dyn Iterator<Item = Expr>> {
|
||||||
tpl.iter().flat_map(|Expr(clause, xpr_typ)| match clause {
|
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(
|
Clause::Auto(name_opt, typ, body) => box_once(Expr(Clause::Auto(
|
||||||
name_opt.as_ref().and_then(|name| {
|
name_opt.as_ref().and_then(|name| {
|
||||||
if let Some(state_key) = name.strip_prefix('$') {
|
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())
|
Some(name.to_owned())
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
write_slice(state, typ),
|
write_slice_rec(state, typ),
|
||||||
write_slice(state, body)
|
write_slice_rec(state, body)
|
||||||
), xpr_typ.to_owned())),
|
), out_typ.to_owned())),
|
||||||
Clause::Lambda(name, typ, body) => box_once(Expr(Clause::Lambda(
|
Clause::Lambda(name, typ, body) => box_once(Expr(Clause::Lambda(
|
||||||
if let Some(state_key) = name.strip_prefix('$') {
|
if let Some(state_key) = name.strip_prefix('$') {
|
||||||
if let Entry::Name(name) = &state[state_key] {
|
if let Entry::Name(name) = &state[state_key] {
|
||||||
@@ -113,13 +122,13 @@ fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
|
|||||||
} else {
|
} else {
|
||||||
name.to_owned()
|
name.to_owned()
|
||||||
},
|
},
|
||||||
write_slice(state, typ),
|
write_slice_rec(state, typ),
|
||||||
write_slice(state, body)
|
write_slice_rec(state, body)
|
||||||
), xpr_typ.to_owned())),
|
), out_typ.to_owned())),
|
||||||
Clause::S(c, body) => box_once(Expr(Clause::S(
|
Clause::S(c, body) => box_once(Expr(Clause::S(
|
||||||
*c,
|
*c,
|
||||||
write_slice(state, body)
|
write_slice_rec(state, body)
|
||||||
), xpr_typ.to_owned())),
|
), out_typ.to_owned())),
|
||||||
Clause::Placeh{key, vec: None} => {
|
Clause::Placeh{key, vec: None} => {
|
||||||
let real_key = unwrap_or!(key.strip_prefix('_'); key);
|
let real_key = unwrap_or!(key.strip_prefix('_'); key);
|
||||||
match &state[real_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 {
|
Entry::Name(n) => box_once(Expr(Clause::Name {
|
||||||
local: Some(n.as_ref().to_owned()),
|
local: Some(n.as_ref().to_owned()),
|
||||||
qualified: one_mrc_slice(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"),
|
_ => panic!("Scalar template may only be derived from scalar placeholder"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Clause::Placeh{key, vec: Some(_)} => if let Entry::Vec(v) = &state[key] {
|
Clause::Placeh{key, vec: Some(_)} => if let Entry::Vec(v) = &state[key] {
|
||||||
into_boxed_iter(v.as_ref().to_owned())
|
into_boxed_iter(v.as_ref().to_owned())
|
||||||
} else {panic!("Vectorial template may only be derived from vectorial placeholder")},
|
} 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
|
// 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(_) =>
|
c@Clause::Literal(_) | c@Clause::Name { .. } | c@Clause::ExternFn(_) | c@Clause::Atom(_) =>
|
||||||
box_once(Expr(c.to_owned(), xpr_typ.to_owned()))
|
box_once(Expr(c.to_owned(), out_typ.to_owned()))
|
||||||
}).collect()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
/// 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();
|
let matcher_cache = SliceMatcherDnC::get_matcher_cache();
|
||||||
Ok(update_all_seqs(Mrc::clone(&input), &mut |p| {
|
Ok(update_all_seqs(Mrc::clone(&input), &mut |p| {
|
||||||
let state = matcher.match_range_cached(p, &matcher_cache)?;
|
let state = matcher.match_range_cached(p, &matcher_cache)?;
|
||||||
Some(write_slice(&state, &tgt))
|
Some(write_slice_rec(&state, &tgt))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ where P: for<'a> FnOnce(&'a T) -> Option<&'a U> {
|
|||||||
Mrc::try_map(Mrc::clone(m), p).ok()
|
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]> {
|
pub fn to_mrc_slice<T>(v: Vec<T>) -> Mrc<[T]> {
|
||||||
Mrc::map(Mrc::new(v), |v| v.as_slice())
|
Mrc::map(Mrc::new(v), |v| v.as_slice())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user