Skip to content

Commit

Permalink
Distinguish between invariants and invariant terms.
Browse files Browse the repository at this point in the history
This change introduces invariant _terms_, which are distinct from
invariants. Terms are independent types that are folded to compute the
variance of a token. When the fold of terms for a token is complete, the
final term is finalized into the invariant.

This allows variance computation via an intermediate type. This is not
yet exercised in this change, but is necessary for some invariants. In
particular, depth is not correctly computed: terminal separators are
miscounted. This is difficult to detect in a tree fold, but can be
accomplished with additional information in terms. However, this
information is only needed for the fold and is superfluous once the sum
is computed.
  • Loading branch information
olson-sean-k committed Mar 21, 2024
1 parent 6280daf commit 8860fe8
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 56 deletions.
3 changes: 1 addition & 2 deletions src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ impl<T, B> Variance<T, B> {
///
/// Depth describes the number of levels into a directory tree from some root that a path
/// represents and a [`Program`] may match. When variant, the bounds of depth are described by
/// [`VariantRange`]. For example, the glob expression `{server/log/,client/**/}*.log` has variant
/// depth of one or more (no upper bound).
/// [`VariantRange`].
///
/// [`Program`]: crate::Program
/// [`VariantRange`]: crate::query::VariantRange
Expand Down
33 changes: 18 additions & 15 deletions src/token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::str;
use crate::diagnostics::{Span, Spanned};
use crate::query::When;
use crate::token::variance::invariant::{IntoNominalText, IntoStructuralText};
use crate::token::variance::ops::{self, Conjunction};
use crate::token::variance::ops;
use crate::token::variance::{TreeExhaustiveness, TreeVariance, VarianceFold, VarianceTerm};
use crate::token::walk::{BranchFold, Fold, FoldMap, Starting, TokenEntry};
use crate::{StrExt as _, PATHS_ARE_CASE_INSENSITIVE};
Expand Down Expand Up @@ -447,12 +447,13 @@ impl<'t, A> Token<'t, A> {

pub fn variance<T>(&self) -> TokenVariance<T>
where
TreeVariance<T>: Fold<'t, A, Term = TokenVariance<T>>,
T: Conjunction<Output = T> + Invariant,
TreeVariance<T::Term>: Fold<'t, A, Term = TokenVariance<T::Term>>,
T: Invariant,
{
self.fold(TreeVariance::default())
.unwrap_or_else(Variance::zero)
.map_invariant(|invariant| ops::conjunction(T::once(), invariant))
T::finalize(
self.fold(TreeVariance::default())
.unwrap_or_else(Variance::zero),
)
}

pub fn invariant_text_prefix(&self) -> (usize, String) {
Expand Down Expand Up @@ -830,7 +831,7 @@ where
Repetition<'t, A>: VarianceFold<T>,
T: Invariant,
{
fn fold(&self, terms: Vec<TokenVariance<T>>) -> Option<TokenVariance<T>> {
fn fold(&self, terms: Vec<TokenVariance<T::Term>>) -> Option<TokenVariance<T::Term>> {
use BranchKind::{Alternation, Concatenation, Repetition};

match self {
Expand All @@ -840,7 +841,7 @@ where
}
}

fn finalize(&self, term: TokenVariance<T>) -> TokenVariance<T> {
fn finalize(&self, term: TokenVariance<T::Term>) -> TokenVariance<T::Term> {
use BranchKind::{Alternation, Concatenation, Repetition};

match self {
Expand Down Expand Up @@ -942,7 +943,7 @@ where
Wildcard: VarianceTerm<T>,
T: Invariant,
{
fn term(&self) -> TokenVariance<T> {
fn term(&self) -> TokenVariance<T::Term> {
use LeafKind::{Class, Literal, Separator, Wildcard};

match self {
Expand Down Expand Up @@ -1082,13 +1083,15 @@ impl Class {
where
Archetype: VarianceTerm<T>,
T: Invariant,
F: FnMut(TokenVariance<T>, TokenVariance<T>) -> TokenVariance<T>,
F: FnMut(TokenVariance<T::Term>, TokenVariance<T::Term>) -> TokenVariance<T::Term>,
{
self.archetypes()
.iter()
.map(Archetype::term)
.reduce(f)
.unwrap_or_else(Variance::zero)
T::finalize(
self.archetypes()
.iter()
.map(Archetype::term)
.reduce(f)
.unwrap_or_else(Variance::zero),
)
}
}

Expand Down
29 changes: 23 additions & 6 deletions src/token/variance/invariant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,28 @@ use std::num::NonZeroUsize;

use crate::token::variance::bound::{BoundedVariantRange, Boundedness, OpenedUpperBound};
use crate::token::variance::ops::{Conjunction, Disjunction, Product};
use crate::token::variance::TokenVariance;

pub use crate::token::variance::invariant::natural::{Depth, Size};
pub use crate::token::variance::invariant::text::{IntoNominalText, IntoStructuralText, Text};

pub type InvariantBound<T> = <T as BoundedVariance>::Bound;

pub trait BoundedVariance {
type Bound;
}

pub trait Identity {
fn zero() -> Self;
}

pub trait Invariant: Sized + Identity {
type Bound;
pub trait Invariant: BoundedVariance + Sized {
type Term: InvariantTerm<Bound = Self::Bound>;

fn once() -> Self {
Self::zero()
}
fn finalize(term: TokenVariance<Self::Term>) -> TokenVariance<Self>;
}

pub trait InvariantTerm: BoundedVariance + Identity + Sized {
fn bound(lhs: Self, rhs: Self) -> Boundedness<Self::Bound>;

fn into_lower_bound(self) -> Boundedness<Self::Bound>;
Expand Down Expand Up @@ -50,15 +57,25 @@ impl Breadth {
}
}

impl BoundedVariance for Breadth {
type Bound = ();
}

impl Identity for Breadth {
fn zero() -> Self {
Breadth
}
}

impl Invariant for Breadth {
type Bound = ();
type Term = Self;

fn finalize(term: TokenVariance<Self::Term>) -> TokenVariance<Self> {
term
}
}

impl InvariantTerm for Breadth {
fn bound(_: Self, _: Self) -> Boundedness<Self::Bound> {
().into()
}
Expand Down
15 changes: 11 additions & 4 deletions src/token/variance/invariant/natural.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::num::NonZeroUsize;
use crate::token::variance::bound::{
Bounded, BoundedVariantRange, Boundedness, Unbounded, VariantRange,
};
use crate::token::variance::invariant::{Identity, Invariant};
use crate::token::variance::invariant::{BoundedVariance, Identity, Invariant, InvariantTerm};
use crate::token::variance::ops::{self, Conjunction, Disjunction, Product};
use crate::token::variance::{TokenVariance, Variance};

Expand Down Expand Up @@ -45,6 +45,10 @@ macro_rules! impl_invariant_natural {
}
}

impl BoundedVariance for $name {
type Bound = BoundedVariantRange;
}

impl Conjunction for $name {
type Output = Self;

Expand Down Expand Up @@ -72,12 +76,15 @@ macro_rules! impl_invariant_natural {
}

impl Invariant for $name {
type Bound = BoundedVariantRange;
type Term = Self;

fn once() -> Self {
$name($once)
fn finalize(term: TokenVariance<Self::Term>) -> TokenVariance<Self> {
// TODO: This is incorrect.
term.map_invariant(|term| ops::conjunction(term, $name($once)))
}
}

impl InvariantTerm for $name {
fn bound(lhs: Self, rhs: Self) -> Boundedness<Self::Bound> {
let [lower, upper] = crate::minmax(lhs, rhs);
BoundedVariantRange::try_from_lower_and_upper(lower.0, upper.0)
Expand Down
16 changes: 14 additions & 2 deletions src/token/variance/invariant/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use std::num::NonZeroUsize;

use crate::encode;
use crate::token::variance::bound::{Boundedness, VariantRange};
use crate::token::variance::invariant::{Identity, Invariant, UnitBound};
use crate::token::variance::invariant::{
BoundedVariance, Identity, Invariant, InvariantTerm, UnitBound,
};
use crate::token::variance::ops::{self, Conjunction, Disjunction, Product};
use crate::token::variance::{TokenVariance, Variance};
use crate::PATHS_ARE_CASE_INSENSITIVE;
Expand Down Expand Up @@ -121,6 +123,10 @@ impl<'t> Text<'t> {
}
}

impl<'t> BoundedVariance for Text<'t> {
type Bound = UnitBound;
}

impl<'t> Conjunction for Text<'t> {
type Output = Self;

Expand Down Expand Up @@ -173,8 +179,14 @@ impl<'t> Identity for Text<'t> {
}

impl<'t> Invariant for Text<'t> {
type Bound = UnitBound;
type Term = Self;

fn finalize(term: TokenVariance<Self::Term>) -> TokenVariance<Self> {
term
}
}

impl<'t> InvariantTerm for Text<'t> {
fn bound(_: Self, _: Self) -> Boundedness<Self::Bound> {
UnitBound.into()
}
Expand Down
Loading

0 comments on commit 8860fe8

Please sign in to comment.