aboutsummaryrefslogtreecommitdiffstats
path: root/predicate-search-core/src/main/antlr3/com/yahoo/document/predicate/parser/Predicate.g
blob: b14f526060c8dc760f0bcdd563f2da41d6544213 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
grammar Predicate;

@header {
package com.yahoo.document.predicate.parser;

import com.yahoo.document.predicate.Conjunction;
import com.yahoo.document.predicate.Disjunction;
import com.yahoo.document.predicate.FeatureRange;
import com.yahoo.document.predicate.FeatureSet;
import com.yahoo.document.predicate.Negation;
import com.yahoo.document.predicate.Predicate;
import com.yahoo.document.predicate.Predicates;
}

@lexer::header {
package com.yahoo.document.predicate.parser;

import com.yahoo.document.predicate.Predicate;
}

@members {
    @Override
    public void emitErrorMessage(String message) {
        throw new IllegalArgumentException(message);
    }
}

@lexer::members {
    @Override
    public void emitErrorMessage(String message) {
        throw new IllegalArgumentException(message);
    }
}

predicate returns [Predicate n]
    : d=disjunction EOF { n = d; }
    ;

disjunction returns [Predicate n]
    : c=conjunction { n = c; }
      ( OR c2=conjunction { n = new Disjunction(n, c2); }
        ( OR c3=conjunction { ((Disjunction)n).addOperand(c3); } )* )?
    ;

conjunction returns [Predicate n]
    : u=unary_node { n = u; }
      ( AND u2=unary_node { n = new Conjunction(n, u2); }
        ( AND u3=unary_node { ((Conjunction)n).addOperand(u3); } )* )?
    ;

unary_node returns [Predicate n]
    : l=leaf { n = l; }
    | ( not=NOT )? '(' d=disjunction ')' { n = d; if (not != null) { n = new Negation(n); } }
    ;

leaf returns [Predicate n]
    : k=value ( not=NOT )? IN
        ( mv=multivalue[k] { n = mv; }
        | r=range[k] { n = r; }
        ) { if (not != null) { n = new Negation(n); } }
    | TRUE { n = Predicates.value(true); }
    | FALSE { n = Predicates.value(false); }
    ;

multivalue[String key] returns [FeatureSet n]
    : '[' v1=value { n = new FeatureSet(key, v1); }
          ( ',' v2=value { n.addValue(v2); })* ']'
    ;

value returns [String s]
    : VALUE { s = $VALUE.text; }
    | STRING { s = $STRING.text; }
    | INTEGER { s = $INTEGER.text; }
    | k=keyword { s = k; }
    ;

range[String key] returns [FeatureRange r]
    : '[' { r = new FeatureRange(key); }
          ( i1=INTEGER { r.setFromInclusive(Long.parseLong(i1.getText())); } )?
          '..'
          ( i2=INTEGER { r.setToInclusive(Long.parseLong(i2.getText())); } )?
          ( '(' partition (',' partition)* ')' )?
      ']'
    ;

partition
    : value ('='|'=-') (INTEGER INTEGER /* second integer becomes negative */ | INTEGER '+[' INTEGER? '..' INTEGER? ']')
    ;

keyword returns [String s]
    : OR  { s = $OR.text; }
    | AND { s = $AND.text; }
    | NOT { s = $NOT.text; }
    | IN  { s = $IN.text; }
    | TRUE { s = $TRUE.text; }
    | FALSE { s = $FALSE.text; }
    ;

INTEGER : ( '-' | '+' )? ('1'..'9' ( '0'..'9' )* | '0') ;

OR  : 'OR' | 'or' ;
AND : 'AND' | 'and' ;
NOT : 'NOT' | 'not' ;
IN  : 'IN' | 'in' ;
TRUE : 'TRUE' | 'true' ;
FALSE : 'FALSE' | 'false' ;

VALUE : ( 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' )+ ;

STRING
    : ( '\'' ( ~('\'') | '\\\'' )* '\''
      | '\"' ( ~('\"') | '\\\"' )* '\"' )
      { setText(Predicate.asciiDecode(getText().substring(1, getText().length() - 1))); }
    ;

WS  : (' ' | '\t')+
      {$channel = HIDDEN;}
    ;