summaryrefslogtreecommitdiffstats
path: root/src/parse.rs
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-07 18:29:10 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-07 18:29:10 -0500
commit0766964a90bef03df35de35d672995a385fc7172 (patch)
tree09d2565ba28a64b5a6c974f3393cec2679e6e1c8 /src/parse.rs
parent94ff8b9091c077ca605df4141d3d1c8d0be10966 (diff)
downloadnbsh-0766964a90bef03df35de35d672995a385fc7172.tar.gz
nbsh-0766964a90bef03df35de35d672995a385fc7172.zip
implement escaping characters
Diffstat (limited to 'src/parse.rs')
-rw-r--r--src/parse.rs109
1 files changed, 103 insertions, 6 deletions
diff --git a/src/parse.rs b/src/parse.rs
index 9d0d230..72de364 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -125,19 +125,35 @@ impl WordOrRedirect {
word.as_rule(),
Rule::bareword | Rule::single_string | Rule::double_string
));
+ let interpolate = matches!(
+ word.as_rule(),
+ Rule::bareword | Rule::double_string
+ );
word_str.push_str(word.as_str());
- Self::Redirect(Redirect::parse(&word_str))
+ if interpolate {
+ word_str = strip_escape(&word_str);
+ } else {
+ word_str = strip_basic_escape(&word_str);
+ }
+ Self::Redirect(Redirect::parse(&strip_escape(&word_str)))
} else {
assert!(matches!(
word.as_rule(),
Rule::bareword | Rule::single_string | Rule::double_string
));
+ let interpolate = matches!(
+ word.as_rule(),
+ Rule::bareword | Rule::double_string
+ );
+ let mut word_str = word.as_str().to_string();
+ if interpolate {
+ word_str = strip_escape(&word_str);
+ } else {
+ word_str = strip_basic_escape(&word_str);
+ }
Self::Word(Word {
- word: word.as_str().to_string(),
- interpolate: matches!(
- word.as_rule(),
- Rule::bareword | Rule::double_string
- ),
+ word: word_str,
+ interpolate,
quoted: matches!(
word.as_rule(),
Rule::single_string | Rule::double_string
@@ -277,6 +293,44 @@ impl Commands {
}
}
+fn strip_escape(s: &str) -> String {
+ let mut new = String::new();
+ let mut escape = false;
+ for c in s.chars() {
+ if escape {
+ new.push(c);
+ escape = false;
+ } else {
+ match c {
+ '\\' => escape = true,
+ _ => new.push(c),
+ }
+ }
+ }
+ new
+}
+
+fn strip_basic_escape(s: &str) -> String {
+ let mut new = String::new();
+ let mut escape = false;
+ for c in s.chars() {
+ if escape {
+ match c {
+ '\\' | '\'' => {}
+ _ => new.push('\\'),
+ }
+ new.push(c);
+ escape = false;
+ } else {
+ match c {
+ '\\' => escape = true,
+ _ => new.push(c),
+ }
+ }
+ }
+ new
+}
+
#[derive(Debug)]
pub struct Error {
input: String,
@@ -557,4 +611,47 @@ mod test {
)
);
}
+
+ #[test]
+ fn test_escape() {
+ parse_eq!(
+ "foo\\ bar",
+ c!("foo\\ bar", p!("foo\\ bar", e!(w!("foo bar"))))
+ );
+ parse_eq!(
+ "'foo\\ bar'",
+ c!(
+ "'foo\\ bar'",
+ p!("'foo\\ bar'", e!(w!("foo\\ bar", false, true)))
+ )
+ );
+ parse_eq!(
+ "\"foo\\ bar\"",
+ c!(
+ "\"foo\\ bar\"",
+ p!("\"foo\\ bar\"", e!(w!("foo bar", true, true)))
+ )
+ );
+ parse_eq!(
+ "\"foo\\\"bar\"",
+ c!(
+ "\"foo\\\"bar\"",
+ p!("\"foo\\\"bar\"", e!(w!("foo\"bar", true, true)))
+ )
+ );
+ parse_eq!(
+ "'foo\\'bar\\\\'",
+ c!(
+ "'foo\\'bar\\\\'",
+ p!("'foo\\'bar\\\\'", e!(w!("foo'bar\\", false, true)))
+ )
+ );
+ parse_eq!(
+ "foo > bar\\ baz",
+ c!(
+ "foo > bar\\ baz",
+ p!("foo > bar\\ baz", e!(w!("foo") ; r!(1, "bar baz", Out)))
+ )
+ );
+ }
}