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