diff --git a/src/core/search/CMakeLists.txt b/src/core/search/CMakeLists.txt index cced83d0b..c942790f1 100644 --- a/src/core/search/CMakeLists.txt +++ b/src/core/search/CMakeLists.txt @@ -1,5 +1,3 @@ -# apt install libfl-dev - gen_flex(lexer) gen_bison(parser) @@ -7,4 +5,4 @@ cur_gen_dir(gen_dir) add_library(query_parser query_driver.cc ${gen_dir}/parser.cc ${gen_dir}/lexer.cc) target_link_libraries(query_parser base absl::strings TRDP::reflex) -cxx_test(search_parser_test query_parser) +cxx_test(search_parser_test query_parser LABELS DFLY) diff --git a/src/core/search/lexer.lex b/src/core/search/lexer.lex index 890e600a9..bbffa0b2e 100644 --- a/src/core/search/lexer.lex +++ b/src/core/search/lexer.lex @@ -53,9 +53,11 @@ term_char [_]|\w "(" return Parser::make_LPAREN (loc()); ")" return Parser::make_RPAREN (loc()); "*" return Parser::make_STAR (loc()); -"~" return Parser::make_NOT_OP (loc()); +"-" return Parser::make_NOT_OP (loc()); ":" return Parser::make_COLON (loc()); "=>" return Parser::make_ARROW (loc()); +"[" return Parser::make_LBRACKET (loc()); +"]" return Parser::make_RBRACKET (loc()); -?[0-9]+ return make_INT64(matched_view(), loc()); diff --git a/src/core/search/parser.y b/src/core/search/parser.y index f7d346f01..91dd2858a 100644 --- a/src/core/search/parser.y +++ b/src/core/search/parser.y @@ -46,14 +46,18 @@ using namespace std; STAR "*" ARROW "=>" COLON ":" - NOT_OP "~" + LBRACKET "[" + RBRACKET "]" ; -%token YYEOF +%precedence NOT_OP + +// Needed 0 at the end to satisfy bison 3.5.1 +%token YYEOF 0 %token TERM "term" PARAM "param" FIELD "field" %token INT64 "int64" -%nterm search_expr +%nterm search_expr field_filter field_cond range_value term_list opt_neg_term %printer { yyo << $$; } <*>; @@ -64,9 +68,25 @@ query: | query search_expr ; -search_expr: TERM { - cout << $1 << endl; -} + +search_expr: + LPAREN search_expr RPAREN { $$ = $2; } + | NOT_OP search_expr { $$ = AstExpr{}; }; + | TERM { } + | field_filter; + +field_filter: + FIELD COLON field_cond { $$ = AstExpr{}; } + +field_cond: term_list | range_value + range_value: LBRACKET INT64 INT64 RBRACKET { $$ = AstExpr{}; } + +term_list: + opt_neg_term | + LPAREN term_list opt_neg_term RPAREN { }; + +opt_neg_term: + TERM { } | NOT_OP TERM { $$ = AstExpr{}; }; %% diff --git a/src/core/search/search_parser_test.cc b/src/core/search/search_parser_test.cc index 04b222167..40fb9e6ec 100644 --- a/src/core/search/search_parser_test.cc +++ b/src/core/search/search_parser_test.cc @@ -47,6 +47,16 @@ class SearchParserTest : public ::testing::Test { auto tok = Lex(); \ ASSERT_EQ(tok.type_get(), Parser::token::tok_enum); \ } +#define NEXT_ERROR() \ + { \ + bool caught = false; \ + try { \ + auto tok = Lex(); \ + } catch (const Parser::syntax_error& e) { \ + caught = true; \ + } \ + ASSERT_TRUE(caught); \ + } TEST_F(SearchParserTest, Scanner) { SetInput("ab cd"); @@ -76,10 +86,18 @@ TEST_F(SearchParserTest, Scanner) { SetInput("почтальон Печкин"); NEXT_EQ(TOK_TERM, string, "почтальон"); NEXT_EQ(TOK_TERM, string, "Печкин"); + + SetInput("18446744073709551616"); + NEXT_ERROR(); } TEST_F(SearchParserTest, Parse) { - EXPECT_EQ(0, Parse(" foo ")); + EXPECT_EQ(0, Parse(" foo bar (baz) ")); + EXPECT_EQ(0, Parse(" -(foo) @foo:bar @ss:[1 2]")); + EXPECT_EQ(1, Parse(" -(foo ")); + EXPECT_EQ(1, Parse(" foo:bar ")); + EXPECT_EQ(1, Parse(" @foo:@bar ")); + EXPECT_EQ(1, Parse(" @foo: ")); } } // namespace search