summaryrefslogtreecommitdiffstats
path: root/src/query/query_parser/query_grammar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/query/query_parser/query_grammar.rs')
-rw-r--r--src/query/query_parser/query_grammar.rs284
1 files changed, 0 insertions, 284 deletions
diff --git a/src/query/query_parser/query_grammar.rs b/src/query/query_parser/query_grammar.rs
deleted file mode 100644
index a3df714..0000000
--- a/src/query/query_parser/query_grammar.rs
+++ /dev/null
@@ -1,284 +0,0 @@
-use super::query_grammar;
-use super::user_input_ast::*;
-use crate::query::occur::Occur;
-use crate::query::query_parser::user_input_ast::UserInputBound;
-use combine::char::*;
-use combine::error::StreamError;
-use combine::stream::StreamErrorFor;
-use combine::*;
-
-parser! {
- fn field[I]()(I) -> String
- where [I: Stream<Item = char>] {
- (
- letter(),
- many(satisfy(|c: char| c.is_alphanumeric() || c == '_')),
- ).map(|(s1, s2): (char, String)| format!("{}{}", s1, s2))
- }
-}
-
-parser! {
- fn word[I]()(I) -> String
- where [I: Stream<Item = char>] {
- many1(satisfy(|c: char| c.is_alphanumeric() || c=='.'))
- .and_then(|s: String| {
- match s.as_str() {
- "OR" => Err(StreamErrorFor::<I>::unexpected_static_message("OR")),
- "AND" => Err(StreamErrorFor::<I>::unexpected_static_message("AND")),
- "NOT" => Err(StreamErrorFor::<I>::unexpected_static_message("NOT")),
- _ => Ok(s)
- }
- })
- }
-}
-
-parser! {
- fn literal[I]()(I) -> UserInputLeaf
- where [I: Stream<Item = char>]
- {
- let term_val = || {
- let phrase = (char('"'), many1(satisfy(|c| c != '"')), char('"')).map(|(_, s, _)| s);
- phrase.or(word())
- };
- let term_val_with_field = negative_number().or(term_val());
- let term_query =
- (field(), char(':'), term_val_with_field).map(|(field_name, _, phrase)| UserInputLiteral {
- field_name: Some(field_name),
- phrase,
- });
- let term_default_field = term_val().map(|phrase| UserInputLiteral {
- field_name: None,
- phrase,
- });
- attempt(term_query)
- .or(term_default_field)
- .map(UserInputLeaf::from)
- }
-}
-
-parser! {
- fn negative_number[I]()(I) -> String
- where [I: Stream<Item = char>]
- {
- (char('-'), many1(satisfy(char::is_numeric)))
- .map(|(s1, s2): (char, String)| format!("{}{}", s1, s2))
- }
-}
-
-parser! {
- fn spaces1[I]()(I) -> ()
- where [I: Stream<Item = char>] {
- skip_many1(space())
- }
-}
-
-parser! {
- fn range[I]()(I) -> UserInputLeaf
- where [I: Stream<Item = char>] {
- let term_val = || {
- word().or(negative_number()).or(char('*').map(|_| "*".to_string()))
- };
- let lower_bound = {
- let excl = (char('{'), term_val()).map(|(_, w)| UserInputBound::Exclusive(w));
- let incl = (char('['), term_val()).map(|(_, w)| UserInputBound::Inclusive(w));
- attempt(excl).or(incl)
- };
- let upper_bound = {
- let excl = (term_val(), char('}')).map(|(w, _)| UserInputBound::Exclusive(w));
- let incl = (term_val(), char(']')).map(|(w, _)| UserInputBound::Inclusive(w));
- attempt(excl).or(incl)
- };
- (
- optional((field(), char(':')).map(|x| x.0)),
- lower_bound,
- spaces(),
- string("TO"),
- spaces(),
- upper_bound,
- ).map(|(field, lower, _, _, _, upper)| UserInputLeaf::Range {
- field,
- lower,
- upper
- })
- }
-}
-
-parser! {
- fn leaf[I]()(I) -> UserInputAST
- where [I: Stream<Item = char>] {
- (char('-'), leaf()).map(|(_, expr)| expr.unary(Occur::MustNot) )
- .or((char('+'), leaf()).map(|(_, expr)| expr.unary(Occur::Must) ))
- .or((char('('), parse_to_ast(), char(')')).map(|(_, expr, _)| expr))
- .or(char('*').map(|_| UserInputAST::from(UserInputLeaf::All) ))
- .or(attempt(
- (string("NOT"), spaces1(), leaf()).map(|(_, _, expr)| expr.unary(Occur::MustNot))
- )
- )
- .or(attempt(
- range().map(UserInputAST::from)
- )
- )
- .or(literal().map(|leaf| UserInputAST::Leaf(Box::new(leaf))))
- }
-}
-
-enum BinaryOperand {
- Or,
- And,
-}
-
-parser! {
- fn binary_operand[I]()(I) -> BinaryOperand
- where [I: Stream<Item = char>] {
- (spaces1(),
- (
- string("AND").map(|_| BinaryOperand::And)
- .or(string("OR").map(|_| BinaryOperand::Or))
- ),
- spaces1()).map(|(_, op,_)| op)
- }
-}
-
-enum Element {
- SingleEl(UserInputAST),
- NormalDisjunctive(Vec<Vec<UserInputAST>>),
-}
-
-impl Element {
- pub fn into_dnf(self) -> Vec<Vec<UserInputAST>> {
- match self {
- Element::NormalDisjunctive(conjunctions) => conjunctions,
- Element::SingleEl(el) => vec![vec![el]],
- }
- }
-}
-
-parser! {
- pub fn parse_to_ast[I]()(I) -> UserInputAST
- where [I: Stream<Item = char>]
- {
- (
- attempt(
- chainl1(
- leaf().map(Element::SingleEl),
- binary_operand().map(|op: BinaryOperand|
- move |left: Element, right: Element| {
- let mut dnf = left.into_dnf();
- if let Element::SingleEl(el) = right {
- match op {
- BinaryOperand::And => {
- if let Some(last) = dnf.last_mut() {
- last.push(el);
- }
- }
- BinaryOperand::Or => {
- dnf.push(vec!(el));
- }
- }
- } else {
- unreachable!("Please report.")
- }
- Element::NormalDisjunctive(dnf)
- }
- )
- )
- .map(query_grammar::Element::into_dnf)
- .map(|fnd| {
- if fnd.len() == 1 {
- UserInputAST::and(fnd.into_iter().next().unwrap()) //< safe
- } else {
- let conjunctions = fnd
- .into_iter()
- .map(UserInputAST::and)
- .collect();
- UserInputAST::or(conjunctions)
- }
- })
- )
- .or(
- sep_by(leaf(), spaces())
- .map(|subqueries: Vec<UserInputAST>| {
- if subqueries.len() == 1 {
- subqueries.into_iter().next().unwrap()
- } else {
- UserInputAST::Clause(subqueries.into_iter().collect())
- }
- })
- )
- )
-
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use super::*;
-
- fn test_parse_query_to_ast_helper(query: &str, expected: &str) {
- let query = parse_to_ast().parse(query).unwrap().0;
- let query_str = format!("{:?}", query);
- assert_eq!(query_str, expected);
- }
-
- fn test_is_parse_err(query: &str) {
- assert!(parse_to_ast().parse(query).is_err());
- }
-
- #[test]
- fn test_parse_query_to_ast_not_op() {
- assert_eq!(
- format!("{:?}", parse_to_ast().parse("NOT")),
- "Err(UnexpectedParse)"
- );
- test_parse_query_to_ast_helper("NOTa", "\"NOTa\"");
- test_parse_query_to_ast_helper("NOT a", "-(\"a\")");
- }
-
- #[test]
- fn test_parse_query_to_ast_binary_op() {
- test_parse_query_to_ast_helper("a AND b", "(+(\"a\") +(\"b\"))");
- test_parse_query_to_ast_helper("a OR b", "(?(\"a\") ?(\"b\"))");
- test_parse_query_to_ast_helper("a OR b AND c", "(?(\"a\") ?((+(\"b\") +(\"c\"))))");
- test_parse_query_to_ast_helper("a AND b AND c", "(+(\"a\") +(\"b\") +(\"c\"))");
- assert_eq!(
- format!("{:?}", parse_to_ast().parse("a OR b aaa")),
- "Err(UnexpectedParse)"
- );
- assert_eq!(
- format!("{:?}", parse_to_ast().parse("a AND b aaa")),
- "Err(UnexpectedParse)"
- );
- assert_eq!(
- format!("{:?}", parse_to_ast().parse("aaa a OR b ")),
- "Err(UnexpectedParse)"
- );
- assert_eq!(
- format!("{:?}", parse_to_ast().parse("aaa ccc a OR b ")),
- "Err(UnexpectedParse)"
- );
- }
-
- #[test]
- fn test_parse_query_to_ast() {
- test_parse_query_to_ast_helper("+(a b) +d", "(+((\"a\" \"b\")) +(\"d\"))");
- test_parse_query_to_ast_helper("(+a +b) d", "((+(\"a\") +(\"b\")) \"d\")");
- test_parse_query_to_ast_helper("(+a)", "+(\"a\")");
- test_parse_query_to_ast_helper("(+a +b)", "(+(\"a\") +(\"b\"))");
- test_parse_query_to_ast_helper("abc:toto", "abc:\"toto\"");
- test_parse_query_to_ast_helper("abc:1.1", "abc:\"1.1\"");
- test_parse_query_to_ast_helper("+abc:toto", "+(abc:\"toto\")");
- test_parse_query_to_ast_helper("(+abc:toto -titi)", "(+(abc:\"toto\") -(\"titi\"))");
- test_parse_query_to_ast_helper("-abc:toto", "-(abc:\"toto\")");
- test_parse_query_to_ast_helper("abc:a b", "(abc:\"a\" \"b\")");
- test_parse_query_to_ast_helper("abc:\"a b\"", "abc:\"a b\"");
- test_parse_query_to_ast_helper("foo:[1 TO 5]", "foo:[\"1\" TO \"5\"]");
- test_parse_query_to_ast_helper("[1 TO 5]", "[\"1\" TO \"5\"]");
- test_parse_query_to_ast_helper("foo:{a TO z}", "foo:{\"a\" TO \"z\"}");
- test_parse_query_to_ast_helper("foo:[1 TO toto}", "foo:[\"1\" TO \"toto\"}");
- test_parse_query_to_ast_helper("foo:[* TO toto}", "foo:[\"*\" TO \"toto\"}");
- test_parse_query_to_ast_helper("foo:[1 TO *}", "foo:[\"1\" TO \"*\"}");
- test_parse_query_to_ast_helper("foo:[1.1 TO *}", "foo:[\"1.1\" TO \"*\"}");
- test_is_parse_err("abc + ");
- }
-}