Unlike in Xapian, there's no specific syntax that generates value ranges. Instead, it's up query transforms to generate them. --- lib/notmuch-private.h | 8 ++++++++ lib/qparser.cc | 20 +++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 5fc54de..9c16f56 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -548,6 +548,8 @@ enum _notmuch_token_type { * with no phrase splitting or whitespace removal. The lexer * only generates TOK_TERMS; the parser creates TOK_LIT. */ TOK_LIT, + /* A value range operand. */ + TOK_RANGE, /* An error token. An error token anywhere in the parse tree will * be propagated up by the generator and returned to the caller. * The error message should be in the text. */ @@ -577,6 +579,12 @@ typedef struct _notmuch_token { * match any terms prefixed with text. */ notmuch_bool_t wildcard; + /* For TOK_RANGE, the value number to filter on, and the + * (inclusive) range to match lexicographically. Either endpoint + * may be NULL, indicating an open-ended range. */ + unsigned valueno; + const char *rangeBegin, *rangeEnd; + /* Link in the lexer token list. */ struct _notmuch_token *next; diff --git a/lib/qparser.cc b/lib/qparser.cc index 0ff240c..2c63062 100644 --- a/lib/qparser.cc +++ b/lib/qparser.cc @@ -43,7 +43,6 @@ * Still missing from this implementation: * * Stemming - The stemming should probably be marked on TOK_TERMS * tokens. Ideally, we can just pass this to the term generator. - * * Value ranges in the IR */ /* XXX notmuch currently registers "tag" as an exclusive boolean @@ -100,13 +99,13 @@ static const char *token_types[] = { "LOVE", "HATE", "BRA", "KET", "AND", "OR", "XOR", "ADJ", "NEAR", "NOT", "FILTER", "PREFIX", - "TERMS", "LIT", "ERROR", "END" + "TERMS", "LIT", "ERROR", "RANGE", "END" }; /* The distinguished end token. This simplifies the parser since it * never has to worry about dereferencing next. */ static _notmuch_token_t tok_end = {TOK_END, NULL, -1, FALSE, NULL, FALSE, - &tok_end, NULL, NULL}; + 0, NULL, NULL, &tok_end, NULL, NULL}; _notmuch_token_t * _notmuch_token_create_op (const void *ctx, enum _notmuch_token_type type, @@ -145,6 +144,9 @@ _notmuch_token_show (const void *ctx, _notmuch_token_t *tok) else if (tok->type == TOK_LIT) return talloc_asprintf (ctx, "'%s'%s", tok->text, tok->wildcard ? "*" : ""); + else if (tok->type == TOK_RANGE) + return talloc_asprintf (ctx, "RANGE/%d:%s..%s", + tok->valueno, tok->rangeBegin, tok->rangeEnd); else if (tok->type == TOK_ERROR) return talloc_asprintf (ctx, "ERROR/\"%s\"", tok->text); @@ -536,6 +538,7 @@ parse_prob (struct _notmuch_parse_state *s, int prec, _notmuch_token_t **tok) break; case TOK_FILTER: + case TOK_RANGE: case TOK_ERROR: INTERNAL_ERROR ("Unexpected token %s", _notmuch_token_show (s->ctx, *tok)); @@ -902,6 +905,17 @@ generate (struct _notmuch_generate_state *s, _notmuch_token_t *root) return generate_wildcard (s, term); return Query (term); + case TOK_RANGE: + if (root->rangeBegin && root->rangeEnd) + return Query (Query::OP_VALUE_RANGE, root->valueno, + root->rangeBegin, root->rangeEnd); + else if (root->rangeBegin) + return Query (Query::OP_VALUE_GE, root->valueno, root->rangeBegin); + else if (root->rangeEnd) + return Query (Query::OP_VALUE_LE, root->valueno, root->rangeEnd); + else + INTERNAL_ERROR ("TOK_RANGE must have an endpoint"); + case TOK_ERROR: if (!s->error) s->error = talloc_strdup (s->ctx, root->text); -- 1.7.2.3