Converted Interner to work with Rc-s

- Interner no longer contains unsafe code
- Tokens now hold a reference to the value they represent directly

This will enable many future improvements
This commit is contained in:
2023-08-19 14:03:05 +01:00
parent ab0b57b1b8
commit 0b887ced70
62 changed files with 592 additions and 762 deletions

View File

@@ -64,7 +64,7 @@ fn mk_vec(pattern: &[RuleExpr]) -> VecMatcher {
let (r_sep, r_side) = right.split_at(r_sep_size);
let l_sep_size = scal_cnt(left.iter().rev());
let (l_side, l_sep) = left.split_at(left.len() - l_sep_size);
let main = VecMatcher::Placeh { key, nonzero };
let main = VecMatcher::Placeh { key: key.clone(), nonzero };
match (left, right) {
(&[], &[]) => VecMatcher::Placeh { key, nonzero },
(&[], _) => VecMatcher::Scan {
@@ -102,13 +102,13 @@ fn mk_vec(pattern: &[RuleExpr]) -> VecMatcher {
fn mk_scalar(pattern: &RuleExpr) -> ScalMatcher {
match &pattern.value {
Clause::P(p) => ScalMatcher::P(p.clone()),
Clause::Name(n) => ScalMatcher::Name(*n),
Clause::Name(n) => ScalMatcher::Name(n.clone()),
Clause::Placeh(Placeholder { name, class }) => {
debug_assert!(
!matches!(class, PHClass::Vec { .. }),
"Scalar matcher cannot be built from vector pattern"
);
ScalMatcher::Placeh(*name)
ScalMatcher::Placeh(name.clone())
},
Clause::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body))),
Clause::Lambda(arg, body) =>
@@ -122,7 +122,7 @@ mod test {
use super::mk_any;
use crate::ast::{Clause, PHClass, Placeholder};
use crate::interner::{InternedDisplay, Interner};
use crate::interner::Interner;
#[test]
fn test_scan() {
@@ -158,6 +158,6 @@ mod test {
.into_expr(),
];
let matcher = mk_any(&pattern);
println!("{}", matcher.bundle(&i));
println!("{matcher}");
}
}

View File

@@ -12,7 +12,7 @@ pub fn scal_match<'a>(
(ScalMatcher::P(p1), Clause::P(p2)) if p1 == p2 => Some(State::new()),
(ScalMatcher::Name(n1), Clause::Name(n2)) if n1 == n2 => Some(State::new()),
(ScalMatcher::Placeh(key), _) =>
Some(State::from([(*key, StateEntry::Scalar(expr))])),
Some(State::from([(key.clone(), StateEntry::Scalar(expr))])),
(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)) => {

View File

@@ -1,13 +1,15 @@
use std::fmt::Write;
use std::fmt::{Display, Write};
use std::rc::Rc;
use itertools::Itertools;
use super::any_match::any_match;
use super::build::mk_any;
use crate::interner::{InternedDisplay, Interner, Tok};
use crate::interner::Tok;
use crate::representations::Primitive;
use crate::rule::matcher::{Matcher, RuleExpr};
use crate::rule::state::State;
use crate::utils::{sym2string, unwrap_or, Side};
use crate::utils::Side;
use crate::Sym;
pub enum ScalMatcher {
@@ -63,115 +65,64 @@ impl Matcher for AnyMatcher {
}
}
// ################ InternedDisplay ################
// ################ Display ################
fn disp_scalv(
scalv: &[ScalMatcher],
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
let (head, tail) = unwrap_or!(scalv.split_first(); return Ok(()));
head.fmt_i(f, i)?;
for s in tail.iter() {
write!(f, " ")?;
s.fmt_i(f, i)?;
}
Ok(())
}
impl InternedDisplay for ScalMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for ScalMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::P(p) => write!(f, "{:?}", p),
Self::Placeh(n) => write!(f, "${}", i.r(*n)),
Self::Name(n) => write!(f, "{}", sym2string(*n, i)),
Self::Placeh(n) => write!(f, "${n}"),
Self::Name(n) => write!(f, "{}", n.extern_vec().join("::")),
Self::S(c, body) => {
f.write_char(*c)?;
body.fmt_i(f, i)?;
f.write_char(match c {
let pair = match c {
'(' => ')',
'[' => ']',
'{' => '}',
_ => unreachable!(),
})
};
write!(f, "{c}{body}{pair}")
},
Self::Lambda(arg, body) => {
f.write_char('\\')?;
arg.fmt_i(f, i)?;
f.write_char('.')?;
body.fmt_i(f, i)
write!(f, "\\{arg}.{body}")
},
}
}
}
impl InternedDisplay for VecMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for VecMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Placeh { key, nonzero } => {
if *nonzero {
f.write_char('.')?;
};
write!(f, "..${}", i.r(*key))
write!(f, "..${key}")
},
Self::Scan { left, sep, right, direction } => {
let arrow = match direction {
Side::Left => " <== ",
Side::Right => " ==> ",
};
write!(f, "Scan{{")?;
left.fmt_i(f, i)?;
f.write_str(arrow)?;
disp_scalv(sep, f, i)?;
f.write_str(arrow)?;
right.fmt_i(f, i)?;
write!(f, "}}")
Self::Scan { left, sep, right, direction } => match direction {
Side::Left =>
write!(f, "Scan{{{left} <== {} <== {right}}}", sep.iter().join(" ")),
Side::Right =>
write!(f, "Scan{{{left} ==> {} ==> {right}}}", sep.iter().join(" ")),
},
Self::Middle { left, left_sep, mid, right_sep, right, .. } => {
write!(f, "Middle{{")?;
left.fmt_i(f, i)?;
f.write_str("|")?;
disp_scalv(left_sep, f, i)?;
f.write_str("|")?;
mid.fmt_i(f, i)?;
f.write_str("|")?;
disp_scalv(right_sep, f, i)?;
f.write_str("|")?;
right.fmt_i(f, i)?;
write!(f, "}}")
let left_sep_s = left_sep.iter().join(" ");
let right_sep_s = right_sep.iter().join(" ");
write!(f, "Middle{{{left}|{left_sep_s}|{mid}|{right_sep_s}|{right}}}")
},
}
}
}
impl InternedDisplay for AnyMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for AnyMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Scalar(s) => {
write!(f, "(")?;
disp_scalv(s, f, i)?;
write!(f, ")")
write!(f, "({})", s.iter().join(" "))
},
Self::Vec { left, mid, right } => {
write!(f, "[")?;
disp_scalv(left, f, i)?;
write!(f, "|")?;
mid.fmt_i(f, i)?;
write!(f, "|")?;
disp_scalv(right, f, i)?;
write!(f, "]")
let lefts = left.iter().join(" ");
let rights = right.iter().join(" ");
write!(f, "[{lefts}|{mid}|{rights}]")
},
}
}
@@ -191,12 +142,8 @@ impl Matcher for VectreeMatcher {
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)
impl Display for VectreeMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}

View File

@@ -17,7 +17,7 @@ pub fn vec_match<'a>(
if *nonzero && seq.is_empty() {
return None;
}
return Some(State::from([(*key, StateEntry::Vec(seq))]));
return Some(State::from([(key.clone(), StateEntry::Vec(seq))]));
},
VecMatcher::Scan { left, sep, right, direction } => {
if seq.len() < sep.len() {

View File

@@ -64,16 +64,16 @@ fn check_rec_expr(
let typ = (*class).into();
// in a template, the type must be known and identical
// outside template (in pattern) the type must be unknown
if let Some(known) = types.insert(*name, typ) {
if let Some(known) = types.insert(name.clone(), typ) {
if !in_template {
Err(RuleError::Multiple(*name))
Err(RuleError::Multiple(name.clone()))
} else if known != typ {
Err(RuleError::ArityMismatch(*name))
Err(RuleError::ArityMismatch(name.clone()))
} else {
Ok(())
}
} else if in_template {
Err(RuleError::Missing(*name))
Err(RuleError::Missing(name.clone()))
} else {
Ok(())
}

View File

@@ -1,4 +1,4 @@
use std::fmt::{Debug, Write};
use std::fmt::{Debug, Display};
use std::format;
use std::rc::Rc;
@@ -11,7 +11,7 @@ use super::prepare_rule::prepare_rule;
use super::state::apply_exprv;
use super::{update_first_seq, RuleError, VectreeMatcher};
use crate::ast::Rule;
use crate::interner::{InternedDisplay, Interner};
use crate::interner::Interner;
use crate::Sym;
#[derive(Debug)]
@@ -21,18 +21,10 @@ pub struct CachedRule<M: Matcher> {
template: Vec<RuleExpr>,
}
impl<M: InternedDisplay + Matcher> InternedDisplay for CachedRule<M> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
for item in self.pattern.iter() {
item.fmt_i(f, i)?;
f.write_char(' ')?;
}
write!(f, "is matched by ")?;
self.matcher.fmt_i(f, i)
impl<M: Display + Matcher> Display for CachedRule<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let patterns = self.pattern.iter().join(" ");
write!(f, "{patterns} is matched by {}", self.matcher)
}
}
@@ -152,22 +144,14 @@ fn fmt_hex(num: f64) -> String {
format!("0x{:x}p{}", mantissa as i64, exponent as i64)
}
impl<M: InternedDisplay + Matcher> InternedDisplay for Repository<M> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl<M: Display + Matcher> Display for Repository<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Repository[")?;
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)?;
for (rule, deps, p) in self.cache.iter() {
let prio = fmt_hex(f64::from(*p));
let deps = deps.iter().map(|t| t.extern_vec().join("::")).join(", ");
writeln!(f, " priority: {prio}\tdependencies: [{deps}]")?;
writeln!(f, " {rule}")?;
}
write!(f, "]")
}

View File

@@ -1,16 +1,16 @@
use std::fmt;
use std::fmt::{self, Display};
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::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)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuleError {
/// A key is present in the template but not the pattern
Missing(Tok<String>),
@@ -33,25 +33,17 @@ impl RuleError {
}
}
impl InternedDisplay for RuleError {
fn fmt_i(&self, f: &mut fmt::Formatter<'_>, i: &Interner) -> fmt::Result {
match *self {
Self::Missing(key) => {
write!(f, "Key {:?} not in match pattern", i.r(key))
},
Self::ArityMismatch(key) => write!(
f,
"Key {:?} used inconsistently with and without ellipsis",
i.r(key)
),
Self::Multiple(key) => {
write!(f, "Key {:?} appears multiple times in match pattern", i.r(key))
},
impl Display for RuleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Missing(key) => write!(f, "Key {key} not in match pattern"),
Self::ArityMismatch(key) =>
write!(f, "Key {key} used inconsistently with and without ellipsis"),
Self::Multiple(key) =>
write!(f, "Key {key} appears multiple times in match pattern"),
Self::VecNeighbors(left, right) => write!(
f,
"Keys {:?} and {:?} are two vectorials right next to each other",
i.r(left),
i.r(right)
"Keys {left} and {right} are two vectorials right next to each other"
),
}
}
@@ -83,13 +75,13 @@ 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 {
fn message(&self) -> String {
format!(
"The key {} appears in the template but not the pattern of this rule",
i.r(self.name)
self.name
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
(self.locations.iter())
.cloned()
@@ -124,10 +116,10 @@ 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 message(&self) -> String {
format!("The key {} appears multiple times in this pattern", self.name)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
(self.locations.iter())
.cloned()
@@ -162,13 +154,13 @@ impl ProjectError for ArityMismatch {
fn description(&self) -> &str {
"A key appears with different arities in a rule"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"The key {} appears multiple times with different arities in this rule",
i.r(self.name)
self.name
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new((self.locations.iter()).cloned().map(|(location, class)| {
ErrorPosition {
location,
@@ -199,12 +191,12 @@ impl VecNeighbors {
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(
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(
) if name == &n1);
let b_vec = matches!(&b.value, ast::Clause::Placeh(
Placeholder{ class: PHClass::Vec { .. }, name }
) if name == n2);
) if name == &n2);
if a_vec && b_vec {
locations.insert(a.location.clone());
locations.insert(b.location.clone());
@@ -219,14 +211,13 @@ impl ProjectError for VecNeighbors {
fn description(&self) -> &str {
"Two vectorial placeholders appear next to each other"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"The keys {} and {} appear next to each other with a vectorial arity",
i.r(self.n1),
i.r(self.n2)
self.n1, self.n2
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
(self.locations.iter())
.cloned()

View File

@@ -5,13 +5,11 @@ use crate::interner::Tok;
/// Returns the name, priority and nonzero of the expression if it is
/// a vectorial placeholder
pub fn vec_attrs(expr: &RuleExpr) -> Option<(Tok<String>, u64, bool)> {
if let Clause::Placeh(Placeholder {
class: PHClass::Vec { prio, nonzero },
name,
}) = expr.value
{
Some((name, prio, nonzero))
} else {
None
match expr.value.clone() {
Clause::Placeh(Placeholder {
class: PHClass::Vec { prio, nonzero },
name,
}) => Some((name, prio, nonzero)),
_ => None,
}
}