From 5ea2e02660eb9040676d7491c82d60d66575841a Mon Sep 17 00:00:00 2001 From: Sean Olson Date: Mon, 25 Mar 2024 15:37:03 -0700 Subject: [PATCH] Remove commented code and rename term items. --- src/token/mod.rs | 9 +- src/token/variance/invariant/mod.rs | 2 +- src/token/variance/invariant/natural.rs | 19 +- src/token/variance/invariant/separation.rs | 192 +++++---------------- src/token/variance/mod.rs | 34 ++-- 5 files changed, 74 insertions(+), 182 deletions(-) diff --git a/src/token/mod.rs b/src/token/mod.rs index 16180a1..77628ac 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -26,7 +26,9 @@ pub use crate::token::parse::{parse, ParseError, ROOT_SEPARATOR_EXPRESSION}; pub use crate::token::variance::bound::{ BoundedVariantRange, Boundedness, NaturalRange, VariantRange, }; -pub use crate::token::variance::invariant::{Separation, SeparatedTerm, Finalize, Breadth, Depth, DepthTerm, Invariant, Size, Text}; +pub use crate::token::variance::invariant::{ + Breadth, Depth, DepthTerm, Finalize, Invariant, Size, Text, +}; pub use crate::token::variance::{TokenVariance, Variance}; // TODO: Tree representations of expressions are intrusive and only differ in their annotations. @@ -1480,10 +1482,7 @@ impl VarianceTerm for Wildcard { impl VarianceTerm for Wildcard { fn term(&self) -> ::Term { match self { - Wildcard::Tree { .. } => BoundaryTerm::Conjunctive(SeparatedTerm( - Separation::Closed { is_coalescent: true }, - Variance::unbounded(), - )), + Wildcard::Tree { .. } => BoundaryTerm::unbounded(), _ => Zero::zero(), } } diff --git a/src/token/variance/invariant/mod.rs b/src/token/variance/invariant/mod.rs index 2827857..64229a0 100644 --- a/src/token/variance/invariant/mod.rs +++ b/src/token/variance/invariant/mod.rs @@ -10,7 +10,7 @@ use crate::token::variance::TokenVariance; pub use crate::token::variance::invariant::natural::{Depth, DepthTerm, Size}; pub use crate::token::variance::invariant::separation::{ - BoundaryTerm, SeparatedTerm, Separation, Finalize, + BoundaryTerm, Finalize, SeparatedTerm, Termination, }; pub use crate::token::variance::invariant::text::{IntoNominalText, IntoStructuralText, Text}; diff --git a/src/token/variance/invariant/natural.rs b/src/token/variance/invariant/natural.rs index d9531b8..07e579c 100644 --- a/src/token/variance/invariant/natural.rs +++ b/src/token/variance/invariant/natural.rs @@ -4,12 +4,11 @@ use crate::token::variance::bound::{ Bounded, BoundedVariantRange, Boundedness, Unbounded, VariantRange, }; use crate::token::variance::invariant::separation::{ - BoundaryTerm, Finalize, SeparatedTerm, Separation, + BoundaryTerm, Finalize, SeparatedTerm, Termination, }; use crate::token::variance::invariant::{BoundedVariance, Invariant, InvariantTerm, One, Zero}; use crate::token::variance::ops::{self, Conjunction, Disjunction, Product}; use crate::token::variance::{TokenVariance, Variance}; -use crate::token::Boundary; macro_rules! impl_natural_invariant_term { ($name:ident $(,)?) => { @@ -169,15 +168,13 @@ impl Finalize for SeparatedTerm> { type Output = TokenVariance; fn finalize(self) -> Self::Output { - use Boundary::Component; - use Separation::{Closed, First, Last, Open}; - use Variance::Invariant; - - let SeparatedTerm(separation, term) = self; - match separation { - Open => ops::conjunction(term, Invariant(Depth::ONE)), - First | Last => term, - Closed { .. } => term.map_invariant(|term| Depth(term.0.saturating_sub(1))), + use Termination::{Closed, Open}; + + let SeparatedTerm(termination, term) = self; + match termination { + Open => ops::conjunction(term, One::one()), + Closed => term.map_invariant(|term| term.map(|term| term.saturating_sub(1))), + _ => term, } } } diff --git a/src/token/variance/invariant/separation.rs b/src/token/variance/invariant/separation.rs index f11bb88..03d5302 100644 --- a/src/token/variance/invariant/separation.rs +++ b/src/token/variance/invariant/separation.rs @@ -1,12 +1,12 @@ -use itertools::{Itertools, Position}; +use itertools::Itertools; use std::collections::HashSet; use std::hash::Hash; use crate::token::variance::bound::Boundedness; -use crate::token::variance::invariant::{BoundedVariance, Invariant, One, Zero}; +use crate::token::variance::invariant::{BoundedVariance, One, Zero}; use crate::token::variance::ops::{self, Conjunction, Disjunction, Product}; use crate::token::variance::{TokenVariance, Variance}; -use crate::token::{Boundary, Composition}; +use crate::token::Composition; pub trait Finalize: Sized { type Output; @@ -21,21 +21,12 @@ where TokenVariance: Eq + Hash, T: BoundedVariance, { - //pub fn separator(term: TokenVariance) -> Self { - // BoundaryTerm::Conjunctive(SeparatedTerm::separator(term)) - //} - - //pub fn component(term: TokenVariance) -> Self { - // BoundaryTerm::Conjunctive(SeparatedTerm::component(term)) - //} - - //pub fn close_boundary_separation(self, position: Position) -> Self { - // match self { - // BoundaryTerm::Conjunctive(term) => BoundaryTerm::Conjunctive(term.close_boundary_separation(position)), - // // TODO: Is it necessary to close boundary separations in disjunctive terms? - // BoundaryTerm::Disjunctive(term) => BoundaryTerm::Disjunctive(term.remap(|term| term.close_boundary_separation(position))), - // } - //} + pub fn unbounded() -> Self { + BoundaryTerm::Conjunctive(SeparatedTerm( + Termination::Coalescent, + Variance::unbounded(), + )) + } pub fn as_variance(&self) -> Variance<&T, Option<&Boundedness>> { match self { @@ -49,8 +40,8 @@ pub type TreeTerm = Composition>; impl Conjunction for TreeTerm where - DisjunctiveTerm: Conjunction> - + Conjunction>, + DisjunctiveTerm: + Conjunction> + Conjunction>, T: Conjunction + Conjunction, Output = DisjunctiveTerm> + Eq @@ -267,106 +258,44 @@ where } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum Separation { - // TODO: While additional information is needed to close `Open` for separators, more general - // boundary information appears to be unnecessary. More importantly, this is insufficient - // to handle the "coalescence" of tree wildcards! This information likely needs to be - // pushed up. One algebra that seems to work is to immediately finalize tree wildcard - // terms in conjunctions (prior to performing the conjunction). The `Separation` is - // otherwise unaffected: tree wildcards are either `Last` or `Closed` and are always - // unbounded. They "just" have an implicit +1 in conjunctions for depth. This extra +1 - // ought to be specified per invariant rather than generalized for all `BoundaryTerm`s. - //Open(Option), +pub enum Coalescence { + Left(T), + Right(T), + Neither(T), +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Termination { Open, First, Last, - Closed { - is_coalescent: bool, - }, + Closed, + Coalescent, } -impl Separation { - pub fn is_coalescent(&self) -> bool { - match self { - Separation::Closed { ref is_coalescent } => *is_coalescent, - _ => false, - } - } -} - -impl Conjunction for Separation { - type Output = Self; +impl Conjunction for Termination { + type Output = Coalescence; fn conjunction(self, rhs: Self) -> Self::Output { - use Separation::{Closed, First, Last, Open}; + use Coalescence::{Left, Neither, Right}; + use Termination::{Closed, Coalescent, First, Last, Open}; match (self, rhs) { - (Closed { is_coalescent: lhs }, Closed { is_coalescent: rhs }) => Closed { is_coalescent: lhs && rhs }, - (First, Last | Closed { .. }) | (Closed { .. }, Last) => Closed { is_coalescent: false }, - (Last | Open, Closed { .. }) | (Last | Open, Last) => Last, - (Closed { .. }, First | Open) | (First, First | Open) => First, - (Open, First | Open) | (Last, First | Open) => Open, + (Coalescent, Coalescent) => Neither(Coalescent), + (Closed, Closed) | (First, Last | Closed) | (Closed, Last) => Neither(Closed), + (Last | Open, Closed) | (Last | Open, Last) => Neither(Last), + (Closed, First | Open) | (First, First | Open) => Neither(First), + (Open, First | Open) | (Last, First | Open) => Neither(Open), + (Coalescent, Closed | Last) => Right(Closed), + (Closed | First, Coalescent) => Left(Closed), + (Last | Open, Coalescent) => Left(Last), + (Coalescent, First | Open) => Right(First), } } } -//impl Disjunction for Separation { -// type Output = Self; -// -// fn disjunction(self, rhs: Self) -> Self::Output { -// use Separation::{First, Last, Terminal, Unit}; -// -// match (self, rhs) { -// (Terminal, _) | (_, Terminal) | (First, Last) | (Last, First) => Terminal, -// (Last, _) | (_, Last) => Last, -// (First, _) | (_, First) => First, -// _ => Unit, -// } -// } -//} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct SeparatedTerm(pub Separation, pub T); - -//impl SeparatedTerm { -// pub fn close_boundary_separation(self, position: Position) -> Self { -// use Boundary::{Component, Separator}; -// use Position::{First, Middle, Last, Only}; -// -// let SeparatedTerm(separation, term) = self; -// SeparatedTerm(match separation { -// separation @ Separation::Open(Some(boundary)) => match (boundary, position) { -// (Component, _) | (_, Only) => separation, -// (Separator, First) => Separation::First, -// (Separator, Middle) => Separation::Open(None), -// (Separator, Last) => Separation::Last, -// }, -// separation => separation, -// }, term) -// } -//} - -impl SeparatedTerm { - //pub fn separator(term: T) -> Self { - // SeparatedTerm(Separation::Open(Some(Boundary::Separator)), term) - //} - - //pub fn component(term: T) -> Self { - // SeparatedTerm(Separation::Open(Some(Boundary::Component)), term) - //} - - pub fn into_inner(self) -> T { - self.1 - } - - fn finalize_in_place(self) -> Self - where - Self: Finalize, - { - let separation = self.0; - SeparatedTerm(separation, self.finalize()) - } -} +pub struct SeparatedTerm(pub Termination, pub T); impl Conjunction> for SeparatedTerm where @@ -377,37 +306,18 @@ where type Output = SeparatedTerm; fn conjunction(self, rhs: SeparatedTerm) -> Self::Output { - let (lhs, rhs) = match (self.0.is_coalescent(), rhs.0.is_coalescent()) { - (true, true) => (self, rhs), - (true, _) => (self, rhs.finalize_in_place()), - (_, true) => (self.finalize_in_place(), rhs), - _ => (self, rhs), + use Coalescence::{Left, Neither, Right}; + + let lhs = self; + let (termination, lhs, rhs) = match ops::conjunction(lhs.0, rhs.0) { + Left(termination) => (termination, lhs.finalize(), rhs.1), + Right(termination) => (termination, lhs.1, rhs.finalize()), + Neither(termination) => (termination, lhs.1, rhs.1), }; - SeparatedTerm( - ops::conjunction(lhs.0, rhs.0), - ops::conjunction(lhs.1, rhs.1), - ) + SeparatedTerm(termination, ops::conjunction(lhs, rhs)) } } -//impl Disjunction> for Separated -//where -// Self: Finalize, -// Separated: Finalize>, -// T: Disjunction, -//{ -// type Output = Separated; -// -// fn disjunction(self, rhs: Separated) -> Self::Output { -// let lhs = self.finalize(); -// let rhs = rhs.finalize(); -// Separated( -// ops::disjunction(lhs.0, rhs.0), -// ops::disjunction(lhs.1, rhs.1), -// ) -// } -//} - impl Disjunction for SeparatedTerm where T: Eq + Hash, @@ -419,24 +329,12 @@ where } } -//impl Finalize for Separated> -//where -// T: BoundedVariance + Invariant, -//{ -// type Output = Self; -// -// fn finalize(self) -> Self { -// let separation = self.0; -// Separated(separation, T::finalize(self)) -// } -//} - impl One for SeparatedTerm where T: One, { fn one() -> Self { - SeparatedTerm(Separation::Closed { is_coalescent: false }, T::one()) + SeparatedTerm(Termination::Closed, T::one()) } } @@ -456,6 +354,6 @@ where T: Zero, { fn zero() -> Self { - SeparatedTerm(Separation::Open, T::zero()) + SeparatedTerm(Termination::Open, T::zero()) } } diff --git a/src/token/variance/mod.rs b/src/token/variance/mod.rs index f150bd0..94e1ac3 100644 --- a/src/token/variance/mod.rs +++ b/src/token/variance/mod.rs @@ -12,7 +12,7 @@ use crate::token::variance::bound::{ }; use crate::token::variance::invariant::{ BoundaryTerm, Breadth, Depth, DepthTerm, Invariant, InvariantBound, InvariantTerm, One, - SeparatedTerm, Separation, Text, UnitBound, Zero, + SeparatedTerm, Termination, Text, UnitBound, Zero, }; use crate::token::variance::ops::{Conjunction, Disjunction, Product}; use crate::token::walk::{ChildToken, Fold, Forward, ParentToken, Sequencer}; @@ -38,7 +38,7 @@ where } } -#[derive(Clone, Copy, Debug, Eq, Hash)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Variance> { Invariant(T), Variant(B), @@ -217,20 +217,6 @@ where } } -impl PartialEq for Variance -where - T: PartialEq, - B: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Variance::Invariant(ref left), Variance::Invariant(ref right)) => left == right, - (Variance::Variant(ref left), Variance::Variant(ref right)) => left == right, - _ => false, - } - } -} - impl Product for TokenVariance where Boundedness: Product>, @@ -369,7 +355,7 @@ impl<'t, A> Fold<'t, A> for TreeExhaustiveness { .into_inner(); if !all && any { return Some(BoundaryTerm::Conjunctive(SeparatedTerm( - Separation::Open, + Termination::Open, TokenVariance::::Variant(Bounded(BoundedVariantRange::Upper(unsafe { NonZeroUsize::new_unchecked(1) }))), @@ -527,28 +513,40 @@ mod tests { #[case("x/{a,a/b}", harness::range(2, 3))] #[case("{a,a/b}x", harness::range(1, 2))] #[case("{a,a/b}/x", harness::range(2, 3))] + #[case("{a,{a/b,a/b/c}}", harness::range(1, 3))] + #[case("{a/,{a/b/,a/b/c/}}x", harness::range(2, 4))] #[case("", harness::invariant(3))] #[case("", harness::range(0, 3))] #[case("x", harness::invariant(3))] #[case("x", harness::invariant(4))] + // TODO: Open components must not be empty. This means that `*` must match something if it + // comprises a component, for example. However, this is not yet tested and is not + // consistently emitted by the encoder: globs likely match incorrectly for such patterns! + // + // Note that patterns that include terminations in components may be empty. For example, + // `<*/>` explicitly includes the boundary `/`, and so may match empty content. This is + // also true of coalescing patterns (the tree wildcard `**`). #[case("*", harness::invariant(1))] #[case("a/*", harness::invariant(2))] #[case("a/*/b", harness::invariant(3))] #[case("*/a", harness::invariant(2))] #[case("{a,*}", harness::invariant(1))] #[case("*", harness::range(2, None))] + #[case("<*/>", Variance::unbounded())] #[case("<*/>*", harness::range(1, None))] #[case("</>*", harness::range(1, None))] #[case("*", harness::range(1, None))] #[case("**", Variance::unbounded())] #[case("a/**", harness::range(1, None))] #[case("a/**/b", harness::range(2, None))] - //#[case("a/<*/>b", harness::range(2, None))] #[case("a/**/b/**/c", harness::range(3, None))] #[case("*/**", harness::range(1, None))] #[case("**/*", harness::range(1, None))] #[case("**/*/**", harness::range(1, None))] #[case("{a/b/,c/**/}*.ext", harness::range(2, None))] + #[case("a/<*/>", harness::range(1, None))] + #[case("a/<*/>b", harness::range(2, None))] + #[case("<*/>a", harness::range(1, None))] fn parse_expression_depth_variance_eq( #[case] expression: &str, #[case] expected: TokenVariance,