Unquote strings and braces to simplify command-Lua interop.
This commit is contained in:
parent
ba49876f80
commit
855ecfc13a
@ -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| {
|
||||
|
150
src/parsing.rs
150
src/parsing.rs
@ -10,8 +10,8 @@ use nom::{
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct ParseResult<'l> {
|
||||
pub commands: Vec<ParsedCommand<'l>>,
|
||||
pub struct ParseResult {
|
||||
pub commands: Vec<ParsedCommand>,
|
||||
}
|
||||
|
||||
#[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<ArgumentGuard>,
|
||||
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<ParsedArgument<'l>>,
|
||||
pub struct ParsedCommand {
|
||||
pub arguments: VecDeque<ParsedArgument>,
|
||||
}
|
||||
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user