Skip to content

Commit

Permalink
Don't delimit front tilde expansion at colon
Browse files Browse the repository at this point in the history
This is the exact behavior that is required by POSIX.
  • Loading branch information
magicant committed May 6, 2024
1 parent 68ec273 commit fbb1ac1
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 27 deletions.
2 changes: 2 additions & 0 deletions yash-syntax/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Lexer::source_string` is no longer generic. The argument type is now
`Range<usize>` instead of a generic implementor of
`SliceIndex<[SourceChar], Output = [SourceChar]>`.
- `Word::parse_tilde_front` no longer delimits the tilde expansion at an
unquoted `:` character.
- `WordLexer::braced_param` now returns `Err(SyntaxError::EmptyParam)` if `{`
is not followed by any name characters. Previously, it returned
`Err(SyntaxError::UnclosedParam{…})` if `{` was followed by a non-name
Expand Down
31 changes: 12 additions & 19 deletions yash-syntax/src/parser/lex/tilde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ use std::iter::Peekable;
/// Parses a tilde expansion except the initial tilde.
///
/// Returns the literal string up to the next non-applicable word unit.
fn parse_name<I: Iterator<Item = WordUnit>>(i: &mut Peekable<I>) -> String {
fn parse_name<I: Iterator<Item = WordUnit>>(i: &mut Peekable<I>, delimit_at_colon: bool) -> String {
let mut name = String::new();

while let Some(Unquoted(Literal(c))) =
i.next_if(|unit| matches!(unit, Unquoted(Literal(c)) if !matches!(*c, '/' | ':')))
{
while let Some(Unquoted(Literal(c))) = i.next_if(
|unit| matches!(unit, &Unquoted(Literal(c)) if c != '/' && (!delimit_at_colon || c != ':')),
) {
name.push(c)
}

Expand All @@ -47,7 +47,7 @@ impl Word {
loop {
is_after_colon = match i.next() {
Some(Unquoted(Literal('~'))) if is_after_colon => {
let name = parse_name(&mut i);
let name = parse_name(&mut i, everywhere);

// Check the delimiter and push the result.
match i.peek() {
Expand Down Expand Up @@ -119,13 +119,13 @@ impl Word {
/// `~$()` to be regarded as a tilde expansion, but this function does not
/// convert it to `WordUnit::Tilde("$()".to_string())`.
///
/// The tilde expansion are delimited by an unquoted slash or colon. This is
/// also not strictly POSIX-conforming since POSIX allows colons to be
/// included in the tilde expansion.
///
/// This function only parses a tilde expansion at the beginning of the word.
/// If the word is a colon-separated list of paths, you might want to use
/// [`parse_tilde_everywhere`](Self::parse_tilde_everywhere) instead.
///
/// The tilde expansion is delimited by an unquoted slash. Unlike
/// `parse_tilde_everywhere`, unquoted colons are not considered as
/// delimiters.
#[inline]
pub fn parse_tilde_front(&mut self) {
self.parse_tilde(false)
Expand Down Expand Up @@ -229,18 +229,11 @@ mod tests {
}

#[test]
fn word_parse_tilde_front_ending_with_colon() {
let input = Word::from_str("~bar:\"\"").unwrap();
fn word_parse_tilde_front_including_colon() {
let input = Word::from_str("~bar:baz").unwrap();
let result = parse_tilde_front(&input);
assert_eq!(result.location, input.location);
assert_eq!(
result.units,
[
Tilde("bar".to_string()),
Unquoted(Literal(':')),
DoubleQuote(Text(vec![])),
]
);
assert_eq!(result.units, [Tilde("bar:baz".to_string())]);
}

#[test]
Expand Down
9 changes: 1 addition & 8 deletions yash-syntax/src/parser/lex/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,7 @@ mod tests {
let mut lexer = Lexer::from_memory("~a:~", Source::Unknown);

let t = lexer.token().now_or_never().unwrap().unwrap();
assert_eq!(
t.word.units,
[
WordUnit::Tilde("a".to_string()),
WordUnit::Unquoted(TextUnit::Literal(':')),
WordUnit::Unquoted(TextUnit::Literal('~'))
]
);
assert_eq!(t.word.units, [WordUnit::Tilde("a:~".to_string())]);
}

#[test]
Expand Down

0 comments on commit fbb1ac1

Please sign in to comment.