1 %{
2 package query
3 import (
4 "fmt"
5 "strconv"
6 "strings"
7 "time"
8 )
9
logDebugGrammar(format string,v...interface{})10 func logDebugGrammar(format string, v ...interface{}) {
11 if debugParser {
12 logger.Printf(format, v...)
13 }
14 }
15 %}
16
17 %union {
18 s string
19 n int
20 f float64
21 q Query
22 pf *float64}
23
24 %token tSTRING tPHRASE tPLUS tMINUS tCOLON tBOOST tNUMBER tSTRING tGREATER tLESS
25 tEQUAL tTILDE
26
27 %type <s> tSTRING
28 %type <s> tPHRASE
29 %type <s> tNUMBER
30 %type <s> posOrNegNumber
31 %type <s> tTILDE
32 %type <s> tBOOST
33 %type <q> searchBase
34 %type <pf> searchSuffix
35 %type <n> searchPrefix
36
37 %%
38
39 input:
40 searchParts {
41 logDebugGrammar("INPUT")
42 };
43
44 searchParts:
45 searchPart searchParts {
46 logDebugGrammar("SEARCH PARTS")
47 }
48 |
49 searchPart {
50 logDebugGrammar("SEARCH PART")
51 };
52
53 searchPart:
54 searchPrefix searchBase searchSuffix {
55 query := $2
56 if $3 != nil {
57 if query, ok := query.(BoostableQuery); ok {
58 query.SetBoost(*$3)
59 }
60 }
61 switch($1) {
62 case queryShould:
63 yylex.(*lexerWrapper).query.AddShould(query)
64 case queryMust:
65 yylex.(*lexerWrapper).query.AddMust(query)
66 case queryMustNot:
67 yylex.(*lexerWrapper).query.AddMustNot(query)
68 }
69 };
70
71
72 searchPrefix:
73 /* empty */ {
74 $$ = queryShould
75 }
76 |
77 tPLUS {
78 logDebugGrammar("PLUS")
79 $$ = queryMust
80 }
81 |
82 tMINUS {
83 logDebugGrammar("MINUS")
84 $$ = queryMustNot
85 };
86
87 searchBase:
88 tSTRING {
89 str := $1
90 logDebugGrammar("STRING - %s", str)
91 var q FieldableQuery
92 if strings.HasPrefix(str, "/") && strings.HasSuffix(str, "/") {
93 q = NewRegexpQuery(str[1:len(str)-1])
94 } else if strings.ContainsAny(str, "*?"){
95 q = NewWildcardQuery(str)
96 } else {
97 q = NewMatchQuery(str)
98 }
99 $$ = q
100 }
101 |
102 tSTRING tTILDE {
103 str := $1
104 fuzziness, err := strconv.ParseFloat($2, 64)
105 if err != nil {
106 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid fuzziness value: %v", err))
107 }
108 logDebugGrammar("FUZZY STRING - %s %f", str, fuzziness)
109 q := NewMatchQuery(str)
110 q.SetFuzziness(int(fuzziness))
111 $$ = q
112 }
113 |
114 tSTRING tCOLON tSTRING tTILDE {
115 field := $1
116 str := $3
117 fuzziness, err := strconv.ParseFloat($4, 64)
118 if err != nil {
119 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid fuzziness value: %v", err))
120 }
121 logDebugGrammar("FIELD - %s FUZZY STRING - %s %f", field, str, fuzziness)
122 q := NewMatchQuery(str)
123 q.SetFuzziness(int(fuzziness))
124 q.SetField(field)
125 $$ = q
126 }
127 |
128 tNUMBER {
129 str := $1
130 logDebugGrammar("STRING - %s", str)
131 q1 := NewMatchQuery(str)
132 val, err := strconv.ParseFloat($1, 64)
133 if err != nil {
134 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("error parsing number: %v", err))
135 }
136 inclusive := true
137 q2 := NewNumericRangeInclusiveQuery(&val, &val, &inclusive, &inclusive)
138 q := NewDisjunctionQuery([]Query{q1,q2})
139 q.queryStringMode = true
140 $$ = q
141 }
142 |
143 tPHRASE {
144 phrase := $1
145 logDebugGrammar("PHRASE - %s", phrase)
146 q := NewMatchPhraseQuery(phrase)
147 $$ = q
148 }
149 |
150 tSTRING tCOLON tSTRING {
151 field := $1
152 str := $3
153 logDebugGrammar("FIELD - %s STRING - %s", field, str)
154 var q FieldableQuery
155 if strings.HasPrefix(str, "/") && strings.HasSuffix(str, "/") {
156 q = NewRegexpQuery(str[1:len(str)-1])
157 } else if strings.ContainsAny(str, "*?"){
158 q = NewWildcardQuery(str)
159 } else {
160 q = NewMatchQuery(str)
161 }
162 q.SetField(field)
163 $$ = q
164 }
165 |
166 tSTRING tCOLON posOrNegNumber {
167 field := $1
168 str := $3
169 logDebugGrammar("FIELD - %s STRING - %s", field, str)
170 q1 := NewMatchQuery(str)
171 q1.SetField(field)
172 val, err := strconv.ParseFloat($3, 64)
173 if err != nil {
174 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("error parsing number: %v", err))
175 }
176 inclusive := true
177 q2 := NewNumericRangeInclusiveQuery(&val, &val, &inclusive, &inclusive)
178 q2.SetField(field)
179 q := NewDisjunctionQuery([]Query{q1,q2})
180 q.queryStringMode = true
181 $$ = q
182 }
183 |
184 tSTRING tCOLON tPHRASE {
185 field := $1
186 phrase := $3
187 logDebugGrammar("FIELD - %s PHRASE - %s", field, phrase)
188 q := NewMatchPhraseQuery(phrase)
189 q.SetField(field)
190 $$ = q
191 }
192 |
193 tSTRING tCOLON tGREATER posOrNegNumber {
194 field := $1
195 min, err := strconv.ParseFloat($4, 64)
196 if err != nil {
197 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("error parsing number: %v", err))
198 }
199 minInclusive := false
200 logDebugGrammar("FIELD - GREATER THAN %f", min)
201 q := NewNumericRangeInclusiveQuery(&min, nil, &minInclusive, nil)
202 q.SetField(field)
203 $$ = q
204 }
205 |
206 tSTRING tCOLON tGREATER tEQUAL posOrNegNumber {
207 field := $1
208 min, err := strconv.ParseFloat($5, 64)
209 if err != nil {
210 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("error parsing number: %v", err))
211 }
212 minInclusive := true
213 logDebugGrammar("FIELD - GREATER THAN OR EQUAL %f", min)
214 q := NewNumericRangeInclusiveQuery(&min, nil, &minInclusive, nil)
215 q.SetField(field)
216 $$ = q
217 }
218 |
219 tSTRING tCOLON tLESS posOrNegNumber {
220 field := $1
221 max, err := strconv.ParseFloat($4, 64)
222 if err != nil {
223 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("error parsing number: %v", err))
224 }
225 maxInclusive := false
226 logDebugGrammar("FIELD - LESS THAN %f", max)
227 q := NewNumericRangeInclusiveQuery(nil, &max, nil, &maxInclusive)
228 q.SetField(field)
229 $$ = q
230 }
231 |
232 tSTRING tCOLON tLESS tEQUAL posOrNegNumber {
233 field := $1
234 max, err := strconv.ParseFloat($5, 64)
235 if err != nil {
236 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("error parsing number: %v", err))
237 }
238 maxInclusive := true
239 logDebugGrammar("FIELD - LESS THAN OR EQUAL %f", max)
240 q := NewNumericRangeInclusiveQuery(nil, &max, nil, &maxInclusive)
241 q.SetField(field)
242 $$ = q
243 }
244 |
245 tSTRING tCOLON tGREATER tPHRASE {
246 field := $1
247 minInclusive := false
248 phrase := $4
249
250 logDebugGrammar("FIELD - GREATER THAN DATE %s", phrase)
251 minTime, err := queryTimeFromString(phrase)
252 if err != nil {
253 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid time: %v", err))
254 }
255 q := NewDateRangeInclusiveQuery(minTime, time.Time{}, &minInclusive, nil)
256 q.SetField(field)
257 $$ = q
258 }
259 |
260 tSTRING tCOLON tGREATER tEQUAL tPHRASE {
261 field := $1
262 minInclusive := true
263 phrase := $5
264
265 logDebugGrammar("FIELD - GREATER THAN OR EQUAL DATE %s", phrase)
266 minTime, err := queryTimeFromString(phrase)
267 if err != nil {
268 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid time: %v", err))
269 }
270 q := NewDateRangeInclusiveQuery(minTime, time.Time{}, &minInclusive, nil)
271 q.SetField(field)
272 $$ = q
273 }
274 |
275 tSTRING tCOLON tLESS tPHRASE {
276 field := $1
277 maxInclusive := false
278 phrase := $4
279
280 logDebugGrammar("FIELD - LESS THAN DATE %s", phrase)
281 maxTime, err := queryTimeFromString(phrase)
282 if err != nil {
283 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid time: %v", err))
284 }
285 q := NewDateRangeInclusiveQuery(time.Time{}, maxTime, nil, &maxInclusive)
286 q.SetField(field)
287 $$ = q
288 }
289 |
290 tSTRING tCOLON tLESS tEQUAL tPHRASE {
291 field := $1
292 maxInclusive := true
293 phrase := $5
294
295 logDebugGrammar("FIELD - LESS THAN OR EQUAL DATE %s", phrase)
296 maxTime, err := queryTimeFromString(phrase)
297 if err != nil {
298 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid time: %v", err))
299 }
300 q := NewDateRangeInclusiveQuery(time.Time{}, maxTime, nil, &maxInclusive)
301 q.SetField(field)
302 $$ = q
303 };
304
305 searchSuffix:
306 /* empty */ {
307 $$ = nil
308 }
309 |
310 tBOOST {
311 $$ = nil
312 boost, err := strconv.ParseFloat($1, 64)
313 if err != nil {
314 yylex.(*lexerWrapper).lex.Error(fmt.Sprintf("invalid boost value: %v", err))
315 } else {
316 $$ = &boost
317 }
318 logDebugGrammar("BOOST %f", boost)
319 };
320
321 posOrNegNumber:
322 tNUMBER {
323 $$ = $1
324 }
325 |
326 tMINUS tNUMBER {
327 $$ = "-" + $2
328 };
329