Transfer commit

This commit is contained in:
2023-03-21 19:36:40 +00:00
parent 180ebb56fa
commit f3ce910f66
63 changed files with 1410 additions and 1023 deletions

View File

@@ -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()),

View File

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

View File

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

View File

@@ -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)?)))
}
}