diff --git a/src/lua_engine.rs b/src/lua_engine.rs index 4820dc6..7b94e7b 100644 --- a/src/lua_engine.rs +++ b/src/lua_engine.rs @@ -64,7 +64,7 @@ impl LuaState { pub fn execute_command( &mut self, command: &str, - arguments: &ParsedCommand<'_>, + arguments: &ParsedCommand, ) -> Result<(), String> { self.interp .try_enter(|ctx| { diff --git a/src/parsing.rs b/src/parsing.rs index 12f8e73..a50b229 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -10,8 +10,8 @@ use nom::{ }; #[derive(PartialEq, Eq, Debug)] -pub struct ParseResult<'l> { - pub commands: Vec>, +pub struct ParseResult { + pub commands: Vec, } #[derive(PartialEq, Eq, Debug, Clone)] @@ -21,12 +21,13 @@ pub enum ArgumentGuard { } #[derive(PartialEq, Eq, Debug, Clone)] -pub struct ParsedArgument<'l> { +pub struct ParsedArgument { pub guard: Option, - pub text: &'l str, + pub text: String, + pub quoted_text: String, } -impl<'l> ParsedArgument<'l> { +impl ParsedArgument { pub fn forget_guard(&self) -> Self { Self { guard: None, @@ -35,7 +36,7 @@ impl<'l> ParsedArgument<'l> { } } -impl<'a> Display for ParsedArgument<'a> { +impl Display for ParsedArgument { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.guard { None => {} @@ -46,7 +47,7 @@ impl<'a> Display for ParsedArgument<'a> { f.write_str("\"")?; } } - f.write_str(self.text)?; + f.write_str(&self.quoted_text)?; match self.guard { None => {} Some(ArgumentGuard::Paren) => { @@ -61,11 +62,11 @@ impl<'a> Display for ParsedArgument<'a> { } #[derive(PartialEq, Eq, Debug, Clone)] -pub struct ParsedCommand<'l> { - pub arguments: VecDeque>, +pub struct ParsedCommand { + pub arguments: VecDeque, } -impl<'l> ParsedCommand<'l> { +impl ParsedCommand { pub fn forget_guards(&self) -> Self { Self { arguments: self.arguments.iter().map(|v| v.forget_guard()).collect(), @@ -74,7 +75,7 @@ impl<'l> ParsedCommand<'l> { } } -impl<'a> Display for ParsedCommand<'a> { +impl Display for ParsedCommand { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut it = self.arguments.iter(); match it.next() { @@ -92,8 +93,8 @@ impl<'a> Display for ParsedCommand<'a> { } } -impl ParsedCommand<'_> { - pub fn split_out_command(&self) -> Option<(&str, Self)> { +impl ParsedCommand { + pub fn split_out_command(&self) -> Option<(String, Self)> { let mut tmp_arguments = self.arguments.clone(); loop { match tmp_arguments.pop_front() { @@ -102,7 +103,7 @@ impl ParsedCommand<'_> { let trimmed_cmd = head.text.trim(); if !trimmed_cmd.is_empty() { return Some(( - trimmed_cmd, + trimmed_cmd.to_owned(), Self { arguments: tmp_arguments, }, @@ -114,6 +115,31 @@ impl ParsedCommand<'_> { } } +fn unquote_string(input: &str) -> String { + let mut buf: String = String::new(); + let mut iter = input.chars(); + loop { + match iter.next() { + None => return buf, + Some('\\') => match iter.next() { + None => { + buf.push('\\'); + return buf; + } + Some('\\') => buf.push('\\'), + Some('{') => buf.push('{'), + Some('}') => buf.push('}'), + Some('"') => buf.push('"'), + Some(c) => { + buf.push('\\'); + buf.push(c); + } + }, + Some(c) => buf.push(c), + } + } +} + fn parse_string(input: &str) -> IResult<&str, ()> { value( (), @@ -155,14 +181,16 @@ fn parse_argument(input: &str) -> IResult<&str, ParsedArgument> { map( delimited(char('{'), recognize(parse_parenthetical), char('}')), |v| ParsedArgument { - text: v, + text: unquote_string(v), + quoted_text: v.to_owned(), guard: Some(ArgumentGuard::Paren), }, ), map( delimited(char('"'), recognize(parse_string), char('"')), |v| ParsedArgument { - text: v, + text: unquote_string(v), + quoted_text: v.to_owned(), guard: Some(ArgumentGuard::DoubleQuote), }, ), @@ -191,7 +219,8 @@ fn parse_argument(input: &str) -> IResult<&str, ParsedArgument> { ))), )), |v| ParsedArgument { - text: v, + text: unquote_string(v), + quoted_text: v.to_owned(), guard: None, }, ), @@ -223,7 +252,8 @@ mod tests { ParseResult { commands: vec![ParsedCommand { arguments: vec![ParsedArgument { - text: "", + text: "".to_owned(), + quoted_text: "".to_owned(), guard: None }] .into() @@ -235,7 +265,8 @@ mod tests { ParseResult { commands: vec![ParsedCommand { arguments: vec![ParsedArgument { - text: "north", + text: "north".to_owned(), + quoted_text: "north".to_owned(), guard: None }] .into() @@ -249,11 +280,13 @@ mod tests { // This is deliberate, ensures we can reconstruct the input. arguments: vec![ ParsedArgument { - text: "north", + text: "north".to_owned(), + quoted_text: "north".to_owned(), guard: None }, ParsedArgument { - text: "", + text: "".to_owned(), + quoted_text: "".to_owned(), guard: None } ] @@ -268,11 +301,13 @@ mod tests { ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "x = 1 + 2; y = 3", + text: "x = 1 + 2; y = 3".to_owned(), + quoted_text: "x = 1 + 2; y = 3".to_owned(), guard: Some(ArgumentGuard::Paren) } ] @@ -280,7 +315,8 @@ mod tests { }, ParsedCommand { arguments: vec![ParsedArgument { - text: "#home", + text: "#home".to_owned(), + quoted_text: "#home".to_owned(), guard: None }] .into() @@ -294,11 +330,13 @@ mod tests { commands: vec![ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "{x = 1 + 2", + text: "{x = 1 + 2".to_owned(), + quoted_text: "{x = 1 + 2".to_owned(), guard: None } ] @@ -312,15 +350,18 @@ mod tests { commands: vec![ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "x = 1", + text: "x = 1".to_owned(), + quoted_text: "x = 1".to_owned(), guard: Some(ArgumentGuard::Paren) }, ParsedArgument { - text: "y = 1", + text: "y = 1".to_owned(), + quoted_text: "y = 1".to_owned(), guard: Some(ArgumentGuard::Paren) } ] @@ -334,15 +375,18 @@ mod tests { commands: vec![ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "hello", + text: "hello".to_owned(), + quoted_text: "hello".to_owned(), guard: Some(ArgumentGuard::DoubleQuote) }, ParsedArgument { - text: "world", + text: "world".to_owned(), + quoted_text: "world".to_owned(), guard: Some(ArgumentGuard::DoubleQuote) }, ] @@ -356,15 +400,18 @@ mod tests { commands: vec![ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "x = \"}\"", + text: "x = \"}\"".to_owned(), + quoted_text: "x = \"}\"".to_owned(), guard: Some(ArgumentGuard::Paren) }, ParsedArgument { - text: "y = 1", + text: "y = 1".to_owned(), + quoted_text: "y = 1".to_owned(), guard: Some(ArgumentGuard::Paren) } ] @@ -379,15 +426,18 @@ mod tests { ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "x = \"}\"; a = \"{\"; y = {}; z = 1;", + text: "x = \"}\"; a = \"{\"; y = {}; z = 1;".to_owned(), + quoted_text: "x = \"}\"; a = \"{\"; y = {}; z = 1;".to_owned(), guard: Some(ArgumentGuard::Paren) }, ParsedArgument { - text: " q = 5 ", + text: " q = 5 ".to_owned(), + quoted_text: " q = 5 ".to_owned(), guard: Some(ArgumentGuard::Paren) } ] @@ -395,7 +445,8 @@ mod tests { }, ParsedCommand { arguments: vec![ParsedArgument { - text: "", + text: "".to_owned(), + quoted_text: "".to_owned(), guard: None }] .into() @@ -409,15 +460,18 @@ mod tests { commands: vec![ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "\\}\\}\\}", + text: "}}}".to_owned(), + quoted_text: "\\}\\}\\}".to_owned(), guard: Some(ArgumentGuard::Paren) }, ParsedArgument { - text: "y = 1", + text: "y = 1".to_owned(), + quoted_text: "y = 1".to_owned(), guard: Some(ArgumentGuard::Paren) } ] @@ -431,11 +485,13 @@ mod tests { commands: vec![ParsedCommand { arguments: vec![ ParsedArgument { - text: "#blah", + text: "#blah".to_owned(), + quoted_text: "#blah".to_owned(), guard: None }, ParsedArgument { - text: "This is a \\\"test\\\"", + text: "This is a \"test\"".to_owned(), + quoted_text: "This is a \\\"test\\\"".to_owned(), guard: Some(ArgumentGuard::DoubleQuote) } ] @@ -452,5 +508,11 @@ mod tests { parse_command(input).map(|c| c.1.to_string()), Ok(input.to_owned()) ); + + let input = "{{{\"Foo \\ Bar\"}}}"; + assert_eq!( + parse_command(input).map(|c| c.1.to_string()), + Ok(input.to_owned()) + ); } }