From 119f41076e9e8a24fc91854be4e2d523ac119096 Mon Sep 17 00:00:00 2001 From: Lawrence Bethlenfalvy Date: Thu, 7 Jul 2022 01:25:50 +0200 Subject: [PATCH] simplified rule interface --- src/rule/bad_state_error.rs | 11 ++++++++ src/rule/executor.rs | 14 ++++++++++ src/rule/mod.rs | 7 ++++- src/rule/name.rs | 3 +++ src/rule/rule.rs | 54 ++++++++++++++++++++++--------------- 5 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 src/rule/bad_state_error.rs create mode 100644 src/rule/executor.rs create mode 100644 src/rule/name.rs diff --git a/src/rule/bad_state_error.rs b/src/rule/bad_state_error.rs new file mode 100644 index 0000000..91bde8c --- /dev/null +++ b/src/rule/bad_state_error.rs @@ -0,0 +1,11 @@ +use std::{fmt, error::Error}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BadState(Vec); + +impl fmt::Display for BadState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "The following key(s) weren't produced by the matching pattern: {:?}", self.0) + } +} +impl Error for BadState {} \ No newline at end of file diff --git a/src/rule/executor.rs b/src/rule/executor.rs new file mode 100644 index 0000000..ad9d8ed --- /dev/null +++ b/src/rule/executor.rs @@ -0,0 +1,14 @@ +use crate::expression::Expr; + +use super::{Rule, BadState}; + +pub fn execute(src: &Src, tgt: &Tgt, mut input: Vec) +-> Result<(Vec, bool), BadState> where Src: Rule, Tgt: Rule { + let (range, state) = match src.scan_slice(&input) { + Some(res) => res, + None => return Ok((input, false)) + }; + let output = tgt.write(&state)?; + input.splice(range, output); + Ok((input, true)) +} \ No newline at end of file diff --git a/src/rule/mod.rs b/src/rule/mod.rs index 2ef3b25..cef008b 100644 --- a/src/rule/mod.rs +++ b/src/rule/mod.rs @@ -1 +1,6 @@ -mod rule; \ No newline at end of file +mod rule; +mod executor; +mod bad_state_error; + +pub use rule::Rule; +pub use bad_state_error::BadState; \ No newline at end of file diff --git a/src/rule/name.rs b/src/rule/name.rs new file mode 100644 index 0000000..7ae0606 --- /dev/null +++ b/src/rule/name.rs @@ -0,0 +1,3 @@ +struct Name { + qualified: Vec +} \ No newline at end of file diff --git a/src/rule/rule.rs b/src/rule/rule.rs index 58574fc..d378fd3 100644 --- a/src/rule/rule.rs +++ b/src/rule/rule.rs @@ -1,38 +1,50 @@ -use std::cmp::{min, max}; +use std::{cmp::{min, max}, error::Error, fmt, ops::Range}; -use hashbrown::HashSet; +use hashbrown::HashMap; use crate::expression::Expr; +use super::BadState; + +type State = HashMap; + pub trait Rule { - type OutIter: Iterator>; + type Out: Iterator; /// The minimum and maximum set of symbols this rule may match. fn len(&self) -> (Option, Option); - /// The exact tokens the pattern consumes (None if varies) - fn consumes(&self) -> Option>>; - /// The exact tokens the pattern produces (None if varies) - fn produces(&self) -> Option>>; - /// Check if the slice matches, and produce the necessary transformations - fn produce(&self, base: &[Expr]) -> Option; + /// Check if the slice matches, and extract data + fn read(&self, input: &[Expr]) -> Option; + /// Construct item from state + fn write(&self, state: &State) -> Result; + /// Placeholders present in this pattern (all consumed must also be provided) + fn placeholders(&'_ self) -> &'_ [&'_ str]; /// Try all subsections of Vec of appropriate size, longest first, front-to-back - /// Match the first, execute the substitution, return the vector and whether any - /// substitutions happened - fn apply(&self, mut base: Vec) -> (Vec, bool) { + /// Match the first, return the position and produced state + fn scan_slice(&self, input: &[Expr]) -> Option<(Range, State)> { let len_range = self.len(); let lo = max(len_range.0.unwrap_or(1), 1); - let hi = min(len_range.1.unwrap_or(base.len()), base.len()); + let hi = min(len_range.1.unwrap_or(input.len()), input.len()); for width in (lo..hi).rev() { - let starts = (0..base.len() - width).into_iter(); + let starts = (0..input.len() - width).into_iter(); let first_match = starts.filter_map(|start| { - self.produce(&base[start..start+width]) - .map(|res| (start, res)) + let res = self.read(&input[start..start+width])?; + Some((start..start+width, res)) }).next(); - if let Some((start, substitution)) = first_match { - let diff = substitution.enumerate().filter_map(|(i, opt)| opt.map(|val| (i, val))); - for (idx, item) in diff { base[start + idx] = item } - return (base, true) + if first_match.is_some() { + return first_match; } } - (base, false) + None } +} + +pub fn verify(src: &Src, tgt: &Tgt) -> Option> where Src: Rule, Tgt: Rule { + let mut amiss: Vec = Vec::new(); + for ent in tgt.placeholders() { + if src.placeholders().iter().find(|x| x == &ent).is_none() { + amiss.push(ent.to_string()) + } + } + if amiss.len() > 0 { Some(amiss) } + else { None } } \ No newline at end of file