Public API and docs

This commit is contained in:
2023-05-26 15:23:15 +01:00
parent 3c1a6e2be2
commit fdf18e6ff8
99 changed files with 503 additions and 406 deletions

View File

@@ -3,7 +3,11 @@ use std::rc::Rc;
use super::state::State;
use crate::ast::Expr;
/// Cacheable optimized structures for matching patterns on slices. This is
/// injected to allow experimentation in the matcher implementation.
pub trait Matcher {
/// Build matcher for a pattern
fn new(pattern: Rc<Vec<Expr>>) -> Self;
/// Apply matcher to a token sequence
fn apply<'a>(&self, source: &'a [Expr]) -> Option<State<'a>>;
}

View File

@@ -25,9 +25,7 @@ fn scal_cnt<'a>(iter: impl Iterator<Item = &'a Expr>) -> usize {
iter.take_while(|expr| vec_attrs(expr).is_none()).count()
}
/// Recursively convert this pattern into a matcher that can be
/// efficiently applied to slices.
pub fn mk_matcher(pattern: &[Expr]) -> AnyMatcher {
pub fn mk_any(pattern: &[Expr]) -> AnyMatcher {
let left_split = scal_cnt(pattern.iter());
if pattern.len() <= left_split {
return AnyMatcher::Scalar(mk_scalv(pattern));
@@ -113,9 +111,9 @@ fn mk_scalar(pattern: &Expr) -> ScalMatcher {
);
ScalMatcher::Placeh(*name)
},
Clause::S(c, body) => ScalMatcher::S(*c, Box::new(mk_matcher(body))),
Clause::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body))),
Clause::Lambda(arg, body) =>
ScalMatcher::Lambda(Box::new(mk_scalar(arg)), Box::new(mk_matcher(body))),
ScalMatcher::Lambda(Box::new(mk_scalar(arg)), Box::new(mk_any(body))),
}
}
@@ -123,7 +121,7 @@ fn mk_scalar(pattern: &Expr) -> ScalMatcher {
mod test {
use std::rc::Rc;
use super::mk_matcher;
use super::mk_any;
use crate::ast::{Clause, PHClass, Placeholder};
use crate::interner::{InternedDisplay, Interner};
@@ -160,7 +158,7 @@ mod test {
})
.into_expr(),
];
let matcher = mk_matcher(&pattern);
let matcher = mk_any(&pattern);
println!("{}", matcher.bundle(&i));
}
}

View File

@@ -16,5 +16,5 @@ mod scal_match;
mod shared;
mod vec_match;
pub use build::mk_matcher;
pub use shared::AnyMatcher;
// pub use build::mk_matcher;
pub use shared::VectreeMatcher;

View File

@@ -2,14 +2,13 @@ use std::fmt::Write;
use std::rc::Rc;
use super::any_match::any_match;
use super::build::mk_matcher;
use super::build::mk_any;
use crate::ast::Expr;
use crate::interner::{InternedDisplay, Interner, Sym, Tok};
use crate::representations::Primitive;
use crate::rule::matcher::Matcher;
use crate::rule::state::State;
use crate::unwrap_or;
use crate::utils::{sym2string, Side};
use crate::utils::{sym2string, unwrap_or, Side};
pub enum ScalMatcher {
P(Primitive),
@@ -56,7 +55,7 @@ pub enum AnyMatcher {
}
impl Matcher for AnyMatcher {
fn new(pattern: Rc<Vec<Expr>>) -> Self {
mk_matcher(&pattern)
mk_any(&pattern)
}
fn apply<'a>(&self, source: &'a [Expr]) -> Option<State<'a>> {
@@ -177,3 +176,27 @@ impl InternedDisplay for AnyMatcher {
}
}
}
// ################ External ################
/// A [Matcher] implementation that builds a priority-order tree of the
/// vectorial placeholders and handles the scalars on leaves.
pub struct VectreeMatcher(AnyMatcher);
impl Matcher for VectreeMatcher {
fn new(pattern: Rc<Vec<Expr>>) -> Self {
Self(AnyMatcher::new(pattern))
}
fn apply<'a>(&self, source: &'a [Expr]) -> Option<State<'a>> {
self.0.apply(source)
}
}
impl InternedDisplay for VectreeMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
self.0.fmt_i(f, i)
}
}

View File

@@ -6,7 +6,7 @@ use super::scal_match::scalv_match;
use super::shared::VecMatcher;
use crate::ast::Expr;
use crate::rule::state::{State, StateEntry};
use crate::unwrap_or;
use crate::utils::unwrap_or;
pub fn vec_match<'a>(
matcher: &VecMatcher,

View File

@@ -1,5 +1,6 @@
//! Substitution rule processing
mod matcher;
mod matcher_second;
mod matcher_vectree;
mod prepare_rule;
mod repository;
mod rule_error;
@@ -7,6 +8,7 @@ mod state;
mod update_first_seq;
mod vec_attrs;
pub use matcher_second::AnyMatcher;
pub use matcher::Matcher;
pub use matcher_vectree::VectreeMatcher;
pub use repository::{Repo, Repository};
pub use rule_error::RuleError;

View File

@@ -22,24 +22,24 @@ fn pad(mut rule: Rule, i: &Interner) -> Rule {
location: Location::Unknown,
value: Clause::Placeh(Placeholder { name: i.i("::suffix"), class }),
}];
let rule_head = rule.source.first().expect("Src can never be empty!");
let rule_head = rule.pattern.first().expect("Src can never be empty!");
let prefix_explicit = vec_attrs(rule_head).is_some();
let rule_tail = rule.source.last().expect("Unreachable branch!");
let rule_tail = rule.pattern.last().expect("Unreachable branch!");
let suffix_explicit = vec_attrs(rule_tail).is_some();
let prefix_v = if prefix_explicit { empty } else { prefix };
let suffix_v = if suffix_explicit { empty } else { suffix };
rule.source = Rc::new(
rule.pattern = Rc::new(
prefix_v
.iter()
.chain(rule.source.iter())
.chain(rule.pattern.iter())
.chain(suffix_v.iter())
.cloned()
.collect(),
);
rule.target = Rc::new(
rule.template = Rc::new(
prefix_v
.iter()
.chain(rule.target.iter())
.chain(rule.template.iter())
.chain(suffix_v.iter())
.cloned()
.collect(),
@@ -118,8 +118,8 @@ fn check_rec_exprv(
pub fn prepare_rule(rule: Rule, i: &Interner) -> Result<Rule, RuleError> {
// Dimension check
let mut types = HashMap::new();
check_rec_exprv(&rule.source, &mut types, false)?;
check_rec_exprv(&rule.target, &mut types, true)?;
check_rec_exprv(&rule.pattern, &mut types, false)?;
check_rec_exprv(&rule.template, &mut types, true)?;
// Padding
Ok(pad(rule, i))
}

View File

@@ -8,7 +8,7 @@ use ordered_float::NotNan;
use super::matcher::Matcher;
use super::prepare_rule::prepare_rule;
use super::state::apply_exprv;
use super::{update_first_seq, AnyMatcher, RuleError};
use super::{update_first_seq, RuleError, VectreeMatcher};
use crate::ast::{Expr, Rule};
use crate::interner::{InternedDisplay, Interner, Sym};
use crate::utils::Substack;
@@ -16,7 +16,7 @@ use crate::utils::Substack;
#[derive(Debug)]
pub struct CachedRule<M: Matcher> {
matcher: M,
source: Rc<Vec<Expr>>,
pattern: Rc<Vec<Expr>>,
template: Rc<Vec<Expr>>,
}
@@ -26,7 +26,7 @@ impl<M: InternedDisplay + Matcher> InternedDisplay for CachedRule<M> {
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
for item in self.source.iter() {
for item in self.pattern.iter() {
item.fmt_i(f, i)?;
f.write_char(' ')?;
}
@@ -35,8 +35,13 @@ impl<M: InternedDisplay + Matcher> InternedDisplay for CachedRule<M> {
}
}
/// Manages a priority queue of substitution rules and allows to apply
/// them
/// Substitution rule scheduler
///
/// Manages a priority queue of rules and offers functions to apply them. The
/// rules are stored in an optimized structure but the repository is generic
/// over the implementation of this optimized form.
///
/// If you don't know what to put in the generic parameter, use [Repo]
pub struct Repository<M: Matcher> {
cache: Vec<(CachedRule<M>, HashSet<Sym>, NotNan<f64>)>,
}
@@ -52,14 +57,17 @@ impl<M: Matcher> Repository<M> {
let prio = r.prio;
let rule = prepare_rule(r.clone(), i).map_err(|e| (r, e))?;
let mut glossary = HashSet::new();
for e in rule.source.iter() {
for e in rule.pattern.iter() {
e.visit_names(Substack::Bottom, &mut |op| {
glossary.insert(op);
})
}
let matcher = M::new(rule.source.clone());
let prep =
CachedRule { matcher, source: rule.source, template: rule.target };
let matcher = M::new(rule.pattern.clone());
let prep = CachedRule {
matcher,
pattern: rule.pattern,
template: rule.template,
};
Ok((prep, glossary, prio))
})
.collect::<Result<Vec<_>, _>>()?;
@@ -163,4 +171,5 @@ impl<M: InternedDisplay + Matcher> InternedDisplay for Repository<M> {
}
}
pub type Repo = Repository<AnyMatcher>;
/// Repository with the default matcher implementation
pub type Repo = Repository<VectreeMatcher>;

View File

@@ -2,13 +2,16 @@ use std::fmt;
use crate::interner::{InternedDisplay, Interner, Tok};
/// Various reasons why a substitution rule may be invalid
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleError {
/// A key is present in the template but not the pattern
Missing(Tok<String>),
/// A key uses a different arity in the template and in the pattern
TypeMismatch(Tok<String>),
/// Multiple occurences of a placeholder in a pattern are no longer
/// supported.
/// Multiple occurences of a placeholder in a pattern
Multiple(Tok<String>),
/// Two vectorial placeholders are next to each other
VecNeighbors(Tok<String>, Tok<String>),
}

View File

@@ -5,7 +5,7 @@ use itertools::Itertools;
use crate::ast::{Clause, Expr, PHClass, Placeholder};
use crate::interner::Tok;
use crate::unwrap_or;
use crate::utils::unwrap_or;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StateEntry<'a> {