@@ -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."));
0 commit comments