1
1
package gal
2
2
3
+ import (
4
+ "fmt"
5
+ "log/slog"
6
+ "strings"
7
+ )
8
+
3
9
type entryKind int
4
10
11
+ func (ek entryKind ) String () string {
12
+ switch ek {
13
+ case unknownEntryKind :
14
+ return "unknownEntryKind"
15
+ case valueEntryKind :
16
+ return "valueEntryKind"
17
+ case operatorEntryKind :
18
+ return "operatorEntryKind"
19
+ case treeEntryKind :
20
+ return "treeEntryKind"
21
+ case functionEntryKind :
22
+ return "functionEntryKind"
23
+ case variableEntryKind :
24
+ return "variableEntryKind"
25
+ default :
26
+ return fmt .Sprintf ("unknown:%d" , ek )
27
+ }
28
+ }
29
+
5
30
const (
6
31
unknownEntryKind entryKind = iota
7
32
valueEntryKind
@@ -90,7 +115,7 @@ func WithFunctions(funcs Functions) treeOption {
90
115
// It accepts optional functional parameters to supply user-defined
91
116
// entities such as functions and variables.
92
117
func (tree Tree ) Eval (opts ... treeOption ) Value {
93
- //config
118
+ // config
94
119
cfg := & treeConfig {}
95
120
96
121
for _ , o := range opts {
@@ -141,22 +166,27 @@ func (tree Tree) Split() []Tree {
141
166
// For instance, a tree representing the expression '2 + 5 * 4 / 2' with an operator precedence
142
167
// of 'multiplicativeOperators' would read the Tree left to right and return a new Tree that
143
168
// represents: '2 + 10' where 10 was calculated (and reduced) from 5 * 4 = 20 / 2 = 10.
169
+ //
170
+ // nolint: gocognit,gocyclo,cyclop
144
171
func (tree Tree ) Calc (isOperatorInPrecedenceGroup func (Operator ) bool , cfg * treeConfig ) Tree {
145
172
var outTree Tree
146
173
147
174
var val entry
148
- var op Operator = invalidOperator
175
+ var op Operator = invalidOperator //nolint: stylecheck
149
176
150
177
for i := 0 ; i < tree .TrunkLen (); i ++ {
151
178
e := tree [i ]
179
+ slog .Debug ("Tree.Calc: entry in Tree" , "i" , i , "kind" , e .kind ().String ())
152
180
if e == nil {
181
+ slog .Debug ("Tree.Calc: nil entry in Tree" )
153
182
return Tree {
154
183
NewUndefinedWithReasonf ("syntax error: nil value at tree entry #%d - tree: %+v" , i , tree ),
155
184
}
156
185
}
157
186
158
187
switch e .kind () {
159
188
case valueEntryKind :
189
+ slog .Debug ("Tree.Calc: valueEntryKind" , "i" , i , "Value" , e .(Value ).String ())
160
190
if val == nil && op == invalidOperator {
161
191
val = e
162
192
continue
@@ -168,9 +198,12 @@ func (tree Tree) Calc(isOperatorInPrecedenceGroup func(Operator) bool, cfg *tree
168
198
}
169
199
}
170
200
201
+ slog .Debug ("Tree.Calc: valueEntryKind - calculate" , "i" , i , "val" , val .(Value ).String (), "op" , op .String (), "e" , e .(Value ).String ())
171
202
val = calculate (val .(Value ), op , e .(Value ))
203
+ slog .Debug ("Tree.Calc: valueEntryKind - calculate" , "i" , i , "result" , val .(Value ).String ())
172
204
173
205
case treeEntryKind :
206
+ slog .Debug ("Tree.Calc: treeEntryKind" , "i" , i )
174
207
if val == nil && op != invalidOperator {
175
208
return Tree {
176
209
NewUndefinedWithReasonf ("syntax error: missing left hand side value for operator '%s'" , op .String ()),
@@ -184,9 +217,11 @@ func (tree Tree) Calc(isOperatorInPrecedenceGroup func(Operator) bool, cfg *tree
184
217
}
185
218
186
219
val = calculate (val .(Value ), op , rhsVal )
220
+ slog .Debug ("Tree.Calc: treeEntryKind - calculate" , "i" , i , "val" , val .(Value ).String (), "op" , op .String (), "rhsVal" , rhsVal .String (), "result" , val .(Value ).String ())
187
221
188
222
case operatorEntryKind :
189
- op = e .(Operator )
223
+ slog .Debug ("Tree.Calc: operatorEntryKind" , "i" , i , "Value" , e .(Operator ).String ())
224
+ op = e .(Operator ) //nolint: errcheck
190
225
if isOperatorInPrecedenceGroup (op ) {
191
226
// same operator precedence: keep operating linearly, do not build a tree
192
227
continue
@@ -199,7 +234,8 @@ func (tree Tree) Calc(isOperatorInPrecedenceGroup func(Operator) bool, cfg *tree
199
234
op = invalidOperator
200
235
201
236
case functionEntryKind :
202
- f := e .(Function )
237
+ slog .Debug ("Tree.Calc: functionEntryKind" , "i" , i , "name" , e .(Function ).Name )
238
+ f := e .(Function ) //nolint: errcheck
203
239
if f .BodyFn == nil {
204
240
f .BodyFn = cfg .functions .Function (f .Name )
205
241
}
@@ -210,22 +246,26 @@ func (tree Tree) Calc(isOperatorInPrecedenceGroup func(Operator) bool, cfg *tree
210
246
}
211
247
212
248
val = calculate (val .(Value ), op , rhsVal )
249
+ slog .Debug ("Tree.Calc: functionEntryKind - calculate" , "i" , i , "val" , val .(Value ).String (), "op" , op .String (), "rhsVal" , rhsVal .String (), "result" , val .(Value ).String ())
213
250
214
251
case variableEntryKind :
252
+ slog .Debug ("Tree.Calc: variableEntryKind" , "i" , i , "name" , e .(Variable ).Name )
215
253
varName := e .(Variable ).Name
216
254
rhsVal , ok := cfg .Variable (varName )
217
255
if ! ok {
218
256
return Tree {
219
257
NewUndefinedWithReasonf ("syntax error: unknown variable name: '%s'" , varName ),
220
258
}
221
259
}
260
+ slog .Debug ("Tree.Calc: variableEntryKind" , "i" , i , "value" , rhsVal .String ())
222
261
223
262
if val == nil {
224
263
val = rhsVal
225
264
continue
226
265
}
227
266
228
267
val = calculate (val .(Value ), op , rhsVal )
268
+ slog .Debug ("Tree.Calc: variableEntryKind - calculate" , "i" , i , "val" , val .(Value ).String (), "op" , op .String (), "rhsVal" , rhsVal .String (), "result" , val .(Value ).String ())
229
269
230
270
case unknownEntryKind :
231
271
return Tree {e }
@@ -274,6 +314,32 @@ func (Tree) kind() entryKind {
274
314
return treeEntryKind
275
315
}
276
316
317
+ func (tree Tree ) String (indents ... string ) string {
318
+ indent := strings .Join (indents , "" )
319
+
320
+ res := ""
321
+ for _ , e := range tree {
322
+ switch e .kind () {
323
+ case unknownEntryKind :
324
+ res += fmt .Sprintf (indent + "unknownEntryKind %T\n " , e )
325
+ case valueEntryKind :
326
+ res += fmt .Sprintf (indent + "Value %T %s\n " , e , e .(Value ).String ())
327
+ case operatorEntryKind :
328
+ res += fmt .Sprintf (indent + "Operator %s\n " , e .(Operator ).String ())
329
+ case treeEntryKind :
330
+ res += fmt .Sprintf (indent + "Tree {\n %s}\n " , e .(Tree ).String (" " ))
331
+ case functionEntryKind :
332
+ res += fmt .Sprintf (indent + "Function %s\n " , e .(Function ).Name )
333
+ case variableEntryKind :
334
+ res += fmt .Sprintf (indent + "Variable %s\n " , e .(Variable ).Name )
335
+ default :
336
+ res += fmt .Sprintf (indent + "undefined %T %s\n " , e , e .kind ().String ())
337
+ }
338
+ }
339
+ return res
340
+ }
341
+
342
+ // nolint: gocognit,gocyclo,cyclop
277
343
func calculate (lhs Value , op Operator , rhs Value ) Value {
278
344
var outVal Value
279
345
0 commit comments