use crate::token::Token;
use crate::lexer::LexerErrorType;
use crate::utils::ParseResult;
pub fn parse_quoted_string<'a>(input: &'a str) -> ParseResult<'a> {
let quote = input.chars().next()
.unwrap_or_else(|| unreachable!("must be called when the next character is a `'` or `\"`"));
let mut escaped = false;
input.char_indices()
.find_map(|(i, character)| {
if i == 0 {
None
} else {
match character {
'\\' => {
escaped = !escaped;
None
},
'\n' => {
if escaped {
escaped = false;
None
} else {
Some(Err(LexerErrorType::UnfinishedString))
}
},
'\r' => None,
_ => {
if !escaped && character == quote {
Some(Ok(i))
} else {
escaped = false;
None
}
}
}
}
})
.unwrap_or(Err(LexerErrorType::UnfinishedString))
.and_then(|i| {
let (result, rest) = input.split_at(i + 1);
Ok((Token::new_string(result), rest))
})
}
#[cfg(test)]
mod tests {
use super::*;
mod ok {
use super::*;
macro_rules! test_string {
($($name:ident : $input:expr),+) => {
$(
#[test]
fn $name() {
let (token, rest) = parse_quoted_string($input).unwrap();
assert_eq!(token, Token::new_string($input));
assert_eq!(rest, "");
}
)+
};
}
test_string!(
double_quoted_word: r#""hello""#,
single_quote_word: "'hello'",
double_quoted_with_single_quote: r#""hel'lo""#,
single_quoted_with_double_quote: r#"'hel"lo'"#,
escaped_double_quotes: r#""hello \"you\"""#,
escaped_single_quotes: r#"'hello \'you\''"#,
escaped_slash_before_double_quote: r#""hello !\\""#,
escaped_slash_before_single_quote: r#"'hello !\\'"#,
double_quoted_more_escaped_characters: r#""hello\t !\"\"""#,
single_quoted_more_escaped_characters: r#"'hello\t !\'\''"#,
multiline_double_quoted: r#""hello \
multilined""#,
multiline_single_quoted: r#"'hello \
multilined'"#,
double_quoted_with_backslash: r#""hey \ you \ ""#,
single_quoted_with_backslash: r#"'hey \ you \ '"#
);
}
mod err {
use super::*;
macro_rules! test_unfinished_string {
($($name:ident : $input:expr),+) => {
$(
#[test]
fn $name() {
let lexer_error = parse_quoted_string($input).unwrap_err();
assert_eq!(lexer_error, LexerErrorType::UnfinishedString);
}
)+
};
}
test_unfinished_string!(
double_quoted_word: r#""hello"#,
single_quote_word: "'hello",
double_quoted_with_single_quote: r#""hel'lo"#,
single_quoted_with_double_quote: r#"'hel"lo"#,
escaped_double_quotes: r#""hello \"you\""#,
escaped_slash_before_double_quotes: r#""hello !\\"#,
double_quoted_more_escaped_characters: r#""hello\t !\"\""#,
multiline_double_quoted: r#""hello \
multilined"#,
double_quoted_with_backslash: r#""hey \ you \ "#
);
}
}