Skip to content

Commit

Permalink
Remove dead, commented, and obsolete code and comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
olson-sean-k committed Feb 12, 2024
1 parent 885c876 commit a95f634
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 431 deletions.
230 changes: 5 additions & 225 deletions src/token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,235 +570,15 @@ impl<'t, A> Token<'t, A> {
}
}

pub fn is_exhaustive1(&self) -> bool {
// NOTE: False positives in this function may cause logic errors and are completely
// unacceptable. The discovery of a false positive here almost cetainly indicates a
// serious bug. False positives in negative patterns cause matching to incorrectly
// discard directory trees.
pub fn is_exhaustive(&self) -> bool {
self.fold(TreeExhaustiveness)
.as_ref()
.map_or(false, Variance::is_exhaustive)
}

// NOTE: False positives in this function may cause logic errors and are completely
// unacceptable. The discovery of a false positive here is likely a serious bug.
pub fn is_exhaustive(&self) -> bool {
type TokenNode<'i, 't, A> = TokenComposition<TokenSum<'i, 't, A>>;

impl<'i, 't, A> TokenNode<'i, 't, A> {
// NOTE: This differs from the `VarianceFold` implementations for branch tokens.
fn fold(&mut self, depth: VarianceOf<Depth>) {
use Bound::Unbounded;
use Variance::Variant;

match self {
Composition::Conjunctive(ref mut sum) => {
sum.depth = ops::conjunction(sum.depth, depth);
},
// TODO: See the `exhaustiveness` unit test. This yields a false positive for
// patterns like `{a/**,**/b}`! This computes the correct depth, which is
// necessary when composing alternations. Consider patterns like
// `<*{/,/}>`. However, this ultimately propagates unboundedness (despite
// the comment below: the computation in question is the conjunction of
// the identity and unbounded variance).
//
// While incomplete, a heuristic that requires all branches to compute
// unbounded depth is probably more acceptable. This can probably be
// accomplished using a batched fold for disjunctive tokens or using more
// elaborate terms for disjunctions. Imagine a type like
// `Exhaustiveness<VariantOf<Depth>>`.
Composition::Disjunctive(ref mut sum) => {
sum.depth = match depth {
// Compute the conjunction for unbounded terms. This bypasses the
// propagation of unbounded variance in disjunction, which is
// inappropriate here.
depth @ Variant(Unbounded) => ops::conjunction(sum.depth, depth),
depth => ops::disjunction(sum.depth, depth),
};
},
}
}

fn finalize(self, parent: Option<&mut Self>) -> Result<VarianceOf<Depth>, ()> {
use Variance::{Invariant, Variant};

let sum = self.get();
let term = sum.branch.map_or(sum.depth, |branch| match branch {
branch @ BranchKind::Repetition(_) => match sum.depth {
// When folding a term into a repetition, only finalize variant terms
// and the multiplicative identity and annihilator (one and zero). This
// is necessary, because natural bounds do not express the subset nor
// relationship of matched values within the range. Consider `<*/*/>`.
// This pattern is unbounded w.r.t. depth, but only matches paths with
// a depth that is a multiple of two and so is nonexhaustive. However,
// the similar pattern `<*/>` is exhaustive and matches any sub-tree of
// a match.
Invariant(Depth(0)) | Invariant(Depth(1)) | Variant(_) => {
branch.finalize(sum.depth)
},
_ => sum.depth,
},
branch => branch.finalize(sum.depth),
});
match parent {
Some(parent) => {
parent.fold(term);
Err(())
},
_ => Ok(term),
}
}
}

impl<'i, 't, A> From<&'i BranchKind<'t, A>> for TokenNode<'i, 't, A> {
fn from(branch: &'i BranchKind<'t, A>) -> Self {
let sum = TokenSum {
depth: Variance::identity(),
branch: Some(branch),
tokens: branch.tokens().into_inner().iter().collect(),
};
match branch.composition() {
Composition::Conjunctive(_) => Composition::Conjunctive(sum),
// TODO: This choice interacts with `fold`. Different initial depths seem
// unnecessary (even incorrect). Use `map` instead if that proves to be
// true.
//Composition::Disjunctive(_) => Composition::Disjunctive(TokenSum {
// depth: Variance::unbounded(),
// ..sum
//}),
Composition::Disjunctive(_) => Composition::Disjunctive(sum),
}
}
}

impl<'i, 't, A> From<&'i Token<'t, A>> for TokenNode<'i, 't, A> {
fn from(token: &'i Token<'t, A>) -> Self {
if let Some(branch) = token.as_branch() {
Self::from(branch)
}
else {
TokenNode::Conjunctive(TokenSum {
depth: Variance::identity(),
branch: None,
tokens: vec![token],
})
}
}
}

#[derive(Debug)]
struct TokenSum<'i, 't, A> {
depth: VarianceOf<Depth>,
branch: Option<&'i BranchKind<'t, A>>,
tokens: Vec<&'i Token<'t, A>>,
}

impl<'i, 't, A> TokenSum<'i, 't, A> {
fn reset(&mut self) {
self.depth = Variance::identity();
}
}

// TODO: Remove printing. :-)

fn display_sum<'i, 't, A>(sum: &TokenSum<'i, 't, A>) -> String {
format!(
"TokenSum {{\n\tdepth: {:?},\n\tbranch: {:?}\n\ttokens: {:?}\n}}",
sum.depth,
sum.branch.as_ref().copied().map(display_branch),
sum.tokens
.iter()
.copied()
.map(display_token)
.collect::<Vec<_>>(),
)
}

fn display_token<'t, A>(token: &Token<'t, A>) -> String {
match token.topology() {
TokenTopology::Branch(ref branch) => display_branch(branch),
TokenTopology::Leaf(ref leaf) => display_leaf(leaf),
}
}

fn display_branch<'t, A>(branch: &BranchKind<'t, A>) -> String {
match branch {
BranchKind::Alternation(_) => format!("Alternation"),
BranchKind::Concatenation(_) => format!("Concatenation"),
BranchKind::Repetition(ref repetition) => {
let (lower, upper) = repetition.bound_specification();
format!("Repetition([{},{:?}])", lower, upper)
},
}
}

fn display_leaf<'t>(leaf: &LeafKind<'t>) -> String {
match leaf {
LeafKind::Class(_) => format!("Class"),
LeafKind::Literal(ref literal) => format!("Literal(`{}`)", literal.text()),
LeafKind::Separator(_) => format!("Separator"),
LeafKind::Wildcard(ref wildcard) => match wildcard {
Wildcard::One => format!("ExactlyOne"),
Wildcard::ZeroOrMore(_) => format!("ZeroOrMore"),
Wildcard::Tree { .. } => format!("Tree"),
},
}
}

let mut tokens = vec![TokenNode::from(self)];
'node: while let Some(mut node) = tokens.pop() {
eprintln!("Popped node: {}", display_sum(node.get()));
'sum: while let Some(token) = node.as_mut().tokens.pop() {
eprintln!("Popped token: {}", display_token(&token));
match token.topology() {
TokenTopology::Branch(branch) => {
eprintln!("Pushing node and token.");
tokens.push(node);
tokens.push(branch.into());
continue 'node;
},
TokenTopology::Leaf(leaf) => {
if let None | Some(Boundary::Component) = token.boundary() {
eprintln!("Token is NOT separator.");
let breadth: VarianceOf<Breadth> = leaf.term();
let text: VarianceOf<Text> = leaf.term();
if breadth.is_bounded() || text.is_bounded() {
eprintln!(
"Token has bounded breadth or text.\n\tBreadth: {:?}\n\tDepth: {:?}",
breadth,
text,
);
let sum = node.as_mut();
if sum
.depth
.variant()
.map_or(true, |bound| bound.upper().into_bound().is_bounded())
{
eprintln!(
"Node has bounded depth: {:?}. Resetting.",
sum.depth,
);
sum.reset();
}
eprintln!("Node is now: {}", display_sum(node.get()));
break 'sum;
}
eprintln!("Token has unbounded breadth and text.");
}
let depth = leaf.term();
eprintln!("Folding token depth into node: {:?}", depth);
node.fold(depth);
eprintln!("Node is now: {}", display_sum(node.get()));
},
}
}
eprintln!("Stopped or exhausted tokens in node. Finalizing.");
if let Ok(term) = node.finalize(tokens.last_mut()) {
eprintln!("Exhausted nodes in tree. Exiting.\n\tDepth: {:?}", term);
//return term.is_unbounded();
return term
.variant()
.map_or(false, |bound| bound.upper().into_bound().is_unbounded());
}
}
unreachable!()
}
}

impl<'t, A> Token<'t, A> {
Expand Down
19 changes: 17 additions & 2 deletions src/token/variance/invariant/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
mod text;

use std::cmp::Ordering;
use std::num::NonZeroUsize;

use crate::token::variance::bound::{Bound, BoundedNonEmptyRange, NonEmptyRange, OpenedUpperBound};
use crate::token::variance::ops::{self, Conjunction, Disjunction, Product};
use crate::token::variance::{self, Variance};
use crate::token::variance::Variance;

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

Expand All @@ -25,6 +26,8 @@ pub trait Invariant: Sized {
fn into_lower_bound(self) -> Bound<Self::Bound>;
}

// TODO: This bound appears to be specific to `Text`. It does not compose properly for `Breadth`,
// which has fairly complex semantics. Rename, move, and specialize this type as needed.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct UnitBound;

Expand Down Expand Up @@ -205,7 +208,7 @@ macro_rules! impl_invariant_natural {
}

fn bound(lhs: Self, rhs: Self) -> Bound<Self::Bound> {
let (lower, upper) = variance::minmax(lhs, rhs);
let (lower, upper) = self::minmax(lhs, rhs);
BoundedNonEmptyRange::try_from_lower_and_upper(lower.0, upper.0)
.map_or(Bound::Unbounded, Bound::Bounded)
}
Expand Down Expand Up @@ -280,3 +283,15 @@ impl VarianceOf<Depth> {
.map_or(false, |bounds| bounds.upper().into_bound().is_unbounded())
}
}

fn minmax<T>(lhs: T, rhs: T) -> (T, T)
where
T: Ord,
{
use Ordering::{Equal, Greater, Less};

match lhs.cmp(&rhs) {
Equal | Less => (lhs, rhs),
Greater => (rhs, lhs),
}
}
Loading

0 comments on commit a95f634

Please sign in to comment.