forked from Orchid/orchid
Most files suffered major changes
- Less ambiguous syntax - Better parser (Chumsky only does tokenization now) - Tidy(|ier) error handling - Facade for simplified embedding - External code grouped in (fairly) self-contained Systems - Dynamic action dispatch - Many STL additions
This commit is contained in:
@@ -112,7 +112,7 @@ fn mk_scalar(pattern: &RuleExpr) -> ScalMatcher {
|
||||
},
|
||||
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_any(body))),
|
||||
ScalMatcher::Lambda(Box::new(mk_any(arg)), Box::new(mk_any(body))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ pub fn scal_match<'a>(
|
||||
(ScalMatcher::S(c1, b_mat), Clause::S(c2, body)) if c1 == c2 =>
|
||||
any_match(b_mat, &body[..]),
|
||||
(ScalMatcher::Lambda(arg_mat, b_mat), Clause::Lambda(arg, body)) => {
|
||||
let mut state = scal_match(arg_mat, arg)?;
|
||||
let mut state = any_match(arg_mat, arg)?;
|
||||
state.extend(any_match(b_mat, body)?);
|
||||
Some(state)
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ pub enum ScalMatcher {
|
||||
P(Primitive),
|
||||
Name(Sym),
|
||||
S(char, Box<AnyMatcher>),
|
||||
Lambda(Box<ScalMatcher>, Box<AnyMatcher>),
|
||||
Lambda(Box<AnyMatcher>, Box<AnyMatcher>),
|
||||
Placeh(Tok<String>),
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ fn check_rec_expr(
|
||||
if !in_template {
|
||||
Err(RuleError::Multiple(*name))
|
||||
} else if known != typ {
|
||||
Err(RuleError::TypeMismatch(*name))
|
||||
Err(RuleError::ArityMismatch(*name))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@@ -79,7 +79,7 @@ fn check_rec_expr(
|
||||
}
|
||||
},
|
||||
Clause::Lambda(arg, body) => {
|
||||
check_rec_expr(arg.as_ref(), types, in_template)?;
|
||||
check_rec_exprv(arg, types, in_template)?;
|
||||
check_rec_exprv(body, types, in_template)
|
||||
},
|
||||
Clause::S(_, body) => check_rec_exprv(body, types, in_template),
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::format;
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use itertools::Itertools;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use super::matcher::{Matcher, RuleExpr};
|
||||
@@ -11,7 +12,6 @@ use super::state::apply_exprv;
|
||||
use super::{update_first_seq, RuleError, VectreeMatcher};
|
||||
use crate::ast::Rule;
|
||||
use crate::interner::{InternedDisplay, Interner};
|
||||
use crate::utils::Substack;
|
||||
use crate::Sym;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -60,9 +60,7 @@ impl<M: Matcher> Repository<M> {
|
||||
let rule = prepare_rule(r.clone(), i).map_err(|e| (r, e))?;
|
||||
let mut glossary = HashSet::new();
|
||||
for e in rule.pattern.iter() {
|
||||
e.visit_names(Substack::Bottom, &mut |op| {
|
||||
glossary.insert(*op);
|
||||
})
|
||||
glossary.extend(e.value.collect_names().into_iter());
|
||||
}
|
||||
let matcher = M::new(Rc::new(rule.pattern.clone()));
|
||||
let prep = CachedRule {
|
||||
@@ -78,10 +76,7 @@ impl<M: Matcher> Repository<M> {
|
||||
|
||||
/// Attempt to run each rule in priority order once
|
||||
pub fn step(&self, code: &RuleExpr) -> Option<RuleExpr> {
|
||||
let mut glossary = HashSet::new();
|
||||
code.visit_names(Substack::Bottom, &mut |op| {
|
||||
glossary.insert(*op);
|
||||
});
|
||||
let glossary = code.value.collect_names();
|
||||
for (rule, deps, _) in self.cache.iter() {
|
||||
if !deps.is_subset(&glossary) {
|
||||
continue;
|
||||
@@ -164,8 +159,13 @@ impl<M: InternedDisplay + Matcher> InternedDisplay for Repository<M> {
|
||||
i: &Interner,
|
||||
) -> std::fmt::Result {
|
||||
writeln!(f, "Repository[")?;
|
||||
for (item, _, p) in self.cache.iter() {
|
||||
write!(f, "\t{}", fmt_hex(f64::from(*p)))?;
|
||||
for (item, deps, p) in self.cache.iter() {
|
||||
write!(
|
||||
f,
|
||||
" priority: {}\tdependencies: [{}]\n ",
|
||||
fmt_hex(f64::from(*p)),
|
||||
deps.iter().map(|t| i.extern_vec(*t).join("::")).join(", ")
|
||||
)?;
|
||||
item.fmt_i(f, i)?;
|
||||
writeln!(f)?;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use crate::ast::{self, search_all_slcs, PHClass, Placeholder, Rule};
|
||||
use crate::error::{ErrorPosition, ProjectError};
|
||||
use crate::interner::{InternedDisplay, Interner, Tok};
|
||||
use crate::utils::BoxedIter;
|
||||
use crate::{Location, Sym};
|
||||
|
||||
/// Various reasons why a substitution rule may be invalid
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -8,12 +15,23 @@ 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>),
|
||||
ArityMismatch(Tok<String>),
|
||||
/// Multiple occurences of a placeholder in a pattern
|
||||
Multiple(Tok<String>),
|
||||
/// Two vectorial placeholders are next to each other
|
||||
VecNeighbors(Tok<String>, Tok<String>),
|
||||
}
|
||||
impl RuleError {
|
||||
/// Convert into a unified error trait object shared by all Orchid errors
|
||||
pub fn to_project_error(self, rule: &Rule<Sym>) -> Rc<dyn ProjectError> {
|
||||
match self {
|
||||
RuleError::Missing(name) => Missing::new(rule, name).rc(),
|
||||
RuleError::Multiple(name) => Multiple::new(rule, name).rc(),
|
||||
RuleError::ArityMismatch(name) => ArityMismatch::new(rule, name).rc(),
|
||||
RuleError::VecNeighbors(n1, n2) => VecNeighbors::new(rule, n1, n2).rc(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InternedDisplay for RuleError {
|
||||
fn fmt_i(&self, f: &mut fmt::Formatter<'_>, i: &Interner) -> fmt::Result {
|
||||
@@ -21,7 +39,7 @@ impl InternedDisplay for RuleError {
|
||||
Self::Missing(key) => {
|
||||
write!(f, "Key {:?} not in match pattern", i.r(key))
|
||||
},
|
||||
Self::TypeMismatch(key) => write!(
|
||||
Self::ArityMismatch(key) => write!(
|
||||
f,
|
||||
"Key {:?} used inconsistently with and without ellipsis",
|
||||
i.r(key)
|
||||
@@ -38,3 +56,181 @@ impl InternedDisplay for RuleError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A key is present in the template but not the pattern of a rule
|
||||
#[derive(Debug)]
|
||||
pub struct Missing {
|
||||
locations: HashSet<Location>,
|
||||
name: Tok<String>,
|
||||
}
|
||||
impl Missing {
|
||||
pub fn new(rule: &ast::Rule<Sym>, name: Tok<String>) -> Self {
|
||||
let mut locations = HashSet::new();
|
||||
for expr in rule.template.iter() {
|
||||
expr.search_all(&mut |e| {
|
||||
if let ast::Clause::Placeh(ph) = &e.value {
|
||||
if ph.name == name {
|
||||
locations.insert(e.location.clone());
|
||||
}
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
Self { locations, name }
|
||||
}
|
||||
}
|
||||
impl ProjectError for Missing {
|
||||
fn description(&self) -> &str {
|
||||
"A key appears in the template but not the pattern of a rule"
|
||||
}
|
||||
fn message(&self, i: &Interner) -> String {
|
||||
format!(
|
||||
"The key {} appears in the template but not the pattern of this rule",
|
||||
i.r(self.name)
|
||||
)
|
||||
}
|
||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
||||
Box::new(
|
||||
(self.locations.iter())
|
||||
.cloned()
|
||||
.map(|location| ErrorPosition { location, message: None }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A key is present multiple times in the pattern of a rule
|
||||
#[derive(Debug)]
|
||||
pub struct Multiple {
|
||||
locations: HashSet<Location>,
|
||||
name: Tok<String>,
|
||||
}
|
||||
impl Multiple {
|
||||
pub fn new(rule: &ast::Rule<Sym>, name: Tok<String>) -> Self {
|
||||
let mut locations = HashSet::new();
|
||||
for expr in rule.template.iter() {
|
||||
expr.search_all(&mut |e| {
|
||||
if let ast::Clause::Placeh(ph) = &e.value {
|
||||
if ph.name == name {
|
||||
locations.insert(e.location.clone());
|
||||
}
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
Self { locations, name }
|
||||
}
|
||||
}
|
||||
impl ProjectError for Multiple {
|
||||
fn description(&self) -> &str {
|
||||
"A key appears multiple times in the pattern of a rule"
|
||||
}
|
||||
fn message(&self, i: &Interner) -> String {
|
||||
format!("The key {} appears multiple times in this pattern", i.r(self.name))
|
||||
}
|
||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
||||
Box::new(
|
||||
(self.locations.iter())
|
||||
.cloned()
|
||||
.map(|location| ErrorPosition { location, message: None }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A key is present multiple times in the pattern of a rule
|
||||
#[derive(Debug)]
|
||||
pub struct ArityMismatch {
|
||||
locations: HashSet<(Location, ast::PHClass)>,
|
||||
name: Tok<String>,
|
||||
}
|
||||
impl ArityMismatch {
|
||||
pub fn new(rule: &ast::Rule<Sym>, name: Tok<String>) -> Self {
|
||||
let mut locations = HashSet::new();
|
||||
for expr in rule.template.iter() {
|
||||
expr.search_all(&mut |e| {
|
||||
if let ast::Clause::Placeh(ph) = &e.value {
|
||||
if ph.name == name {
|
||||
locations.insert((e.location.clone(), ph.class));
|
||||
}
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
Self { locations, name }
|
||||
}
|
||||
}
|
||||
impl ProjectError for ArityMismatch {
|
||||
fn description(&self) -> &str {
|
||||
"A key appears with different arities in a rule"
|
||||
}
|
||||
fn message(&self, i: &Interner) -> String {
|
||||
format!(
|
||||
"The key {} appears multiple times with different arities in this rule",
|
||||
i.r(self.name)
|
||||
)
|
||||
}
|
||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
||||
Box::new((self.locations.iter()).cloned().map(|(location, class)| {
|
||||
ErrorPosition {
|
||||
location,
|
||||
message: Some(
|
||||
"This instance represents ".to_string()
|
||||
+ match class {
|
||||
ast::PHClass::Scalar => "one clause",
|
||||
ast::PHClass::Vec { nonzero: true, .. } => "one or more clauses",
|
||||
ast::PHClass::Vec { nonzero: false, .. } =>
|
||||
"any number of clauses",
|
||||
},
|
||||
),
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Two vectorial placeholders appear next to each other
|
||||
#[derive(Debug)]
|
||||
pub struct VecNeighbors {
|
||||
locations: HashSet<Location>,
|
||||
n1: Tok<String>,
|
||||
n2: Tok<String>,
|
||||
}
|
||||
impl VecNeighbors {
|
||||
pub fn new(rule: &ast::Rule<Sym>, n1: Tok<String>, n2: Tok<String>) -> Self {
|
||||
let mut locations = HashSet::new();
|
||||
search_all_slcs(&rule.template[..], &mut |ev| {
|
||||
for pair in ev.windows(2) {
|
||||
let (a, b) = (&pair[0], &pair[1]);
|
||||
let a_vec = matches!(a.value, ast::Clause::Placeh(
|
||||
Placeholder{ class: PHClass::Vec { .. }, name }
|
||||
) if name == n1);
|
||||
let b_vec = matches!(b.value, ast::Clause::Placeh(
|
||||
Placeholder{ class: PHClass::Vec { .. }, name }
|
||||
) if name == n2);
|
||||
if a_vec && b_vec {
|
||||
locations.insert(a.location.clone());
|
||||
locations.insert(b.location.clone());
|
||||
}
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
Self { locations, n1, n2 }
|
||||
}
|
||||
}
|
||||
impl ProjectError for VecNeighbors {
|
||||
fn description(&self) -> &str {
|
||||
"Two vectorial placeholders appear next to each other"
|
||||
}
|
||||
fn message(&self, i: &Interner) -> String {
|
||||
format!(
|
||||
"The keys {} and {} appear next to each other with a vectorial arity",
|
||||
i.r(self.n1),
|
||||
i.r(self.n2)
|
||||
)
|
||||
}
|
||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
||||
Box::new(
|
||||
(self.locations.iter())
|
||||
.cloned()
|
||||
.map(|location| ErrorPosition { location, message: None }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::matcher::RuleExpr;
|
||||
use crate::ast::{Clause, Expr, PHClass, Placeholder};
|
||||
@@ -44,12 +43,7 @@ pub fn apply_expr(template: &RuleExpr, state: &State) -> Vec<RuleExpr> {
|
||||
Clause::Lambda(arg, body) => vec![Expr {
|
||||
location: location.clone(),
|
||||
value: Clause::Lambda(
|
||||
Rc::new(
|
||||
apply_expr(arg.as_ref(), state)
|
||||
.into_iter()
|
||||
.exactly_one()
|
||||
.expect("Lambda arguments can only ever be scalar"),
|
||||
),
|
||||
Rc::new(apply_exprv(arg, state)),
|
||||
Rc::new(apply_exprv(&body[..], state)),
|
||||
),
|
||||
}],
|
||||
|
||||
@@ -34,8 +34,8 @@ pub fn clause<F: FnMut(Rc<Vec<RuleExpr>>) -> Option<Rc<Vec<RuleExpr>>>>(
|
||||
match c {
|
||||
Clause::P(_) | Clause::Placeh { .. } | Clause::Name { .. } => None,
|
||||
Clause::Lambda(arg, body) =>
|
||||
if let Some(arg) = expr(arg.as_ref(), pred) {
|
||||
Some(Clause::Lambda(Rc::new(arg), body.clone()))
|
||||
if let Some(arg) = exprv(arg.clone(), pred) {
|
||||
Some(Clause::Lambda(arg, body.clone()))
|
||||
} else {
|
||||
exprv(body.clone(), pred).map(|body| Clause::Lambda(arg.clone(), body))
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user