@@ -15,22 +15,31 @@ import (
15
15
"github.com/expr-lang/expr/parser/utils"
16
16
)
17
17
18
+ type arg byte
19
+
20
+ const (
21
+ expr arg = 1 << iota
22
+ closure
23
+ )
24
+
25
+ const optional arg = 1 << 7
26
+
18
27
var predicates = map [string ]struct {
19
- arity int
28
+ args [] arg
20
29
}{
21
- "all" : {2 },
22
- "none" : {2 },
23
- "any" : {2 },
24
- "one" : {2 },
25
- "filter" : {2 },
26
- "map" : {2 },
27
- "count" : {2 },
28
- "find" : {2 },
29
- "findIndex" : {2 },
30
- "findLast" : {2 },
31
- "findLastIndex" : {2 },
32
- "groupBy" : {2 },
33
- "reduce" : {3 },
30
+ "all" : {[] arg { expr , closure } },
31
+ "none" : {[] arg { expr , closure } },
32
+ "any" : {[] arg { expr , closure } },
33
+ "one" : {[] arg { expr , closure } },
34
+ "filter" : {[] arg { expr , closure } },
35
+ "map" : {[] arg { expr , closure } },
36
+ "count" : {[] arg { expr , closure } },
37
+ "find" : {[] arg { expr , closure } },
38
+ "findIndex" : {[] arg { expr , closure } },
39
+ "findLast" : {[] arg { expr , closure } },
40
+ "findLastIndex" : {[] arg { expr , closure } },
41
+ "groupBy" : {[] arg { expr , closure } },
42
+ "reduce" : {[] arg { expr , closure , expr | optional } },
34
43
}
35
44
36
45
type parser struct {
@@ -143,7 +152,9 @@ func (p *parser) parseExpression(precedence int) Node {
143
152
p .next ()
144
153
145
154
if opToken .Value == "|" {
146
- nodeLeft = p .parsePipe (nodeLeft )
155
+ identToken := p .current
156
+ p .expect (Identifier )
157
+ nodeLeft = p .parseCall (identToken , []Node {nodeLeft }, true )
147
158
goto next
148
159
}
149
160
@@ -279,7 +290,7 @@ func (p *parser) parsePrimary() Node {
279
290
p .next ()
280
291
token = p .current
281
292
p .expect (Identifier )
282
- return p .parsePostfixExpression (p .parseCall (token , false ))
293
+ return p .parsePostfixExpression (p .parseCall (token , [] Node {}, false ))
283
294
}
284
295
285
296
return p .parseSecondary ()
@@ -307,7 +318,12 @@ func (p *parser) parseSecondary() Node {
307
318
node .SetLocation (token .Location )
308
319
return node
309
320
default :
310
- node = p .parseCall (token , true )
321
+ if p .current .Is (Bracket , "(" ) {
322
+ node = p .parseCall (token , []Node {}, true )
323
+ } else {
324
+ node = & IdentifierNode {Value : token .Value }
325
+ node .SetLocation (token .Location )
326
+ }
311
327
}
312
328
313
329
case Number :
@@ -386,68 +402,86 @@ func (p *parser) toFloatNode(number float64) Node {
386
402
return & FloatNode {Value : number }
387
403
}
388
404
389
- func (p * parser ) parseCall (token Token , checkOverrides bool ) Node {
405
+ func (p * parser ) parseCall (token Token , arguments [] Node , checkOverrides bool ) Node {
390
406
var node Node
391
- if p .current .Is (Bracket , "(" ) {
392
- var arguments []Node
393
-
394
- isOverridden := p .config .IsOverridden (token .Value )
395
- isOverridden = isOverridden && checkOverrides
396
-
397
- // TODO: Refactor parser to use builtin.Builtins instead of predicates map.
398
- if b , ok := predicates [token .Value ]; ok && ! isOverridden {
399
- p .expect (Bracket , "(" )
400
-
401
- if b .arity == 1 {
402
- arguments = make ([]Node , 1 )
403
- arguments [0 ] = p .parseExpression (0 )
404
- } else if b .arity == 2 {
405
- arguments = make ([]Node , 2 )
406
- arguments [0 ] = p .parseExpression (0 )
407
- p .expect (Operator , "," )
408
- arguments [1 ] = p .parseClosure ()
409
- }
410
407
411
- if token .Value == "reduce" {
412
- arguments = make ([]Node , 2 )
413
- arguments [0 ] = p .parseExpression (0 )
414
- p .expect (Operator , "," )
415
- arguments [1 ] = p .parseClosure ()
416
- if p .current .Is (Operator , "," ) {
417
- p .next ()
418
- arguments = append (arguments , p .parseExpression (0 ))
419
- }
420
- }
408
+ isOverridden := p .config .IsOverridden (token .Value )
409
+ isOverridden = isOverridden && checkOverrides
410
+
411
+ if b , ok := predicates [token .Value ]; ok && ! isOverridden {
412
+ p .expect (Bracket , "(" )
421
413
422
- p .expect (Bracket , ")" )
414
+ // In case of the pipe operator, the first argument is the left-hand side
415
+ // of the operator, so we do not parse it as an argument inside brackets.
416
+ args := b .args [len (arguments ):]
423
417
424
- node = & BuiltinNode {
425
- Name : token .Value ,
426
- Arguments : arguments ,
418
+ for i , arg := range args {
419
+ if arg & optional == optional {
420
+ if p .current .Is (Bracket , ")" ) {
421
+ break
422
+ }
423
+ } else {
424
+ if p .current .Is (Bracket , ")" ) {
425
+ p .error ("expected at least %d arguments" , len (args ))
426
+ }
427
427
}
428
- node .SetLocation (token .Location )
429
- } else if _ , ok := builtin .Index [token .Value ]; ok && ! p .config .Disabled [token .Value ] && ! isOverridden {
430
- node = & BuiltinNode {
431
- Name : token .Value ,
432
- Arguments : p .parseArguments (),
428
+
429
+ if i > 0 {
430
+ p .expect (Operator , "," )
433
431
}
434
- node .SetLocation (token .Location )
435
- } else {
436
- callee := & IdentifierNode {Value : token .Value }
437
- callee .SetLocation (token .Location )
438
- node = & CallNode {
439
- Callee : callee ,
440
- Arguments : p .parseArguments (),
432
+ var node Node
433
+ switch {
434
+ case arg & expr == expr :
435
+ node = p .parseExpression (0 )
436
+ case arg & closure == closure :
437
+ node = p .parseClosure ()
441
438
}
442
- node .SetLocation (token .Location )
439
+ arguments = append (arguments , node )
440
+ }
441
+
442
+ p .expect (Bracket , ")" )
443
+
444
+ node = & BuiltinNode {
445
+ Name : token .Value ,
446
+ Arguments : arguments ,
447
+ }
448
+ node .SetLocation (token .Location )
449
+ } else if _ , ok := builtin .Index [token .Value ]; ok && ! p .config .Disabled [token .Value ] && ! isOverridden {
450
+ node = & BuiltinNode {
451
+ Name : token .Value ,
452
+ Arguments : p .parseArguments (arguments ),
443
453
}
454
+ node .SetLocation (token .Location )
444
455
} else {
445
- node = & IdentifierNode {Value : token .Value }
456
+ callee := & IdentifierNode {Value : token .Value }
457
+ callee .SetLocation (token .Location )
458
+ node = & CallNode {
459
+ Callee : callee ,
460
+ Arguments : p .parseArguments (arguments ),
461
+ }
446
462
node .SetLocation (token .Location )
447
463
}
448
464
return node
449
465
}
450
466
467
+ func (p * parser ) parseArguments (arguments []Node ) []Node {
468
+ // If pipe operator is used, the first argument is the left-hand side
469
+ // of the operator, so we do not parse it as an argument inside brackets.
470
+ offset := len (arguments )
471
+
472
+ p .expect (Bracket , "(" )
473
+ for ! p .current .Is (Bracket , ")" ) && p .err == nil {
474
+ if len (arguments ) > offset {
475
+ p .expect (Operator , "," )
476
+ }
477
+ node := p .parseExpression (0 )
478
+ arguments = append (arguments , node )
479
+ }
480
+ p .expect (Bracket , ")" )
481
+
482
+ return arguments
483
+ }
484
+
451
485
func (p * parser ) parseClosure () Node {
452
486
startToken := p .current
453
487
expectClosingBracket := false
@@ -575,7 +609,7 @@ func (p *parser) parsePostfixExpression(node Node) Node {
575
609
memberNode .Method = true
576
610
node = & CallNode {
577
611
Callee : memberNode ,
578
- Arguments : p .parseArguments (),
612
+ Arguments : p .parseArguments ([] Node {} ),
579
613
}
580
614
node .SetLocation (propertyToken .Location )
581
615
} else {
@@ -641,72 +675,3 @@ func (p *parser) parsePostfixExpression(node Node) Node {
641
675
}
642
676
return node
643
677
}
644
-
645
- func (p * parser ) parsePipe (node Node ) Node {
646
- identifier := p .current
647
- p .expect (Identifier )
648
-
649
- arguments := []Node {node }
650
-
651
- if b , ok := predicates [identifier .Value ]; ok {
652
- p .expect (Bracket , "(" )
653
-
654
- // TODO: Refactor parser to use builtin.Builtins instead of predicates map.
655
-
656
- if b .arity == 2 {
657
- arguments = append (arguments , p .parseClosure ())
658
- }
659
-
660
- if identifier .Value == "reduce" {
661
- arguments = append (arguments , p .parseClosure ())
662
- if p .current .Is (Operator , "," ) {
663
- p .next ()
664
- arguments = append (arguments , p .parseExpression (0 ))
665
- }
666
- }
667
-
668
- p .expect (Bracket , ")" )
669
-
670
- node = & BuiltinNode {
671
- Name : identifier .Value ,
672
- Arguments : arguments ,
673
- }
674
- node .SetLocation (identifier .Location )
675
- } else if _ , ok := builtin .Index [identifier .Value ]; ok {
676
- arguments = append (arguments , p .parseArguments ()... )
677
-
678
- node = & BuiltinNode {
679
- Name : identifier .Value ,
680
- Arguments : arguments ,
681
- }
682
- node .SetLocation (identifier .Location )
683
- } else {
684
- callee := & IdentifierNode {Value : identifier .Value }
685
- callee .SetLocation (identifier .Location )
686
-
687
- arguments = append (arguments , p .parseArguments ()... )
688
-
689
- node = & CallNode {
690
- Callee : callee ,
691
- Arguments : arguments ,
692
- }
693
- node .SetLocation (identifier .Location )
694
- }
695
-
696
- return node
697
- }
698
-
699
- func (p * parser ) parseArguments () []Node {
700
- p .expect (Bracket , "(" )
701
- nodes := make ([]Node , 0 )
702
- for ! p .current .Is (Bracket , ")" ) && p .err == nil {
703
- if len (nodes ) > 0 {
704
- p .expect (Operator , "," )
705
- }
706
- node := p .parseExpression (0 )
707
- nodes = append (nodes , node )
708
- }
709
- p .expect (Bracket , ")" )
710
-
711
- return nodes
712
- }
0 commit comments