Skip to content

Commit

Permalink
Unify invariant text prefix functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
olson-sean-k committed Jan 14, 2024
1 parent e758d83 commit db7de20
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 68 deletions.
44 changes: 44 additions & 0 deletions src/token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,50 @@ impl<'t, A> Token<'t, A> {
.map_invariant(|invariant| T::once() + invariant)
}

pub fn invariant_text_prefix(&self) -> (usize, String) {
#[derive(Clone, Debug)]
struct Prefix {
index: usize,
text: String,
}

let mut head = Prefix {
index: 0,
text: String::new(),
};
let mut checkpoint = None;
let tokens = self.conjunction().iter().peekable();
// TODO: The more correct predicate is, "Does this token have a root and variant text?"
// However, `has_root` is not quite correct, so rooted tree wildcards are detected
// explicitly instead to avoid shenanigans. See `has_root`.
if tokens.peek().map_or(false, |token| {
matches!(token.as_wildcard(), Wildcard::Tree { has_root: true, .. })
}) {
return (0, String::from(Separator::INVARIANT_TEXT));
}
for (n, token) in tokens.enumerate() {
match token.variance::<Text>() {
Variance::Invariant(text) => {
head.index = n;
head.text.push_str(text.to_string().as_ref());
if let Some(Boundary::Separator) = token.boundary() {
checkpoint = Some(head.clone());
}
},
_ => {
return match checkpoint {
Some(checkpoint) => (checkpoint.index + 1, checkpoint.text),
None => (0, String::new()),
};
},
}
}
(head.index + 1, head.text)
}

// TODO: Is root an invariant? This query is a bit odd. It returns `true` for alternations and
// repetitions (even with a lower bound of zero). Either way, this should probably return
// `When`, not `bool`.
pub fn has_root(&self) -> bool {
self.walk().starting().any(|(_, token)| {
token.as_leaf().map_or(false, |leaf| {
Expand Down
68 changes: 0 additions & 68 deletions src/token/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,74 +260,6 @@ where
}
}

// TODO: Is there some way to unify this with `invariant_text_prefix_upper_bound`?
pub fn invariant_text_prefix<'t, A, I>(tokens: I) -> String
where
A: 't,
I: IntoIterator<Item = &'t Token<'t, A>>,
{
let separator = &Separator::invariant_text();
let mut tokens = tokens.into_iter().peekable();
let mut prefix = String::new();
if tokens
.peek()
.map_or(false, |token| !token.has_sub_tokens() && token.has_root())
{
// Push a preceding separator if the first token has a root and is not a group. This
// ensures that initiating separators and tree wildcards express a root in invariant
// prefixes.
prefix.push_str(separator);
}
// TODO: Replace `map`, `take_while`, and `flatten` with `map_while` when it stabilizes.
prefix.push_str(
&token::components(tokens)
.map(|component| {
component
.variance::<Text>()
.as_invariant()
.map(Text::to_string)
.map(Cow::into_owned)
})
.take_while(Option::is_some)
.flatten()
.join(separator),
);
prefix
}

pub fn invariant_text_prefix_upper_bound<'t, A, I>(tokens: I) -> usize
where
A: 't,
I: IntoIterator<Item = &'t Token<'t, A>>,
{
use crate::token::TokenKind::{Separator, Wildcard};
use crate::token::Wildcard::Tree;

let mut m = 0usize;
let mut separator = None;
for (n, token) in tokens.into_iter().map(Token::kind).enumerate() {
m = n;
match token {
Separator(_) => {
separator = Some(n);
},
Wildcard(Tree { .. }) => {
return n;
},
_ => {
if token.variance::<Text>().is_invariant() {
continue;
}
return match separator {
Some(n) => n + 1,
None => 0,
};
},
}
}
m + 1
}

// TODO: Replace and remove this.
/// Returns `true` if the token tree is exhaustive.
///
Expand Down

0 comments on commit db7de20

Please sign in to comment.