11package execution
22
33import (
4+ "errors"
45 "fmt"
56
67 "github.com/tomwright/dasel/v3/model"
78 "github.com/tomwright/dasel/v3/selector/ast"
89 "github.com/tomwright/dasel/v3/selector/lexer"
910)
1011
11- func binaryExprExecutor (opts * Options , e ast.BinaryExpr ) (expressionExecutor , error ) {
12- return func (data * model.Value ) (* model.Value , error ) {
13- left , err := ExecuteAST (e .Left , data , opts )
12+ type binaryExpressionExecutorFn func (expr ast.BinaryExpr , value * model.Value , options * Options ) (* model.Value , error )
13+
14+ func basicBinaryExpressionExecutorFn (handler func (left * model.Value , right * model.Value , e ast.BinaryExpr ) (* model.Value , error )) binaryExpressionExecutorFn {
15+ return func (expr ast.BinaryExpr , value * model.Value , options * Options ) (* model.Value , error ) {
16+ left , err := ExecuteAST (expr .Left , value , options )
1417 if err != nil {
1518 return nil , fmt .Errorf ("error evaluating left expression: %w" , err )
1619 }
1720
18- var doOperation func (a * model.Value , b * model.Value ) (* model.Value , error )
19-
20- switch e .Operator .Kind {
21- case lexer .Plus :
22- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
23- return a .Add (b )
24- }
25- case lexer .Dash :
26- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
27- return a .Subtract (b )
28- }
29- case lexer .Star :
30- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
31- return a .Multiply (b )
32- }
33- case lexer .Slash :
34- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
35- return a .Divide (b )
36- }
37- case lexer .Percent :
38- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
39- return a .Modulo (b )
40- }
41- case lexer .GreaterThan :
42- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
43- return a .GreaterThan (b )
44- }
45- case lexer .GreaterThanOrEqual :
46- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
47- return a .GreaterThanOrEqual (b )
48- }
49- case lexer .LessThan :
50- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
51- return a .LessThan (b )
52- }
53- case lexer .LessThanOrEqual :
54- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
55- return a .LessThanOrEqual (b )
56- }
57- case lexer .Equal :
58- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
59- return a .Equal (b )
60- }
61- case lexer .NotEqual :
62- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
63- return a .NotEqual (b )
64- }
65- case lexer .Equals :
66- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
67- err := a .Set (b )
68- if err != nil {
69- return nil , fmt .Errorf ("error setting value: %w" , err )
70- }
71- switch a .Type () {
72- case model .TypeMap :
73- return a , nil
74- case model .TypeSlice :
75- return a , nil
76- default :
77- return b , nil
78- }
79- }
80- case lexer .And :
81- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
82- leftBool , err := a .BoolValue ()
83- if err != nil {
84- return nil , fmt .Errorf ("error getting left bool value: %w" , err )
85- }
86- rightBool , err := b .BoolValue ()
87- if err != nil {
88- return nil , fmt .Errorf ("error getting right bool value: %w" , err )
89- }
90- return model .NewBoolValue (leftBool && rightBool ), nil
91- }
92- case lexer .Or :
93- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
94- leftBool , err := a .BoolValue ()
95- if err != nil {
96- return nil , fmt .Errorf ("error getting left bool value: %w" , err )
97- }
98- rightBool , err := b .BoolValue ()
99- if err != nil {
100- return nil , fmt .Errorf ("error getting right bool value: %w" , err )
101- }
102- return model .NewBoolValue (leftBool || rightBool ), nil
103- }
104- case lexer .Like , lexer .NotLike :
105- doOperation = func (a * model.Value , b * model.Value ) (* model.Value , error ) {
106- leftStr , err := a .StringValue ()
107- if err != nil {
108- return nil , fmt .Errorf ("like requires left side to be a string, got %s" , left .Type ().String ())
109- }
110- rightPatt , ok := e .Right .(ast.RegexExpr )
111- if ! ok {
112- return nil , fmt .Errorf ("like requires right side to be a regex pattern" )
113- }
114- res := rightPatt .Regex .MatchString (leftStr )
115- if e .Operator .Kind == lexer .NotLike {
116- res = ! res
117- }
118- return model .NewBoolValue (res ), nil
119- }
120- default :
121- return nil , fmt .Errorf ("unhandled operator: %s" , e .Operator .Value )
122- }
123-
124- if doOperation == nil {
125- return nil , fmt .Errorf ("missing operation for operator %s" , e .Operator .Value )
126- }
127-
12821 if ! left .IsBranch () {
129- right , err := ExecuteAST (e .Right , data , opts )
22+ right , err := ExecuteAST (expr .Right , value , options )
13023 if err != nil {
13124 return nil , fmt .Errorf ("error evaluating right expression: %w" , err )
13225 }
133- return doOperation (left , right )
26+ return handler (left , right , expr )
13427 }
13528
13629 res := model .NewSliceValue ()
13730 res .MarkAsBranch ()
13831 if err := left .RangeSlice (func (i int , v * model.Value ) error {
139- right , err := ExecuteAST (e .Right , v , opts )
32+ right , err := ExecuteAST (expr .Right , v , options )
14033 if err != nil {
14134 return fmt .Errorf ("error evaluating right expression: %w" , err )
14235 }
143-
144- r , err := doOperation (v , right )
36+ r , err := handler (v , right , expr )
14537 if err != nil {
14638 return err
14739 }
@@ -153,5 +45,149 @@ func binaryExprExecutor(opts *Options, e ast.BinaryExpr) (expressionExecutor, er
15345 return nil , err
15446 }
15547 return res , nil
48+ }
49+ }
50+
51+ var binaryExpressionExecutors = map [lexer.TokenKind ]binaryExpressionExecutorFn {}
52+
53+ func binaryExprExecutor (opts * Options , e ast.BinaryExpr ) (expressionExecutor , error ) {
54+ return func (data * model.Value ) (* model.Value , error ) {
55+
56+ exec , ok := binaryExpressionExecutors [e .Operator .Kind ]
57+ if ! ok {
58+ return nil , fmt .Errorf ("unhandled operator: %s" , e .Operator .Value )
59+ }
60+
61+ return exec (e , data , opts )
15662 }, nil
15763}
64+
65+ func init () {
66+ binaryExpressionExecutors [lexer .Plus ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
67+ return left .Add (right )
68+ })
69+ binaryExpressionExecutors [lexer .Dash ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
70+ return left .Subtract (right )
71+ })
72+ binaryExpressionExecutors [lexer .Star ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
73+ return left .Multiply (right )
74+ })
75+ binaryExpressionExecutors [lexer .Slash ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
76+ return left .Divide (right )
77+ })
78+ binaryExpressionExecutors [lexer .Percent ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
79+ return left .Modulo (right )
80+ })
81+ binaryExpressionExecutors [lexer .GreaterThan ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
82+ return left .GreaterThan (right )
83+ })
84+ binaryExpressionExecutors [lexer .GreaterThanOrEqual ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
85+ return left .GreaterThanOrEqual (right )
86+ })
87+ binaryExpressionExecutors [lexer .LessThan ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
88+ return left .LessThan (right )
89+ })
90+ binaryExpressionExecutors [lexer .LessThanOrEqual ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
91+ return left .LessThanOrEqual (right )
92+ })
93+ binaryExpressionExecutors [lexer .Equal ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
94+ return left .Equal (right )
95+ })
96+ binaryExpressionExecutors [lexer .NotEqual ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
97+ return left .NotEqual (right )
98+ })
99+ binaryExpressionExecutors [lexer .Equals ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
100+ err := left .Set (right )
101+ if err != nil {
102+ return nil , fmt .Errorf ("error setting value: %w" , err )
103+ }
104+ switch left .Type () {
105+ case model .TypeMap :
106+ return left , nil
107+ case model .TypeSlice :
108+ return left , nil
109+ default :
110+ return right , nil
111+ }
112+ })
113+ binaryExpressionExecutors [lexer .And ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
114+ leftBool , err := left .BoolValue ()
115+ if err != nil {
116+ return nil , fmt .Errorf ("error getting left bool value: %w" , err )
117+ }
118+ rightBool , err := right .BoolValue ()
119+ if err != nil {
120+ return nil , fmt .Errorf ("error getting right bool value: %w" , err )
121+ }
122+ return model .NewBoolValue (leftBool && rightBool ), nil
123+ })
124+ binaryExpressionExecutors [lexer .Or ] = basicBinaryExpressionExecutorFn (func (left * model.Value , right * model.Value , _ ast.BinaryExpr ) (* model.Value , error ) {
125+ leftBool , err := left .BoolValue ()
126+ if err != nil {
127+ return nil , fmt .Errorf ("error getting left bool value: %w" , err )
128+ }
129+ rightBool , err := right .BoolValue ()
130+ if err != nil {
131+ return nil , fmt .Errorf ("error getting right bool value: %w" , err )
132+ }
133+ return model .NewBoolValue (leftBool || rightBool ), nil
134+ })
135+ binaryExpressionExecutors [lexer .Like ] = basicBinaryExpressionExecutorFn (func (left * model.Value , _ * model.Value , e ast.BinaryExpr ) (* model.Value , error ) {
136+ leftStr , err := left .StringValue ()
137+ if err != nil {
138+ return nil , fmt .Errorf ("like requires left side to be a string, got %s" , left .Type ().String ())
139+ }
140+ rightPatt , ok := e .Right .(ast.RegexExpr )
141+ if ! ok {
142+ return nil , fmt .Errorf ("like requires right side to be a regex pattern" )
143+ }
144+ res := rightPatt .Regex .MatchString (leftStr )
145+ return model .NewBoolValue (res ), nil
146+ })
147+ binaryExpressionExecutors [lexer .NotLike ] = basicBinaryExpressionExecutorFn (func (left * model.Value , _ * model.Value , e ast.BinaryExpr ) (* model.Value , error ) {
148+ leftStr , err := left .StringValue ()
149+ if err != nil {
150+ return nil , fmt .Errorf ("like requires left side to be a string, got %s" , left .Type ().String ())
151+ }
152+ rightPatt , ok := e .Right .(ast.RegexExpr )
153+ if ! ok {
154+ return nil , fmt .Errorf ("like requires right side to be a regex pattern" )
155+ }
156+ res := rightPatt .Regex .MatchString (leftStr )
157+ return model .NewBoolValue (! res ), nil
158+ })
159+ binaryExpressionExecutors [lexer .DoubleQuestionMark ] = func (expr ast.BinaryExpr , value * model.Value , options * Options ) (* model.Value , error ) {
160+ left , err := ExecuteAST (expr .Left , value , options )
161+
162+ if err == nil && ! left .IsNull () {
163+ return left , nil
164+ }
165+
166+ if err != nil {
167+ handleErrs := []any {
168+ model.ErrIncompatibleTypes {},
169+ model.ErrUnexpectedType {},
170+ model.ErrUnexpectedTypes {},
171+ model.SliceIndexOutOfRange {},
172+ model.MapKeyNotFound {},
173+ }
174+ for _ , e := range handleErrs {
175+ if errors .As (err , & e ) {
176+ err = nil
177+ break
178+ }
179+ }
180+
181+ if err != nil {
182+ return nil , fmt .Errorf ("error evaluating left expression: %w" , err )
183+ }
184+ }
185+
186+ // Do we need to handle branches here?
187+ right , err := ExecuteAST (expr .Right , value , options )
188+ if err != nil {
189+ return nil , fmt .Errorf ("error evaluating right expression: %w" , err )
190+ }
191+ return right , nil
192+ }
193+ }
0 commit comments