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