From 94ff8b9091c077ca605df4141d3d1c8d0be10966 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Fri, 7 Jan 2022 04:39:33 -0500 Subject: fix quoted redirect targets --- src/parse.rs | 79 ++++++++++++++++++++++++++++++++++++++++++------------------ 1 file 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) -> 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) -> 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))) + ) + ); } } -- cgit v1.2.3-54-g00ecf