diff --git a/lib/mu-query-parser.cc b/lib/mu-query-parser.cc index 50a07f48..87242ddc 100644 --- a/lib/mu-query-parser.cc +++ b/lib/mu-query-parser.cc @@ -178,7 +178,7 @@ unit(Sexp& tokens, ParseContext& ctx) /* special case: interpret "not" as a matcher instead; */ if (sub.empty()) - return Sexp{placeholder_sym, not_sym.name}; + return matcher(prepend(tokens, Sexp{placeholder_sym, not_sym.name}), ctx); /* we try to optimize: double negations are removed */ if (sub.head_symbolp(not_sym)) @@ -214,6 +214,8 @@ factor(Sexp& tokens, ParseContext& ctx) auto implicit_and = [&]() { if (tokens.head_symbolp(open_sym)) return true; + else if (tokens.head_symbolp(not_sym)) // turn a lone 'not' -> 'and not' + return true; else if (auto&& head{tokens.head()}; head) return looks_like_matcher(*head); else @@ -222,7 +224,6 @@ factor(Sexp& tokens, ParseContext& ctx) Sexp uns; while (true) { - if (tokens.head_symbolp(and_sym)) tokens.pop_front(); else if (!implicit_and()) @@ -362,7 +363,8 @@ test_parser_basic() TestCase{R"(a and (b or c))", R"((and (_ "a") (or (_ "b") (_ "c"))))"}, // not a and not b TestCase{R"(not a and b)", R"((and (not (_ "a")) (_ "b")))"}, - // TODO: add more... + // a not b + TestCase{R"(a not b)", R"((and (_ "a") (not (_ "b"))))"}, }; for (auto&& test: cases) { diff --git a/lib/mu-query-xapianizer.cc b/lib/mu-query-xapianizer.cc index e9cdf52b..efc0c2fd 100644 --- a/lib/mu-query-xapianizer.cc +++ b/lib/mu-query-xapianizer.cc @@ -452,6 +452,13 @@ test_xapian() R"(Query((Shello world OR (Shello PHRASE 2 Sworld))))"}, TestCase{R"(subject:/boo/")", R"(Query())"}, + // logic + TestCase{R"(not)", R"(Query((Tnot OR Cnot OR Hnot OR Fnot OR Snot OR Bnot OR Enot)))"}, + TestCase{R"(from:a and (from:b or from:c))", R"(Query((Fa AND (Fb OR Fc))))"}, + // optimize? + TestCase{R"(not from:a and to:b)", R"(Query((( AND_NOT Fa) AND Tb)))"}, + TestCase{R"(cc:a not bcc:b)", R"(Query((Ca AND ( AND_NOT Hb))))"}, + // ranges. TestCase{R"(size:1..10")", R"(Query(VALUE_RANGE 17 g1 ga))"}, TestCase{R"(size:10..1")", R"(Query(VALUE_RANGE 17 g1 ga))"},