Skip to content

Commit 6058e43

Browse files
committed
strictre
1 parent 5813abb commit 6058e43

File tree

2 files changed

+63
-16
lines changed

2 files changed

+63
-16
lines changed

src/parser.rs

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,14 @@ fn parse_word_parts(
766766
)
767767
}
768768

769+
fn append_char(result: &mut Vec<WordPart>, c: char) {
770+
if let Some(WordPart::Text(text)) = result.last_mut() {
771+
text.push(c);
772+
} else {
773+
result.push(WordPart::Text(c.to_string()));
774+
}
775+
}
776+
769777
move |input| {
770778
enum PendingPart<'a> {
771779
Char(char),
@@ -775,6 +783,7 @@ fn parse_word_parts(
775783
Parts(Vec<WordPart>),
776784
}
777785

786+
let original_input = input;
778787
let (input, parts) = many0(or7(
779788
or3(
780789
map(tag("$?"), |_| PendingPart::Variable("?")),
@@ -819,23 +828,32 @@ fn parse_word_parts(
819828
))(input)?;
820829

821830
let mut result = Vec::new();
822-
for part in parts {
831+
let mut parts = parts.into_iter().enumerate().peekable();
832+
while let Some((i, part)) = parts.next() {
823833
match part {
824834
PendingPart::Char(c) => {
825-
if let Some(WordPart::Text(text)) = result.last_mut() {
826-
text.push(c);
835+
append_char(&mut result, c);
836+
}
837+
PendingPart::Tilde => {
838+
if i == 0 {
839+
if matches!(parts.peek(), None | Some((_, PendingPart::Char('/'))))
840+
{
841+
result.push(WordPart::Tilde);
842+
} else {
843+
return ParseError::fail(
844+
original_input,
845+
"Unsupported tilde expansion.",
846+
);
847+
}
827848
} else {
828-
result.push(WordPart::Text(c.to_string()));
849+
append_char(&mut result, '~');
829850
}
830851
}
831-
PendingPart::Tilde => result.push(WordPart::Tilde),
832852
PendingPart::Command(s) => result.push(WordPart::Command(s)),
833853
PendingPart::Variable(v) => {
834-
result.push(WordPart::Variable(v.to_string()))
835-
}
836-
PendingPart::Parts(parts) => {
837-
result.extend(parts);
854+
result.push(WordPart::Variable(v.to_string()));
838855
}
856+
PendingPart::Parts(parts) => result.extend(parts),
839857
}
840858
}
841859

@@ -1435,6 +1453,25 @@ mod test {
14351453
);
14361454
}
14371455

1456+
#[test]
1457+
fn tilde_expansion() {
1458+
run_test(
1459+
parse_word_parts(ParseWordPartsMode::Unquoted),
1460+
r#"~test"#,
1461+
Err("Unsupported tilde expansion."),
1462+
);
1463+
run_test(
1464+
parse_word_parts(ParseWordPartsMode::Unquoted),
1465+
r#"~+/test"#,
1466+
Err("Unsupported tilde expansion."),
1467+
);
1468+
run_test(
1469+
parse_word_parts(ParseWordPartsMode::Unquoted),
1470+
r#"~/test"#,
1471+
Ok(vec![WordPart::Tilde, WordPart::Text("/test".to_string())]),
1472+
);
1473+
}
1474+
14381475
#[test]
14391476
fn test_parse_word() {
14401477
run_test(parse_unquoted_word, "if", Err("Unsupported reserved word."));

tests/integration_test.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,14 +1431,24 @@ async fn paren_escapes() {
14311431

14321432
#[tokio::test]
14331433
async fn tilde_expansion() {
1434+
let text = concat!(
1435+
r"export HOME=/home/dir && echo ~/test && echo ~ && ",
1436+
r"echo \~ && export HOME=/test && echo ~ && ",
1437+
r"HOME=/nope echo ~ && ",
1438+
r"HOME=/nope $(echo echo ~) && ",
1439+
r"echo ~/sub/~/sub"
1440+
);
1441+
let text = if cfg!(windows) {
1442+
// windows uses a different env var
1443+
text.replace("HOME", "USERPROFILE")
1444+
} else {
1445+
text.to_string()
1446+
};
14341447
TestBuilder::new()
1435-
.command(concat!(
1436-
r"export HOME=/home/dir && echo ~/test && echo ~ && ",
1437-
r"echo \~ && export HOME=/test && echo ~ && ",
1438-
r"HOME=/nope echo ~ && ",
1439-
r"HOME=/nope $(echo echo ~)"
1440-
))
1441-
.assert_stdout("/home/dir/test\n/home/dir\n~\n/test\n/test\n/test\n")
1448+
.command(&text)
1449+
.assert_stdout(
1450+
"/home/dir/test\n/home/dir\n~\n/test\n/test\n/test\n/test/sub/~/sub\n",
1451+
)
14421452
.run()
14431453
.await;
14441454
}

0 commit comments

Comments
 (0)