1
1
package execution
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
5
6
6
7
"github.com/tomwright/dasel/v3/model"
7
8
"github.com/tomwright/dasel/v3/selector/ast"
8
9
"github.com/tomwright/dasel/v3/selector/lexer"
9
10
)
10
11
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 )
14
17
if err != nil {
15
18
return nil , fmt .Errorf ("error evaluating left expression: %w" , err )
16
19
}
17
20
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
-
128
21
if ! left .IsBranch () {
129
- right , err := ExecuteAST (e .Right , data , opts )
22
+ right , err := ExecuteAST (expr .Right , value , options )
130
23
if err != nil {
131
24
return nil , fmt .Errorf ("error evaluating right expression: %w" , err )
132
25
}
133
- return doOperation (left , right )
26
+ return handler (left , right , expr )
134
27
}
135
28
136
29
res := model .NewSliceValue ()
137
30
res .MarkAsBranch ()
138
31
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 )
140
33
if err != nil {
141
34
return fmt .Errorf ("error evaluating right expression: %w" , err )
142
35
}
143
-
144
- r , err := doOperation (v , right )
36
+ r , err := handler (v , right , expr )
145
37
if err != nil {
146
38
return err
147
39
}
@@ -153,5 +45,149 @@ func binaryExprExecutor(opts *Options, e ast.BinaryExpr) (expressionExecutor, er
153
45
return nil , err
154
46
}
155
47
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 )
156
62
}, nil
157
63
}
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