From 0e5e2668137f58ce6e97a06b7aea31e0dcda004b Mon Sep 17 00:00:00 2001 From: Sean Olson Date: Fri, 26 Jan 2024 13:46:51 -0800 Subject: [PATCH] Rename items in fold APIs. --- src/token/mod.rs | 125 ++++++++++++++++++-------------------- src/token/variance/mod.rs | 31 ++-------- 2 files changed, 64 insertions(+), 92 deletions(-) diff --git a/src/token/mod.rs b/src/token/mod.rs index 5bea651..2380058 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -212,13 +212,10 @@ impl<'t, A> TokenTree<'t> for Tokenized<'t, A> { } } -// NOTE: Fold APIs are batched. They accept a complete sequence of terms rather than an accumulator -// and a single term. This incurs a performance penalty, but more easily supports -// aggregations that must consider the complete sequence of terms. While not yet implemented, -// this includes bounds in variance, in particular the variant bounds of breadth, where the -// terms must be partitioned to determine the bounds (they are disjunctive). This can be -// implemented using an accumulator, but requires additional state in either the `Fold` type, -// the `Term` type, or both. +// Fold APIs are batched: folds operate against a complete and ordered sequence of terms rather +// than an accumulator and a single subsequent term. This incurs a performance penalty, but +// supports aggregations that must consider the complete sequence of terms without the need for +// additional state in `Fold` implementers or `Term`s. pub trait Fold<'t, A> { type Term; @@ -228,8 +225,8 @@ pub trait Fold<'t, A> { fn fold(&mut self, branch: &BranchKind<'t, A>, terms: Vec) -> Option; - fn finalize(&mut self, _branch: &BranchKind<'t, A>, accumulator: Self::Term) -> Self::Term { - accumulator + fn finalize(&mut self, _branch: &BranchKind<'t, A>, term: Self::Term) -> Self::Term { + term } fn term(&mut self, leaf: &LeafKind<'t>) -> Self::Term; @@ -294,8 +291,8 @@ impl<'t, A> Token<'t, A> { // TODO: Implement this iteratively. Unfortunately, `fold_map` only maps annotations. This is // in some part a consequence of using an intrusive tree structure: it is difficult to - // expose a general mapping API over any and all data in nodes, because nodes also - // describe their topology (i.e., may directly contain children). + // expose a general mapping API over any and all data in nodes, because the inputs and + // outputs must be expressed in terms of `Token`. pub fn into_owned(self) -> Token<'static, A> { let Token { topology, @@ -348,23 +345,19 @@ impl<'t, A> Token<'t, A> { } } - // TODO: Reverse the iterator over child nodes when extending buffers rather than using - // `VecDeque` to maintain ordering in path node types here and in `fold_map`. - // TODO: The use of terms like "fold", "accumulate", "summand", "sum", and "term" are unclear - // and maybe inconsistent here (and elsewhere). Revisit such names. pub fn fold(&self, f: F) -> Option where F: Fold<'t, A>, { - struct Path<'i, 't, A, F> + struct TokenPath<'i, 't, A, F> where F: Fold<'t, A>, { - summands: Vec>, + branches: Vec>, f: F, } - impl<'i, 't, A, F> Path<'i, 't, A, F> + impl<'i, 't, A, F> TokenPath<'i, 't, A, F> where F: Fold<'t, A>, { @@ -373,27 +366,27 @@ impl<'t, A> Token<'t, A> { if let Some(term) = self.f.initialize(branch) { terms.push_front(term); } - self.summands.push(Summand { branch, terms }); + self.branches.push(TokenBranch { branch, terms }); } pub fn pop(&mut self, depth: usize) { - if let Some(n) = self.summands.len().checked_sub(depth) { + if let Some(n) = self.branches.len().checked_sub(depth) { self.fold_n(n); } } pub fn fold(mut self) -> Option { self.fold_n(usize::MAX); - self.summands + self.branches .pop() - .and_then(|summand| summand.fold(&mut self.f)) + .and_then(|branch| branch.fold(&mut self.f)) } pub fn accumulate(&mut self, leaf: &'i LeafKind<'t>) -> Result<(), F::Term> { let term = self.f.term(leaf); - match self.summands.last_mut() { - Some(summand) => { - summand.push(term); + match self.branches.last_mut() { + Some(branch) => { + branch.push(term); Ok(()) }, None => Err(term), @@ -401,23 +394,25 @@ impl<'t, A> Token<'t, A> { } fn fold_n(&mut self, n: usize) { - for _ in 0..cmp::min(n, self.summands.len().saturating_sub(1)) { - if let Some(term) = self.summands.pop().unwrap().fold(&mut self.f) { - self.summands.last_mut().unwrap().push(term); + for _ in 0..cmp::min(n, self.branches.len().saturating_sub(1)) { + if let Some(term) = self.branches.pop().unwrap().fold(&mut self.f) { + self.branches.last_mut().unwrap().push(term); } } } } - struct Summand<'i, 't, A, F> + struct TokenBranch<'i, 't, A, F> where F: Fold<'t, A>, { branch: &'i BranchKind<'t, A>, + // A queue is used to preserve the order of terms w.r.t. to the token tree and, more + // subtly, any initializer terms. terms: VecDeque, } - impl<'i, 't, A, F> Summand<'i, 't, A, F> + impl<'i, 't, A, F> TokenBranch<'i, 't, A, F> where F: Fold<'t, A>, { @@ -426,14 +421,14 @@ impl<'t, A> Token<'t, A> { } fn fold(self, f: &mut F) -> Option { - let Summand { branch, terms } = self; + let TokenBranch { branch, terms } = self; f.fold(branch, terms.into()) - .map(|accumulator| f.finalize(branch, accumulator)) + .map(|term| f.finalize(branch, term)) } } - let mut path = Path { - summands: vec![], + let mut path = TokenPath { + branches: vec![], f, }; let mut tokens = vec![(self, 0usize)]; @@ -464,25 +459,25 @@ impl<'t, A> Token<'t, A> { where F: FoldMap<'t, A>, { - struct Path<'t, A, F> + struct TokenPath<'t, A, F> where F: FoldMap<'t, A>, { - branches: Vec>, + branches: Vec>, f: F, } - impl<'t, A, F> Path<'t, A, F> + impl<'t, A, F> TokenPath<'t, A, F> where F: FoldMap<'t, A>, { pub fn push(&mut self, annotation: A, branch: BranchFold, hint: Option) { - self.branches.push(BranchNode { + self.branches.push(TokenBranch { annotation, branch, tokens: match hint { - Some(hint) => VecDeque::with_capacity(hint), - _ => VecDeque::new(), + Some(hint) => Vec::with_capacity(hint), + _ => vec![], }, }); } @@ -524,34 +519,34 @@ impl<'t, A> Token<'t, A> { } } - struct BranchNode<'t, A, F> + struct TokenBranch<'t, A, F> where F: FoldMap<'t, A>, { annotation: A, branch: BranchFold, - tokens: VecDeque>, + tokens: Vec>, } - impl<'t, A, F> BranchNode<'t, A, F> + impl<'t, A, F> TokenBranch<'t, A, F> where F: FoldMap<'t, A>, { fn push(&mut self, token: Token<'t, F::Annotation>) { - self.tokens.push_front(token) + self.tokens.push(token) } fn fold(self, f: &mut F) -> Option> { - let BranchNode { + let TokenBranch { annotation, branch, tokens, } = self; - f.fold(annotation, branch, tokens.into()) + f.fold(annotation, branch, tokens) } } - let mut path = Path { + let mut path = TokenPath { branches: vec![], f, }; @@ -562,7 +557,7 @@ impl<'t, A> Token<'t, A> { Topology::Branch(branch) => { let (branch, children) = branch.decompose(); let n = children.len(); - tokens.extend(children.into_iter().map(|token| (token, depth + 1))); + tokens.extend(children.into_iter().rev().map(|token| (token, depth + 1))); path.push(token.annotation, branch, Some(n)); }, Topology::Leaf(leaf) => { @@ -1128,13 +1123,13 @@ where } } - fn finalize(&self, accumulator: Variance) -> Variance { + fn finalize(&self, term: Variance) -> Variance { use BranchKind::{Alternation, Concatenation, Repetition}; match self { - Alternation(ref alternation) => alternation.finalize(accumulator), - Concatenation(ref concatenation) => concatenation.finalize(accumulator), - Repetition(ref repetition) => repetition.finalize(accumulator), + Alternation(ref alternation) => alternation.finalize(term), + Concatenation(ref concatenation) => concatenation.finalize(term), + Repetition(ref repetition) => repetition.finalize(term), } } } @@ -1595,14 +1590,14 @@ impl<'t, A> Repetition<'t, A> { )) } - fn repeat_or_union(&self, accumulator: Variance) -> Variance + fn repeat_or_union(&self, term: Variance) -> Variance where T: Invariant, { - self.repeat_or_else(accumulator, variance::union) + self.repeat_or_else(term, variance::union) } - fn repeat_or_else(&self, accumulator: Variance, f: F) -> Variance + fn repeat_or_else(&self, term: Variance, f: F) -> Variance where T: Invariant, F: FnOnce(Variance, Variance) -> Variance, @@ -1614,10 +1609,10 @@ impl<'t, A> Repetition<'t, A> { // both `encode::compile` and `rule::check` (in distinct but similar ways). Querying // token trees for an invariant must be done with care (after using these functions) to // avoid expanding pathological invariant expressions like ``. - accumulator.map_invariant(|text| text * n) + term.map_invariant(|text| text * n) } else { - f(accumulator, variance.map_invariant(|_| T::identity())) + f(term, variance.map_invariant(|_| T::identity())) } } } @@ -1657,10 +1652,10 @@ impl<'t, A> VarianceFold for Repetition<'t, A> { terms.into_iter().reduce(variance::union) } - fn finalize(&self, accumulator: Variance) -> Variance { - match accumulator { - Variance::Invariant(depth) if depth == 0 => accumulator, - _ => self.repeat_or_union(accumulator), + fn finalize(&self, term: Variance) -> Variance { + match term { + Variance::Invariant(depth) if depth == 0 => term, + _ => self.repeat_or_union(term), } } } @@ -1670,8 +1665,8 @@ impl<'t, A> VarianceFold for Repetition<'t, A> { terms.into_iter().reduce(variance::conjunction) } - fn finalize(&self, accumulator: Variance) -> Variance { - self.repeat_or_union(accumulator) + fn finalize(&self, term: Variance) -> Variance { + self.repeat_or_union(term) } } @@ -1680,8 +1675,8 @@ impl<'t, A> VarianceFold> for Repetition<'t, A> { terms.into_iter().reduce(variance::conjunction) } - fn finalize(&self, accumulator: Variance>) -> Variance> { - self.repeat_or_union(accumulator) + fn finalize(&self, term: Variance>) -> Variance> { + self.repeat_or_union(term) } } diff --git a/src/token/variance/mod.rs b/src/token/variance/mod.rs index f31877c..9673299 100644 --- a/src/token/variance/mod.rs +++ b/src/token/variance/mod.rs @@ -15,8 +15,8 @@ pub trait VarianceTerm { pub trait VarianceFold { fn fold(&self, terms: Vec>) -> Option>; - fn finalize(&self, accumulator: Variance) -> Variance { - accumulator + fn finalize(&self, term: Variance) -> Variance { + term } } @@ -290,8 +290,8 @@ where branch.fold(terms) } - fn finalize(&mut self, branch: &BranchKind<'t, A>, accumulator: Self::Term) -> Self::Term { - branch.finalize(accumulator) + fn finalize(&mut self, branch: &BranchKind<'t, A>, term: Self::Term) -> Self::Term { + branch.finalize(term) } fn term(&mut self, leaf: &LeafKind<'t>) -> Self::Term { @@ -299,29 +299,6 @@ where } } -// TODO: Replace and remove this. -/// Returns `true` if the token tree is exhaustive. -/// -/// A glob expression and its token tree are exhaustive if the terminal component has unbounded -/// depth and unbounded variance. -//pub fn is_exhaustive<'i, 't, A, I>(tokens: I) -> bool -//where -// 't: 'i, -// A: 't, -// I: IntoIterator>, -//{ -// let component = token::components(tokens).last(); -// matches!( -// component.map(|component| { -// ( -// component.depth(), -// component.variance::().bound(), -// ) -// }), -// Some((Bound::Unbounded, Bound::Unbounded)), -// ) -//} - pub fn conjunction(lhs: Variance, rhs: Variance) -> Variance where T: Invariant,