@@ -15,22 +15,31 @@ import (
1515 "github.com/expr-lang/expr/parser/utils"
1616)
1717
18+ type arg byte
19+
20+ const (
21+ expr arg = 1 << iota
22+ closure
23+ )
24+
25+ const optional arg = 1 << 7
26+
1827var predicates = map [string ]struct {
19- arity int
28+ args [] arg
2029}{
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 } },
3443}
3544
3645type parser struct {
@@ -143,7 +152,9 @@ func (p *parser) parseExpression(precedence int) Node {
143152 p .next ()
144153
145154 if opToken .Value == "|" {
146- nodeLeft = p .parsePipe (nodeLeft )
155+ identToken := p .current
156+ p .expect (Identifier )
157+ nodeLeft = p .parseCall (identToken , []Node {nodeLeft }, true )
147158 goto next
148159 }
149160
@@ -279,7 +290,7 @@ func (p *parser) parsePrimary() Node {
279290 p .next ()
280291 token = p .current
281292 p .expect (Identifier )
282- return p .parsePostfixExpression (p .parseCall (token , false ))
293+ return p .parsePostfixExpression (p .parseCall (token , [] Node {}, false ))
283294 }
284295
285296 return p .parseSecondary ()
@@ -307,7 +318,12 @@ func (p *parser) parseSecondary() Node {
307318 node .SetLocation (token .Location )
308319 return node
309320 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+ }
311327 }
312328
313329 case Number :
@@ -386,68 +402,86 @@ func (p *parser) toFloatNode(number float64) Node {
386402 return & FloatNode {Value : number }
387403}
388404
389- func (p * parser ) parseCall (token Token , checkOverrides bool ) Node {
405+ func (p * parser ) parseCall (token Token , arguments [] Node , checkOverrides bool ) Node {
390406 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- }
410407
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 , "(" )
421413
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 ):]
423417
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+ }
427427 }
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 , "," )
433431 }
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 ()
441438 }
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 ),
443453 }
454+ node .SetLocation (token .Location )
444455 } 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+ }
446462 node .SetLocation (token .Location )
447463 }
448464 return node
449465}
450466
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+
451485func (p * parser ) parseClosure () Node {
452486 startToken := p .current
453487 expectClosingBracket := false
@@ -575,7 +609,7 @@ func (p *parser) parsePostfixExpression(node Node) Node {
575609 memberNode .Method = true
576610 node = & CallNode {
577611 Callee : memberNode ,
578- Arguments : p .parseArguments (),
612+ Arguments : p .parseArguments ([] Node {} ),
579613 }
580614 node .SetLocation (propertyToken .Location )
581615 } else {
@@ -641,72 +675,3 @@ func (p *parser) parsePostfixExpression(node Node) Node {
641675 }
642676 return node
643677}
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