forked from Orchid/orchid
Transfer commit
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use mappable_rc::Mrc;
|
||||
|
||||
use crate::unwrap_or;
|
||||
use crate::utils::{to_mrc_slice, one_mrc_slice, mrc_empty_slice, replace_first};
|
||||
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;
|
||||
@@ -14,7 +15,7 @@ use super::update_first_seq_rec;
|
||||
|
||||
fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>)
|
||||
-> Result<(), String> {
|
||||
let verify_clause = |clause: &Clause, is_vec: &mut HashMap<String, bool>| -> Result<(), String> {
|
||||
let verify_clause = |clause: &Clause, is_vec: &mut HashMap<String, bool>| {
|
||||
match clause {
|
||||
Clause::Placeh{key, vec} => {
|
||||
if let Some(known) = is_vec.get(key) {
|
||||
@@ -23,16 +24,24 @@ fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>)
|
||||
is_vec.insert(key.clone(), vec.is_some());
|
||||
}
|
||||
}
|
||||
Clause::Auto(name, typ, body) => {
|
||||
if let Some(key) = name.as_ref().and_then(|key| key.strip_prefix('$')) {
|
||||
if is_vec.get(key) == Some(&true) { return Err(key.to_string()) }
|
||||
Clause::Auto(name_opt, typ, body) => {
|
||||
if let Some(name) = name_opt.as_ref() {
|
||||
if let Clause::Placeh { key, vec } = name.as_ref() {
|
||||
if vec.is_some() || is_vec.get(key) == Some(&true) {
|
||||
return Err(key.to_string())
|
||||
}
|
||||
is_vec.insert(key.to_owned(), false);
|
||||
}
|
||||
}
|
||||
typ.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
|
||||
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
|
||||
}
|
||||
Clause::Lambda(name, typ, body) => {
|
||||
if let Some(key) = name.strip_prefix('$') {
|
||||
if is_vec.get(key) == Some(&true) { return Err(key.to_string()) }
|
||||
if let Clause::Placeh { key, vec } = name.as_ref() {
|
||||
if vec.is_some() || is_vec.get(key) == Some(&true) {
|
||||
return Err(key.to_string())
|
||||
}
|
||||
is_vec.insert(key.to_owned(), false);
|
||||
}
|
||||
typ.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
|
||||
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
|
||||
@@ -52,33 +61,56 @@ fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn slice_to_vec(src: &mut Mrc<[Expr]>, tgt: &mut Mrc<[Expr]>) {
|
||||
let prefix_expr = Expr(Clause::Placeh{key: "::prefix".to_string(), vec: Some((0, false))}, to_mrc_slice(vec![]));
|
||||
let postfix_expr = Expr(Clause::Placeh{key: "::postfix".to_string(), vec: Some((0, false))}, to_mrc_slice(vec![]));
|
||||
/// Ensure that src starts and ends with a vectorial placeholder without
|
||||
/// modifying the meaning of the substitution rule
|
||||
fn slice_to_vec(src: &mut Rc<Vec<Expr>>, tgt: &mut Rc<Vec<Expr>>) {
|
||||
let prefix_expr = Expr(Clause::Placeh{
|
||||
key: "::prefix".to_string(),
|
||||
vec: Some((0, false))
|
||||
}, Rc::default());
|
||||
let postfix_expr = Expr(Clause::Placeh{
|
||||
key: "::postfix".to_string(),
|
||||
vec: Some((0, false))
|
||||
}, Rc::default());
|
||||
// Prefix or postfix to match the full vector
|
||||
let head_multi = matches!(src.first().expect("Src can never be empty!").0, Clause::Placeh{vec: Some(_), ..});
|
||||
let tail_multi = matches!(src.last().expect("Impossible branch!").0, Clause::Placeh{vec: Some(_), ..});
|
||||
let head_multi = matches!(
|
||||
src.first().expect("Src can never be empty!").0,
|
||||
Clause::Placeh{vec: Some(_), ..}
|
||||
);
|
||||
let tail_multi = matches!(
|
||||
src.last().expect("Impossible branch!").0,
|
||||
Clause::Placeh{vec: Some(_), ..}
|
||||
);
|
||||
let prefix_vec = if head_multi {vec![]} else {vec![prefix_expr]};
|
||||
let postfix_vec = if tail_multi {vec![]} else {vec![postfix_expr]};
|
||||
*src = to_mrc_slice(prefix_vec.iter().chain(src.iter()).chain(postfix_vec.iter()).cloned().collect());
|
||||
*tgt = to_mrc_slice(prefix_vec.iter().chain(tgt.iter()).chain(postfix_vec.iter()).cloned().collect());
|
||||
*src = Rc::new(
|
||||
prefix_vec.iter()
|
||||
.chain(src.iter())
|
||||
.chain(postfix_vec.iter())
|
||||
.cloned().collect()
|
||||
);
|
||||
*tgt = Rc::new(
|
||||
prefix_vec.iter()
|
||||
.chain(tgt.iter())
|
||||
.chain(postfix_vec.iter())
|
||||
.cloned().collect()
|
||||
);
|
||||
}
|
||||
|
||||
/// keep re-probing the input with pred until it stops matching
|
||||
fn update_all_seqs<F>(input: Mrc<[Expr]>, pred: &mut F) -> Option<Mrc<[Expr]>>
|
||||
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
|
||||
fn update_all_seqs<F>(input: Rc<Vec<Expr>>, pred: &mut F)
|
||||
-> Option<Rc<Vec<Expr>>>
|
||||
where F: FnMut(Rc<Vec<Expr>>) -> Option<Rc<Vec<Expr>>> {
|
||||
let mut tmp = update_first_seq_rec::exprv(input, pred);
|
||||
while let Some(xv) = tmp {
|
||||
tmp = update_first_seq_rec::exprv(Mrc::clone(&xv), pred);
|
||||
tmp = update_first_seq_rec::exprv(xv.clone(), pred);
|
||||
if tmp.is_none() {return Some(xv)}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// 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>> {
|
||||
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)
|
||||
@@ -86,6 +118,11 @@ fn write_expr_rec(state: &State, Expr(tpl_clause, tpl_typ): &Expr) -> Box<dyn It
|
||||
match tpl_clause {
|
||||
Clause::Auto(name_opt, typ, body) => box_once(Expr(Clause::Auto(
|
||||
name_opt.as_ref().and_then(|name| {
|
||||
if let Clause::Placeh { key, .. } = name {
|
||||
match &state[key] {
|
||||
Entry::NameOpt(name) => name.as_ref().map(|s| s.as_ref().to_owned())
|
||||
}
|
||||
}
|
||||
if let Some(state_key) = name.strip_prefix('$') {
|
||||
match &state[state_key] {
|
||||
Entry::NameOpt(name) => name.as_ref().map(|s| s.as_ref().to_owned()),
|
||||
|
||||
@@ -11,14 +11,17 @@ use super::State;
|
||||
use super::split_at_max_vec::split_at_max_vec;
|
||||
|
||||
/// Tuple with custom cloning logic
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
pub struct CacheEntry<'a>(Mrc<[Expr]>, &'a SliceMatcherDnC);
|
||||
impl<'a> Clone for CacheEntry<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
let CacheEntry(mrc, matcher) = self;
|
||||
CacheEntry(Mrc::clone(mrc), matcher)
|
||||
}
|
||||
}
|
||||
// #[derive(Debug, Eq, PartialEq, Hash)]
|
||||
// pub struct CacheEntry<'a>(Mrc<[Expr]>, &'a SliceMatcherDnC);
|
||||
// impl<'a> Clone for CacheEntry<'a> {
|
||||
// fn clone(&self) -> Self {
|
||||
// let CacheEntry(mrc, matcher) = self;
|
||||
// CacheEntry(Mrc::clone(mrc), matcher)
|
||||
// }
|
||||
// }
|
||||
// ^^^^
|
||||
// This has been removed because the slice-based version needs no custom
|
||||
// cloning logic. In the next iteration, remove the this altogether.
|
||||
|
||||
|
||||
/// Matcher that applies a pattern to a slice via divide-and-conquer
|
||||
@@ -66,8 +69,8 @@ impl SliceMatcherDnC {
|
||||
matches!(self.clause.as_ref(), Clause::Placeh{vec: Some(..), ..})
|
||||
}
|
||||
/// If clause is a name, the qualified name this can match
|
||||
pub fn clause_qual_name(&self) -> Option<Mrc<[String]>> {
|
||||
if let Clause::Name { qualified, .. } = self.clause.as_ref() {Some(Mrc::clone(qualified))} else {None}
|
||||
pub fn clause_qual_name(&self) -> Option<Rc<Vec<Spur>>> {
|
||||
if let Clause::Name(name) = self.clause.as_ref() {Some(name.clone())} else {None}
|
||||
}
|
||||
/// If clause is a Placeh, the key in the state the match will be stored at
|
||||
pub fn state_key(&self) -> Option<&String> {
|
||||
@@ -89,8 +92,8 @@ impl SliceMatcherDnC {
|
||||
|
||||
/// Enumerate all valid subdivisions based on the reported size constraints of self and
|
||||
/// the two subranges
|
||||
pub fn valid_subdivisions(&self,
|
||||
range: Mrc<[Expr]>
|
||||
pub fn valid_subdivisions<'a>(&'a self,
|
||||
range: &'a [Expr]
|
||||
) -> impl Iterator<Item = (Mrc<[Expr]>, Mrc<[Expr]>, Mrc<[Expr]>)> {
|
||||
let own_max = unwrap_or!(self.own_max_size(range.len()); return box_empty());
|
||||
let own_min = self.own_min_size();
|
||||
@@ -196,7 +199,7 @@ impl SliceMatcherDnC {
|
||||
if !range.is_empty() {None}
|
||||
else {Some(State::new())}
|
||||
},
|
||||
Some(m) => cache.try_find(&CacheEntry(range, m)).map(|s| s.as_ref().to_owned())
|
||||
Some(m) => cache.find(&CacheEntry(range, m))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
use std::{ops::{Add, Index}, rc::Rc, fmt::Debug};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use lasso::Spur;
|
||||
|
||||
use crate::ast::Expr;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum Entry {
|
||||
Vec(Rc<Vec<Expr>>),
|
||||
Scalar(Rc<Expr>),
|
||||
Name(Rc<String>),
|
||||
NameOpt(Option<Rc<String>>)
|
||||
Name(Rc<Vec<Spur>>),
|
||||
NameOpt(Option<Rc<Vec<Spur>>>)
|
||||
}
|
||||
|
||||
/// A bucket of indexed expression fragments. Addition may fail if there's a conflict.
|
||||
@@ -55,33 +56,32 @@ impl State {
|
||||
}
|
||||
Some(self)
|
||||
}
|
||||
pub fn insert_name<S1, S2>(mut self, k: &S1, v: &S2) -> Option<Self>
|
||||
pub fn insert_name<S1>(mut self, k: &S1, v: &[Spur]) -> Option<Self>
|
||||
where
|
||||
S1: AsRef<str> + ToString + ?Sized,
|
||||
S2: AsRef<str> + ToString + ?Sized
|
||||
S1: AsRef<str> + ToString + ?Sized
|
||||
{
|
||||
if let Some(old) = self.0.get(k.as_ref()) {
|
||||
if let Entry::Name(val) = old {
|
||||
if val.as_str() != v.as_ref() {return None}
|
||||
if val.as_ref() != v.as_ref() {return None}
|
||||
} else {return None}
|
||||
} else {
|
||||
self.0.insert(k.to_string(), Entry::Name(Rc::new(v.to_string())));
|
||||
self.0.insert(k.to_string(), Entry::Name(Rc::new(v.to_vec())));
|
||||
}
|
||||
Some(self)
|
||||
}
|
||||
pub fn insert_name_opt<S1, S2>(mut self, k: &S1, v: Option<&S2>) -> Option<Self>
|
||||
where
|
||||
S1: AsRef<str> + ToString + ?Sized,
|
||||
S2: AsRef<str> + ToString + ?Sized
|
||||
pub fn insert_name_opt<S1, S2>(mut self, k: &S1, v: Option<&[Spur]>)
|
||||
-> Option<Self>
|
||||
where S1: AsRef<str> + ToString + ?Sized
|
||||
{
|
||||
if let Some(old) = self.0.get(k.as_ref()) {
|
||||
if let Entry::NameOpt(val) = old {
|
||||
if val.as_ref().map(|s| s.as_ref().as_str()) != v.map(|s| s.as_ref()) {
|
||||
if val.as_ref().map(|s| s.as_ref().as_slice()) != v {
|
||||
return None
|
||||
}
|
||||
} else {return None}
|
||||
} else {
|
||||
self.0.insert(k.to_string(), Entry::NameOpt(v.map(|s| Rc::new(s.to_string()))));
|
||||
let data = v.map(|s| Rc::new(s.to_vec()));
|
||||
self.0.insert(k.to_string(), Entry::NameOpt(data));
|
||||
}
|
||||
Some(self)
|
||||
}
|
||||
@@ -138,10 +138,4 @@ impl IntoIterator for State {
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for State {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,54 @@
|
||||
use mappable_rc::Mrc;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{ast::{Expr, Clause}, utils::{replace_first, to_mrc_slice}};
|
||||
use crate::utils::replace_first;
|
||||
use crate::ast::{Expr, Clause};
|
||||
|
||||
/// Traverse the tree, calling pred on every sibling list until it returns some vec
|
||||
/// then replace the sibling list with that vec and return true
|
||||
/// Traverse the tree, calling pred on every sibling list until it returns
|
||||
/// some vec then replace the sibling list with that vec and return true
|
||||
/// return false if pred never returned some
|
||||
pub fn exprv<F>(input: Mrc<[Expr]>, pred: &mut F) -> Option<Mrc<[Expr]>>
|
||||
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
|
||||
if let o@Some(_) = pred(Mrc::clone(&input)) {return o}
|
||||
pub fn exprv<F>(input: Rc<Vec<Expr>>, pred: &mut F) -> Option<Rc<Vec<Expr>>>
|
||||
where F: FnMut(Rc<Vec<Expr>>) -> Option<Rc<Vec<Expr>>> {
|
||||
if let o@Some(_) = pred(input.clone()) {return o}
|
||||
replace_first(input.as_ref(), |ex| expr(ex, pred))
|
||||
.map(|i| to_mrc_slice(i.collect()))
|
||||
.map(|i| Rc::new(i.collect()))
|
||||
}
|
||||
|
||||
pub fn expr<F>(Expr(cls, typ): &Expr, pred: &mut F) -> Option<Expr>
|
||||
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
|
||||
if let Some(t) = clausev(Mrc::clone(typ), pred) {return Some(Expr(cls.clone(), t))}
|
||||
if let Some(c) = clause(cls, pred) {return Some(Expr(c, Mrc::clone(typ)))}
|
||||
where F: FnMut(Rc<Vec<Expr>>) -> Option<Rc<Vec<Expr>>> {
|
||||
if let Some(t) = clausev(typ.clone(), pred) {return Some(Expr(cls.clone(), t))}
|
||||
if let Some(c) = clause(cls, pred) {return Some(Expr(c, typ.clone()))}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn clausev<F>(input: Mrc<[Clause]>, pred: &mut F) -> Option<Mrc<[Clause]>>
|
||||
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
|
||||
pub fn clausev<F>(input: Rc<Vec<Clause>>, pred: &mut F) -> Option<Rc<Vec<Clause>>>
|
||||
where F: FnMut(Rc<Vec<Expr>>) -> Option<Rc<Vec<Expr>>> {
|
||||
replace_first(input.as_ref(), |c| clause(c, pred))
|
||||
.map(|i| to_mrc_slice(i.collect()))
|
||||
.map(|i| Rc::new(i.collect()))
|
||||
}
|
||||
|
||||
pub fn clause<F>(c: &Clause, pred: &mut F) -> Option<Clause>
|
||||
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
|
||||
where F: FnMut(Rc<Vec<Expr>>) -> Option<Rc<Vec<Expr>>> {
|
||||
match c {
|
||||
Clause::P(_) | Clause::Placeh {..} | Clause::Name {..} => None,
|
||||
Clause::Lambda(n, typ, body) => {
|
||||
if let Some(b) = exprv(Mrc::clone(body), pred) {
|
||||
return Some(Clause::Lambda(n.clone(), Mrc::clone(typ), b))
|
||||
if let Some(b) = exprv(body.clone(), pred) {
|
||||
return Some(Clause::Lambda(n.clone(), typ.clone(), b))
|
||||
}
|
||||
if let Some(t) = exprv(Mrc::clone(typ), pred) {
|
||||
return Some(Clause::Lambda(n.clone(), t, Mrc::clone(body)))
|
||||
if let Some(t) = exprv(typ.clone(), pred) {
|
||||
return Some(Clause::Lambda(n.clone(), t, body.clone()))
|
||||
}
|
||||
None
|
||||
}
|
||||
Clause::Auto(n, typ, body) => {
|
||||
if let Some(b) = exprv(Mrc::clone(body), pred) {
|
||||
return Some(Clause::Auto(n.clone(), Mrc::clone(typ), b))
|
||||
if let Some(b) = exprv(body.clone(), pred) {
|
||||
return Some(Clause::Auto(n.clone(), typ.clone(), b))
|
||||
}
|
||||
if let Some(t) = exprv(Mrc::clone(typ), pred) {
|
||||
return Some(Clause::Auto(n.clone(), t, Mrc::clone(body)))
|
||||
if let Some(t) = exprv(typ.clone(), pred) {
|
||||
return Some(Clause::Auto(n.clone(), t, body.clone()))
|
||||
}
|
||||
None
|
||||
}
|
||||
Clause::S(c, body) => Some(Clause::S(*c, exprv(Mrc::clone(body), pred)?)),
|
||||
Clause::Explicit(t) => Some(Clause::Explicit(Mrc::new(expr(t, pred)?)))
|
||||
Clause::S(c, body) => Some(Clause::S(*c, exprv(body.clone(), pred)?)),
|
||||
Clause::Explicit(t) => Some(Clause::Explicit(Rc::new(expr(t, pred)?)))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user