From d26db33422b720822b9b24b99ddadc3ffd36d752 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Wed, 13 Jan 2021 11:20:21 -0300 Subject: Finalize Holder design (hopefully) --- src/errors.rs | 10 ++++++++++ src/lib.rs | 35 ++++++++++++++++++++++++++++++++--- src/pattern.rs | 11 +++++++---- src/vm.rs | 18 +++++++++++------- 4 files changed, 60 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/errors.rs b/src/errors.rs index 4fc2144..ddc6a1a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,8 +1,18 @@ pub struct PatternError; +/// Error type returned by the matcher. #[derive(Clone)] pub enum MatchError { + /// Returned if the pattern nests too deeply. StackOverflow, + /// Returned if the pattern rejects the input. ValidationError, + /// Returned if the pattern attempts an unsupported operation. + /// + /// In particular, if the PatternTypes doesn't support get or pairs for a + /// given value, this error will be returned. It can be treated as a + /// ValidationError, or as a bug in the pattern, at the user's discretion. + UnsupportedOperation, + /// Returned if an unspecified non-critical error occurred. Other } diff --git a/src/lib.rs b/src/lib.rs index 9e84de1..f41b4c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,12 +5,41 @@ mod vm; pub use pattern::Pattern; -// TODO +// TODO investigate if this should be PatternTypes: Default +/// Defines the types and operations used for matching. pub trait PatternTypes { /// The value type. type Value; - type Iter; + + /// The owned key type. May be uninhabited. + // TODO replace with GATs. + type Key; + + /// Returns an iterator over key-value pairs contained within an item, or + /// None if this operation is unsupported for the given value. + fn pairs<'b>( + item: &'b Self::Value + ) -> Option + 'b>> { + // TODO remove these default impls that only exist for testing purposes + let x = None; + Some(Box::new(x.into_iter())) + } + + /// Returns an optional key-value pair keyed by the given key, or None if + /// this operation is unsupported for the given value. + fn get<'a, 'b>( + item: &'b Self::Value, + key: &'a str + ) -> Option> { + // TODO remove these default impls that only exist for testing purposes + Some(None) + } + + /// Returns whether two values are the same/equivalent. This must provide + /// the same guarantees as PartialEq. In fact, this is a replacement for + /// PartialEq for cases where it's not possible to just use PartialEq. + fn matches(left: &Self::Value, right: &Self::Value) -> bool; } // TODO -pub type Predicate = dyn (Fn(&::Value) -> bool) + Send + Sync; +type Predicate = dyn (Fn(&::Value) -> bool) + Send + Sync; diff --git a/src/pattern.rs b/src/pattern.rs index 8c57f00..0368a88 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -6,17 +6,20 @@ use crate::vm::PatternConstants; use crate::vm::MAX_CALLS; pub struct Pattern { - constants: PatternConstants, + consts: PatternConstants, } impl Pattern { pub fn compile(s: &str) -> Result { Ok(Self { - constants: parse(s)? + consts: parse(s)? }) } - pub fn attempt_match<'a, 'b>(&'a self, value: &'b T::Value) -> Matcher<'a, 'b, T> { - Matcher::new(value, &self.constants, self.constants.protos.len() - 1, MAX_CALLS).ok().expect("datafu internal error: MAX_CALLS must not be 0") + pub fn attempt_match<'a, 'b>( + &'a self, + value: &'b T::Value + ) -> Matcher<'a, 'b, T> { + Matcher::new(value, &self.consts, self.consts.protos.len() - 1, MAX_CALLS).ok().expect("datafu internal error: MAX_CALLS must not be 0") } } diff --git a/src/vm.rs b/src/vm.rs index 3131571..595fac1 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -19,6 +19,10 @@ pub(crate) struct PatternConstants { pub(crate) strings: Vec, pub(crate) regices: Vec<()/* TODO */>, pub(crate) predicates: Vec>>, + // NOTE these are part of the constant pool and so have lifetime analogous + // to 'a (consistently used to indicate constant pool lifetime) when used + // elsewhere. In particular, they can't be yielded by the iterator. + pub(crate) defs: Vec, } /// A pattern element. @@ -132,18 +136,16 @@ struct Holder<'a, 'b, T: PatternTypes> { name: Option<&'a str>, value: HolderState<'a, 'b, T>, parent: Option<&'b T::Value>, - //iterator: Box, MatchError>> + Capture<'a> + Capture<'b>>, - iterator: Box Option, MatchError>>>, - //iterator: T::Iter, + iterator: Box + 'b>, + filters: Vec Fn(&'c mut HolderState<'a, 'b, T>) + 'a>>, } impl<'a, 'b, T: PatternTypes> Holder<'a, 'b, T> { fn next(&mut self) -> Option> { if let Self { value: ref mut v, iterator: ref mut it, .. } = self { let is_subtree = v.is_subtree(); - *v = match it() { - Some(Ok(pair)) => pair, - Some(Err(e)) => return Some(Err(e)), + *v = match it.next() { + Some(pair) => HolderState::Key(pair), None => return None }; // just try to make sure the type doesn't change. @@ -160,7 +162,9 @@ impl<'a, 'b, T: PatternTypes> Default for Holder<'a, 'b, T> { name: Default::default(), value: HolderState::EmptyKey, parent: Default::default(), - iterator: Box::new(|| None), + // TODO https://github.com/rust-lang/rfcs/issues/3059 + iterator: Box::new(std::iter::empty()), + filters: Default::default(), } } } -- cgit 1.4.1