]> git.notmuchmail.org Git - notmuch/blob - lib/parse-sexp.cc
lib/parse-sexp: support and, not, and or.
[notmuch] / lib / parse-sexp.cc
1 #include "database-private.h"
2
3 #if HAVE_SFSEXP
4 #include "sexp.h"
5
6
7 /* _sexp is used for file scope symbols to avoid clashing with
8  * definitions from sexp.h */
9
10 typedef enum {
11     SEXP_FLAG_NONE = 0,
12 } _sexp_flag_t;
13
14 typedef struct  {
15     const char *name;
16     Xapian::Query::op xapian_op;
17     Xapian::Query initial;
18     _sexp_flag_t flags;
19 } _sexp_prefix_t;
20
21 static _sexp_prefix_t prefixes[] =
22 {
23     { "and",            Xapian::Query::OP_AND,          Xapian::Query::MatchAll,
24       SEXP_FLAG_NONE },
25     { "not",            Xapian::Query::OP_AND_NOT,      Xapian::Query::MatchAll,
26       SEXP_FLAG_NONE },
27     { "or",             Xapian::Query::OP_OR,           Xapian::Query::MatchNothing,
28       SEXP_FLAG_NONE },
29     { }
30 };
31
32 static notmuch_status_t _sexp_to_xapian_query (notmuch_database_t *notmuch,
33                                                const _sexp_prefix_t *parent,
34                                                const sexp_t *sx,
35                                                Xapian::Query &output);
36
37 static notmuch_status_t
38 _sexp_combine_query (notmuch_database_t *notmuch,
39                      const _sexp_prefix_t *parent,
40                      Xapian::Query::op operation,
41                      Xapian::Query left,
42                      const sexp_t *sx,
43                      Xapian::Query &output)
44 {
45     Xapian::Query subquery;
46
47     notmuch_status_t status;
48
49     /* if we run out elements, return accumulator */
50
51     if (! sx) {
52         output = left;
53         return NOTMUCH_STATUS_SUCCESS;
54     }
55
56     status = _sexp_to_xapian_query (notmuch, parent, sx, subquery);
57     if (status)
58         return status;
59
60     return _sexp_combine_query (notmuch,
61                                 parent,
62                                 operation,
63                                 Xapian::Query (operation, left, subquery),
64                                 sx->next, output);
65 }
66
67 /* Here we expect the s-expression to be a proper list, with first
68  * element defining and operation, or as a special case the empty
69  * list */
70
71 static notmuch_status_t
72 _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent, const sexp_t *sx,
73                        Xapian::Query &output)
74 {
75
76     if (sx->ty == SEXP_VALUE) {
77         std::string term = Xapian::Unicode::tolower (sx->val);
78         Xapian::Stem stem = *(notmuch->stemmer);
79         if (sx->aty == SEXP_BASIC)
80             term = "Z" + stem (term);
81
82         output = Xapian::Query (term);
83         return NOTMUCH_STATUS_SUCCESS;
84     }
85
86     /* Empty list */
87     if (! sx->list) {
88         output = Xapian::Query::MatchAll;
89         return NOTMUCH_STATUS_SUCCESS;
90     }
91
92     if (sx->list->ty == SEXP_LIST) {
93         _notmuch_database_log (notmuch, "unexpected list in field/operation position\n",
94                                sx->list->val);
95         return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
96     }
97
98     for (_sexp_prefix_t *prefix = prefixes; prefix && prefix->name; prefix++) {
99         if (strcmp (prefix->name, sx->list->val) == 0) {
100             return _sexp_combine_query (notmuch, parent, prefix->xapian_op, prefix->initial,
101                                         sx->list->next, output);
102         }
103     }
104
105     _notmuch_database_log (notmuch, "unknown prefix '%s'\n", sx->list->val);
106
107     return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
108 }
109
110 notmuch_status_t
111 _notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr,
112                                       Xapian::Query &output)
113 {
114     const sexp_t *sx = NULL;
115     char *buf = talloc_strdup (notmuch, querystr);
116
117     sx = parse_sexp (buf, strlen (querystr));
118     if (! sx) {
119         _notmuch_database_log (notmuch, "invalid s-expression: '%s'\n", querystr);
120         return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
121     }
122
123     return _sexp_to_xapian_query (notmuch, NULL, sx, output);
124 }
125 #endif