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