diff options
author | Jesse Luehrs <doy@tozt.net> | 2022-01-07 04:39:33 -0500 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2022-01-07 04:39:33 -0500 |
commit | 94ff8b9091c077ca605df4141d3d1c8d0be10966 (patch) | |
tree | ec29c3cadb9a07158065a6da8cb20469a32d51b2 /src/parse.rs | |
parent | de5db374da5c53e44c52bf896140efaf4b7ae7ec (diff) | |
download | nbsh-94ff8b9091c077ca605df4141d3d1c8d0be10966.tar.gz nbsh-94ff8b9091c077ca605df4141d3d1c8d0be10966.zip |
fix quoted redirect targets
Diffstat (limited to 'src/parse.rs')
-rw-r--r-- | src/parse.rs | 79 |
1 files changed, 55 insertions, 24 deletions
diff --git a/src/parse.rs b/src/parse.rs index 229f387..9d0d230 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -108,31 +108,41 @@ pub struct Word { quoted: bool, } -impl Word { +enum WordOrRedirect { + Word(Word), + Redirect(Redirect), +} + +impl WordOrRedirect { fn build_ast(pair: pest::iterators::Pair<Rule>) -> Self { assert!(matches!(pair.as_rule(), Rule::word)); let mut inner = pair.into_inner(); let mut word = inner.next().unwrap(); - let mut word_str = String::new(); if matches!(word.as_rule(), Rule::redir_prefix) { - word_str = word.as_str().trim().to_string(); + let mut word_str = word.as_str().trim().to_string(); word = inner.next().unwrap(); - } - assert!(matches!( - word.as_rule(), - Rule::bareword | Rule::single_string | Rule::double_string - )); - word_str.push_str(word.as_str()); - Self { - word: word_str, - interpolate: matches!( + assert!(matches!( word.as_rule(), - Rule::bareword | Rule::double_string - ), - quoted: matches!( + Rule::bareword | Rule::single_string | Rule::double_string + )); + word_str.push_str(word.as_str()); + Self::Redirect(Redirect::parse(&word_str)) + } else { + assert!(matches!( word.as_rule(), - Rule::single_string | Rule::double_string - ), + Rule::bareword | Rule::single_string | Rule::double_string + )); + Self::Word(Word { + word: word.as_str().to_string(), + interpolate: matches!( + word.as_rule(), + Rule::bareword | Rule::double_string + ), + quoted: matches!( + word.as_rule(), + Rule::single_string | Rule::double_string + ), + }) } } } @@ -148,13 +158,27 @@ impl Exe { fn build_ast(pair: pest::iterators::Pair<Rule>) -> Self { assert!(matches!(pair.as_rule(), Rule::exe)); let mut iter = pair.into_inner(); - let exe = Word::build_ast(iter.next().unwrap()); - let (args, redirects): (_, Vec<_>) = - iter.map(Word::build_ast).partition(|word| { - word.quoted || !word.word.contains(&['<', '>'][..]) - }); - let redirects = - redirects.iter().map(|r| Redirect::parse(&r.word)).collect(); + let exe = match WordOrRedirect::build_ast(iter.next().unwrap()) { + WordOrRedirect::Word(word) => word, + WordOrRedirect::Redirect(_) => todo!(), + }; + let (args, redirects): (_, Vec<_>) = iter + .map(WordOrRedirect::build_ast) + .partition(|word| matches!(word, WordOrRedirect::Word(_))); + let args = args + .into_iter() + .map(|word| match word { + WordOrRedirect::Word(word) => word, + WordOrRedirect::Redirect(_) => unreachable!(), + }) + .collect(); + let redirects = redirects + .into_iter() + .map(|word| match word { + WordOrRedirect::Word(_) => unreachable!(), + WordOrRedirect::Redirect(redirect) => redirect, + }) + .collect(); Self { exe, args, @@ -525,5 +549,12 @@ mod test { p!("foo >> bar", e!(w!("foo") ; r!(1, "bar", Append))) ) ); + parse_eq!( + "foo > 'bar baz'", + c!( + "foo > 'bar baz'", + p!("foo > 'bar baz'", e!(w!("foo") ; r!(1, "bar baz", Out))) + ) + ); } } |