-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsearch-query.jison
120 lines (102 loc) · 4.13 KB
/
search-query.jison
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
120
/**
* http://zaach.github.io/jison/try/
* http://jsonformatter.curiousconcept.com/
* Still pending:
* - UNION
*/
/* description: Parses SQL */
/* :tabSize=2:indentSize=2:noTabs=true: */
%lex
%options case-insensitive
%%
\s+ /* skip whitespace */
'BETWEEN' return 'BETWEEN'
'ORDER BY' return 'ORDER_BY'
',' return 'COMMA'
'=' return 'CMP_EQUALS'
'!=' return 'CMP_NOTEQUALS'
'>=' return 'CMP_GREATEROREQUAL'
'>' return 'CMP_GREATER'
'<=' return 'CMP_LESSOREQUAL'
'<' return 'CMP_LESS'
'(' return 'LPAREN'
')' return 'RPAREN'
'IS' return 'IS'
'IN' return 'IN'
'AND' return 'LOGICAL_AND'
'OR' return 'LOGICAL_OR'
'NOT' return 'LOGICAL_NOT'
'LIKE' return 'LIKE'
'ASC' return 'ASC'
'DESC' return 'DESC'
['](\\.|[^'])*['] return 'STRING'
'NULL' return 'NULL'
true return 'TRUE'
false return 'FALSE'
[0-9]+(\.[0-9]+)? return 'NUMERIC'
[a-zA-Z_][a-zA-Z0-9_]* return 'IDENTIFIER'
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
%start main
%% /* language grammar */
main
: expression orderBy EOF
{ return {search: $1, order: $2}; }
;
orderBy
: { $$ = null; }
| ORDER_BY orderByCommaList { $$ = $2; }
;
orderValue
: IDENTIFIER orderWay { $$ = {field: $1, way: $2}; }
;
orderWay
: { $$ = 'asc';}
| ASC { $$ = 'asc'; }
| DESC { $$ = 'desc'; }
;
orderByCommaList
: orderByCommaList COMMA orderValue { $$ = $1; $1.push($3); }
| orderValue { $$ = [$1]; }
;
expression
: condition { $$ = [$1]; }
| expression expressionConnector condition { $$ = $1; $3.connector=$2; $1.push($3); }
;
expressionConnector
: LOGICAL_AND { $$ = 'and'; }
| LOGICAL_OR { $$ = 'or'; }
;
condition
: IDENTIFIER comparison value { $$ = {field: $1, comparison: $2, value: $3}; }
| IDENTIFIER IN LPAREN commaList RPAREN { $$ = {field: $1, comparison: 'in', value: $4}; }
| IDENTIFIER LOGICAL_NOT IN LPAREN commaList RPAREN { $$ = {field: $1, comparison: 'not in', value: $5}; }
| IDENTIFIER IS NULL { $$ = {field: $1, comparison: 'is', value: null}; }
| IDENTIFIER IS LOGICAL_NOT NULL { $$ = {field: $1, comparison: 'is not', value: null}; }
| IDENTIFIER BETWEEN value LOGICAL_AND value { $$ = {field: $1, comparison: 'between', value: [$3, $5]}; }
| IDENTIFIER LOGICAL_NOT BETWEEN value LOGICAL_AND value { $$ = {field: $1, comparison: 'not between', value: [$4, $6]}; }
| LPAREN expression RPAREN { $$ = {items: $2}; }
;
commaList
: commaList COMMA value { $$ = $1; $1.push($3); }
| value { $$ = [$1]; }
;
value
: STRING { $$ = yytext.substr(1, yytext.length - 2) } /* we don't want the wrapping quotes in output */
| NUMERIC { $$ = Number(yytext) } /* output should return a true number, not a number as a string */
| TRUE { $$ = true }
| FALSE { $$ = false }
| IDENTIFIER {$$ = yytext; }
;
comparison
: CMP_EQUALS { $$ = $1; }
| CMP_NOTEQUALS { $$ = $1; }
| CMP_NOTEQUALS_BASIC { $$ = $1; }
| CMP_GREATER { $$ = $1; }
| CMP_GREATEROREQUAL { $$ = $1; }
| CMP_LESS { $$ = $1; }
| CMP_LESSOREQUAL { $$ = $1; }
| LIKE { $$ = 'like'; }
| LOGICAL_NOT LIKE { $$ = 'not like'; }
;