github.com/GuanceCloud/cliutils@v1.1.21/filter/gram.y (about) 1 %{ 2 package filter 3 4 import ( 5 "time" 6 ) 7 %} 8 9 %union { 10 node Node 11 nodes []Node 12 13 item Item 14 15 strings []string 16 float float64 17 duration time.Duration 18 timestamp time.Time 19 } 20 21 %token <item> EQ COLON SEMICOLON COMMA COMMENT DURATION 22 EOF ERROR ID LEFT_BRACE LEFT_BRACKET 23 LEFT_PAREN NUMBER RIGHT_BRACE RIGHT_BRACKET 24 RIGHT_PAREN SPACE STRING QUOTED_STRING NAMESPACE 25 DOT 26 27 // operator 28 %token operatorsStart 29 %token <item> ADD 30 DIV GTE GT 31 LT LTE MOD MUL 32 NEQ POW SUB 33 %token operatorsEnd 34 35 // keywords 36 %token keywordsStart 37 %token <item> 38 AS ASC AUTO BY 39 MATCH NOT_MATCH 40 DESC TRUE FALSE FILTER 41 IDENTIFIER IN NOT_IN AND LINK LIMIT SLIMIT 42 OR NIL NULL OFFSET SOFFSET 43 ORDER RE INT FLOAT POINT TIMEZONE WITH 44 %token keywordsEnd 45 46 // start symbols for parser 47 %token startSymbolsStart 48 %token START_STMTS START_BINARY_EXPRESSION START_FUNC_EXPRESSION START_WHERE_CONDITION 49 %token startSymbolsEnd 50 51 //////////////////////////////////////////////////// 52 // grammar rules 53 //////////////////////////////////////////////////// 54 %type <item> 55 unary_op 56 function_name 57 identifier 58 59 %type<nodes> 60 filter_list 61 function_args 62 63 %type <node> 64 stmts 65 where_conditions 66 array_elem 67 array_list 68 attr_expr 69 binary_expr 70 expr 71 function_arg 72 function_expr 73 naming_arg 74 paren_expr 75 filter_elem 76 regex 77 columnref 78 bool_literal 79 string_literal 80 nil_literal 81 number_literal 82 cascade_functions 83 star 84 85 %start start 86 87 // operator listed with increasing precedence 88 %left OR 89 %left AND 90 %left GTE GT NEQ EQ LTE LT 91 %left ADD SUB 92 %left MUL DIV MOD 93 %right POW 94 95 // `offset` do not have associativity 96 %nonassoc OFFSET 97 %right LEFT_BRACKET 98 99 %% 100 101 start: START_WHERE_CONDITION stmts 102 { 103 yylex.(*parser).parseResult = $2 104 } 105 | start EOF 106 | error 107 { 108 yylex.(*parser).unexpected("", "") 109 } 110 ; 111 112 stmts: where_conditions 113 { 114 $$ = WhereConditions{$1} 115 } 116 | stmts SEMICOLON where_conditions 117 { 118 if $3 != nil { 119 arr := $1.(WhereConditions) 120 arr = append(arr, $3) 121 $$ = arr 122 } else { 123 $$ = $1 124 } 125 } 126 ; 127 128 /* expression */ 129 expr: array_elem | regex | paren_expr | function_expr | binary_expr | cascade_functions 130 ; 131 132 columnref: identifier 133 { 134 $$ = &Identifier{Name: $1.Val} 135 } 136 | attr_expr 137 { 138 $$ = $1 139 } 140 ; 141 142 attr_expr: identifier DOT identifier 143 { 144 $$ = &AttrExpr{ 145 Obj: &Identifier{Name: $1.Val}, 146 Attr: &Identifier{Name: $3.Val}, 147 } 148 } 149 | attr_expr DOT identifier 150 { 151 $$ = &AttrExpr{ 152 Obj: $1.(*AttrExpr), 153 Attr: &Identifier{Name: $3.Val}, 154 } 155 } 156 ; 157 158 unary_op: ADD 159 | SUB 160 ; 161 162 string_literal: STRING 163 { 164 $$ = &StringLiteral{Val: yylex.(*parser).unquoteString($1.Val)} 165 } 166 ; 167 168 nil_literal: NIL 169 { 170 $$ = &NilLiteral{} 171 } 172 | NULL 173 { 174 $$ = &NilLiteral{} 175 } 176 ; 177 178 bool_literal: TRUE 179 { 180 $$ = &BoolLiteral{Val: true} 181 } 182 | FALSE 183 { 184 $$ = &BoolLiteral{Val: false} 185 } 186 ; 187 188 paren_expr: LEFT_PAREN expr RIGHT_PAREN 189 { 190 $$ = &ParenExpr{Param: $2} 191 } 192 ; 193 194 function_expr: function_name LEFT_PAREN function_args RIGHT_PAREN 195 { 196 $$ = yylex.(*parser).newFunc($1.Val, $3) 197 } 198 ; 199 200 cascade_functions: function_expr DOT function_expr 201 { 202 $$ = &CascadeFunctions{Funcs: []*FuncExpr{$1.(*FuncExpr), $3.(*FuncExpr)}} 203 } 204 | cascade_functions DOT function_expr 205 { 206 fc := $1.(*CascadeFunctions) 207 fc.Funcs = append(fc.Funcs, $3.(*FuncExpr)) 208 $$ = fc 209 } 210 ; 211 212 function_args: function_args COMMA function_arg 213 { 214 $$ = append($$, $3) 215 } 216 | function_args COMMA 217 | function_arg 218 { 219 $$ = []Node{$1} 220 } 221 | /* empty */ 222 { 223 $$ = nil 224 } 225 ; 226 227 array_list: array_list COMMA array_elem 228 { 229 nl := $$.(NodeList) 230 nl = append(nl, $3) 231 $$ = nl 232 } 233 | array_elem 234 { 235 $$ = NodeList{$1} 236 } 237 | /* empty */ 238 { 239 $$ = NodeList{} 240 } 241 ; 242 243 array_elem: number_literal 244 | string_literal 245 | columnref 246 | nil_literal 247 | bool_literal 248 | star 249 ; 250 251 star : MUL 252 { 253 $$ = &Star{} 254 } 255 ; 256 257 function_arg: naming_arg 258 | expr 259 | LEFT_BRACKET array_list RIGHT_BRACKET 260 { 261 $$ = getFuncArgList($2.(NodeList)) 262 } 263 ; 264 265 naming_arg: identifier EQ expr 266 { 267 $$ = &FuncArg{ArgName: $1.Val, ArgVal: $3} 268 } 269 | identifier EQ LEFT_BRACKET array_list RIGHT_BRACKET 270 { 271 $$ = &FuncArg{ 272 ArgName: $1.Val, 273 ArgVal: getFuncArgList($4.(NodeList)), 274 } 275 } 276 ; 277 278 where_conditions: LEFT_BRACE filter_list RIGHT_BRACE 279 { 280 $$ = yylex.(*parser).newWhereConditions($2) 281 } 282 | /* empty */ 283 { 284 $$ = nil 285 } 286 ; 287 288 /* filter list */ 289 filter_list: filter_elem 290 { 291 $$ = []Node{ $1 } 292 } 293 | filter_list COMMA filter_elem 294 { 295 $$ = append($$, $3) 296 } 297 | filter_list COMMA 298 | /* empty */ 299 { $$ = nil } 300 ; 301 302 filter_elem: binary_expr | paren_expr 303 ; 304 305 binary_expr: expr ADD expr 306 { 307 $$ = yylex.(*parser).newBinExpr($1, $3, $2) 308 } 309 | expr DIV expr 310 { 311 $$ = yylex.(*parser).newBinExpr($1, $3, $2) 312 } 313 | expr GTE expr 314 { 315 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 316 bexpr.ReturnBool = true 317 $$ = bexpr 318 } 319 | expr GT expr 320 { 321 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 322 bexpr.ReturnBool = true 323 $$ = bexpr 324 } 325 | expr AND expr 326 { 327 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 328 bexpr.ReturnBool = true 329 $$ = bexpr 330 } 331 | expr OR expr 332 { 333 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 334 bexpr.ReturnBool = true 335 $$ = bexpr 336 } 337 | expr LT expr 338 { 339 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 340 bexpr.ReturnBool = true 341 $$ = bexpr 342 } 343 | expr LTE expr 344 { 345 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 346 bexpr.ReturnBool = true 347 $$ = bexpr 348 } 349 | expr MOD expr 350 { 351 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 352 $$ = bexpr 353 } 354 | expr MUL expr 355 { 356 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 357 $$ = bexpr 358 } 359 | expr NEQ expr 360 { 361 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 362 bexpr.ReturnBool = true 363 $$ = bexpr 364 } 365 | expr POW expr 366 { 367 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 368 $$ = bexpr 369 } 370 | expr SUB expr 371 { 372 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 373 $$ = bexpr 374 } 375 | expr EQ expr 376 { 377 bexpr := yylex.(*parser).newBinExpr($1, $3, $2) 378 bexpr.ReturnBool = true 379 $$ = bexpr 380 } 381 | columnref IN LEFT_BRACKET array_list RIGHT_BRACKET 382 { 383 bexpr := yylex.(*parser).newBinExpr($1, $4, $2) 384 bexpr.ReturnBool = true 385 $$ = bexpr 386 } 387 | columnref NOT_IN LEFT_BRACKET array_list RIGHT_BRACKET 388 { 389 bexpr := yylex.(*parser).newBinExpr($1, $4, $2) 390 bexpr.ReturnBool = true 391 $$ = bexpr 392 } 393 | columnref MATCH LEFT_BRACKET array_list RIGHT_BRACKET 394 { 395 bexpr := yylex.(*parser).newBinExpr($1, $4, $2) 396 bexpr.ReturnBool = true 397 $$ = bexpr 398 } 399 | columnref NOT_MATCH LEFT_BRACKET array_list RIGHT_BRACKET 400 { 401 bexpr := yylex.(*parser).newBinExpr($1, $4, $2) 402 bexpr.ReturnBool = true 403 $$ = bexpr 404 } 405 ; 406 407 /* function names */ 408 function_name: identifier 409 { 410 $$ = $1 411 } 412 | attr_expr 413 { 414 $$ = Item{Val: $1.(*AttrExpr).String()} 415 } 416 ; 417 418 /* literals */ 419 number_literal: NUMBER 420 { 421 $$ = yylex.(*parser).number($1.Val) 422 } 423 | unary_op NUMBER 424 { 425 num := yylex.(*parser).number($2.Val) 426 switch $1.Typ { 427 case ADD: // pass 428 case SUB: 429 if num.IsInt { 430 num.Int = -num.Int 431 } else { 432 num.Float = -num.Float 433 } 434 } 435 $$ = num 436 } 437 ; 438 439 regex: RE LEFT_PAREN string_literal RIGHT_PAREN 440 { 441 $$ = yylex.(*parser).newRegex($3.(*StringLiteral).Val) 442 } 443 | RE LEFT_PAREN QUOTED_STRING RIGHT_PAREN 444 { 445 $$ = yylex.(*parser).newRegex(yylex.(*parser).unquoteString($3.Val)) 446 } 447 ; 448 449 identifier: ID 450 | QUOTED_STRING 451 { 452 $$.Val = yylex.(*parser).unquoteString($1.Val) 453 } 454 | IDENTIFIER LEFT_PAREN string_literal RIGHT_PAREN 455 { 456 $$.Val = $3.(*StringLiteral).Val 457 } 458 %%