You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
6.0 KiB

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