forked from Orchid/orchid
Public API and docs
This commit is contained in:
@@ -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>>;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>),
|
||||
}
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user