2021-10-22 01:59:38 +02:00
|
|
|
use nom::branch::alt;
|
|
|
|
use nom::bytes::complete::{take_till, take_while1};
|
|
|
|
use nom::character::complete::char;
|
|
|
|
use nom::sequence::delimited;
|
|
|
|
|
2021-11-02 20:27:07 +01:00
|
|
|
use crate::{ws, Error, IResult, Span, Token};
|
2021-10-22 01:59:38 +02:00
|
|
|
|
|
|
|
/// value = WS* ~ ( word | singleQuoted | doubleQuoted) ~ WS*
|
2021-11-02 20:27:07 +01:00
|
|
|
pub fn parse_value(input: Span) -> IResult<Token> {
|
2021-10-22 01:59:38 +02:00
|
|
|
// singleQuoted = "'" .* all but quotes "'"
|
2021-11-02 20:27:07 +01:00
|
|
|
let simple_quoted = |input| take_till(|c: char| c == '\'')(input);
|
2021-10-22 01:59:38 +02:00
|
|
|
// doubleQuoted = "\"" (word | spaces)* "\""
|
2021-11-02 20:27:07 +01:00
|
|
|
let double_quoted = |input| take_till(|c: char| c == '"')(input);
|
2021-10-22 01:59:38 +02:00
|
|
|
// word = (alphanumeric | _ | - | .)+
|
|
|
|
let word = |input| take_while1(is_key_component)(input);
|
|
|
|
|
2021-11-02 20:27:07 +01:00
|
|
|
ws(alt((
|
|
|
|
delimited(char('\''), simple_quoted, char('\'')),
|
|
|
|
delimited(char('"'), double_quoted, char('"')),
|
|
|
|
word,
|
|
|
|
)))(input)
|
2021-10-22 01:59:38 +02:00
|
|
|
.map(|(s, t)| (s, t.into()))
|
2021-11-02 20:27:07 +01:00
|
|
|
.map_err(|e| e.map(|_| Error::expected_value(input)))
|
2021-10-22 01:59:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_key_component(c: char) -> bool {
|
|
|
|
c.is_alphanumeric() || ['_', '-', '.'].contains(&c)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests {
|
|
|
|
use super::*;
|
|
|
|
use crate::tests::rtok;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn name() {
|
|
|
|
let test_case = [
|
|
|
|
("channel", rtok("", "channel")),
|
|
|
|
(".private", rtok("", ".private")),
|
|
|
|
("I-love-kebab", rtok("", "I-love-kebab")),
|
|
|
|
("but_snakes_are_also_good", rtok("", "but_snakes_are_also_good")),
|
|
|
|
("parens(", rtok("", "parens")),
|
|
|
|
("parens)", rtok("", "parens")),
|
|
|
|
("not!", rtok("", "not")),
|
|
|
|
(" channel", rtok(" ", "channel")),
|
|
|
|
("channel ", rtok("", "channel")),
|
|
|
|
("'channel'", rtok("'", "channel")),
|
|
|
|
("\"channel\"", rtok("\"", "channel")),
|
|
|
|
("'cha)nnel'", rtok("'", "cha)nnel")),
|
|
|
|
("'cha\"nnel'", rtok("'", "cha\"nnel")),
|
|
|
|
("\"cha'nnel\"", rtok("\"", "cha'nnel")),
|
|
|
|
("\" some spaces \"", rtok("\"", " some spaces ")),
|
|
|
|
("\"cha'nnel\"", rtok("'", "cha'nnel")),
|
|
|
|
("\"cha'nnel\"", rtok("'", "cha'nnel")),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (input, expected) in test_case {
|
2021-11-02 17:35:17 +01:00
|
|
|
let input = Span::new_extra(input, input);
|
2021-11-02 20:27:07 +01:00
|
|
|
let result = parse_value(input);
|
2021-10-22 01:59:38 +02:00
|
|
|
|
|
|
|
assert!(
|
|
|
|
result.is_ok(),
|
|
|
|
"Filter `{:?}` was supposed to be parsed but failed with the following error: `{}`",
|
|
|
|
expected,
|
|
|
|
result.unwrap_err()
|
|
|
|
);
|
|
|
|
let value = result.unwrap().1;
|
|
|
|
assert_eq!(value, expected, "Filter `{}` failed.", input);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|