@@ -3,56 +3,123 @@ package main
3
3
import (
4
4
"fmt"
5
5
"math/rand"
6
+ "reflect"
6
7
"runtime/debug"
7
8
8
9
"github.com/antonmedv/expr"
9
10
"github.com/antonmedv/expr/ast"
10
11
"github.com/antonmedv/expr/builtin"
11
12
)
12
13
13
- var env = map [string ]interface {}{
14
- "a" : 1 ,
15
- "b" : 2 ,
16
- "f" : 0.5 ,
17
- "ok" : true ,
18
- "s" : "abc" ,
19
- "arr" : []int {1 , 2 , 3 },
20
- "obj" : map [string ]interface {}{
21
- "a" : 1 ,
22
- "b" : 2 ,
23
- "obj" : map [string ]interface {}{
24
- "a" : 1 ,
25
- "b" : 2 ,
26
- "obj" : map [string ]int {
27
- "a" : 1 ,
28
- "b" : 2 ,
29
- },
30
- },
31
- "fn" : func (a int ) int { return a + 1 },
32
- "head" : func (xs ... interface {}) interface {} { return xs [0 ] },
14
+ var env = map [string ]any {
15
+ "ok" : true ,
16
+ "f64" : .5 ,
17
+ "f32" : float32 (.5 ),
18
+ "i" : 1 ,
19
+ "i64" : int64 (1 ),
20
+ "i32" : int32 (1 ),
21
+ "array" : []int {1 , 2 , 3 , 4 , 5 },
22
+ "list" : []Foo {{"bar" }, {"baz" }},
23
+ "foo" : Foo {"bar" },
24
+ "add" : func (a , b int ) int { return a + b },
25
+ "div" : func (a , b int ) int { return a / b },
26
+ "half" : func (a float64 ) float64 { return a / 2 },
27
+ "score" : func (a int , x ... int ) int {
28
+ s := a
29
+ for _ , n := range x {
30
+ s += n
31
+ }
32
+ return s
33
33
},
34
- "add" : func (a , b int ) int { return a + b },
35
- "div" : func (a , b int ) int { return a / b },
34
+ "greet" : func (name string ) string { return "Hello, " + name },
35
+ }
36
+
37
+ type Foo struct {
38
+ Bar string
39
+ }
40
+
41
+ func (f Foo ) String () string {
42
+ return "foo"
43
+ }
44
+
45
+ func (f Foo ) Qux (s string ) string {
46
+ return f .Bar + s
36
47
}
37
48
38
- var names []string
49
+ var (
50
+ dict []string
51
+ predicates []string
52
+ builtins []string
53
+ operators = []string {
54
+ "or" ,
55
+ "||" ,
56
+ "and" ,
57
+ "&&" ,
58
+ "==" ,
59
+ "!=" ,
60
+ "<" ,
61
+ ">" ,
62
+ ">=" ,
63
+ "<=" ,
64
+ ".." ,
65
+ "+" ,
66
+ "-" ,
67
+ "*" ,
68
+ "/" ,
69
+ "%" ,
70
+ "**" ,
71
+ "^" ,
72
+ "in" ,
73
+ "matches" ,
74
+ "contains" ,
75
+ "startsWith" ,
76
+ "endsWith" ,
77
+ "not in" ,
78
+ "not matches" ,
79
+ "not contains" ,
80
+ "not startsWith" ,
81
+ "not endsWith" ,
82
+ }
83
+ )
39
84
40
85
func init () {
41
- for name := range env {
42
- names = append (names , name )
86
+ for name , x := range env {
87
+ dict = append (dict , name )
88
+ v := reflect .ValueOf (x )
89
+ if v .Kind () == reflect .Struct {
90
+ for i := 0 ; i < v .NumField (); i ++ {
91
+ dict = append (dict , v .Type ().Field (i ).Name )
92
+ }
93
+ for i := 0 ; i < v .NumMethod (); i ++ {
94
+ dict = append (dict , v .Type ().Method (i ).Name )
95
+ }
96
+ }
97
+ if v .Kind () == reflect .Map {
98
+ for _ , key := range v .MapKeys () {
99
+ dict = append (dict , fmt .Sprintf ("%v" , key .Interface ()))
100
+ }
101
+ }
102
+ }
103
+ for _ , b := range builtin .Builtins {
104
+ if b .Predicate {
105
+ predicates = append (predicates , b .Name )
106
+ } else {
107
+ builtins = append (builtins , b .Name )
108
+ }
43
109
}
44
110
}
45
111
46
112
func main () {
47
113
var code string
48
114
defer func () {
49
115
if r := recover (); r != nil {
50
- fmt .Printf ("==========================\n %s\n ==========================\n " , code )
116
+ fmt .Printf ("==========================\n %s\n ==========================\n %s \n ========================== \n " , code , r )
51
117
debug .PrintStack ()
52
118
}
53
119
}()
54
120
55
- corpus := map [string ]struct {}{}
121
+ var corpus = map [string ]struct {}{}
122
+
56
123
for {
57
124
code = node (weightedRandomInt ([]intWeight {
58
125
{3 , 100 },
@@ -91,6 +158,7 @@ func node(depth int) ast.Node {
91
158
{stringNode , 1 },
92
159
{booleanNode , 1 },
93
160
{identifierNode , 10 },
161
+ {pointerNode , 10 },
94
162
})(depth - 1 )
95
163
}
96
164
return weightedRandom ([]fnWeight {
@@ -109,136 +177,89 @@ func node(depth int) ast.Node {
109
177
})(depth - 1 )
110
178
}
111
179
112
- func nilNode (depth int ) ast.Node {
180
+ func nilNode (_ int ) ast.Node {
113
181
return & ast.NilNode {}
114
182
}
115
183
116
- func floatNode (depth int ) ast.Node {
117
- cases := []float64 {
118
- 0.0 ,
119
- 0.5 ,
120
- }
184
+ func floatNode (_ int ) ast.Node {
121
185
return & ast.FloatNode {
122
- Value : cases [ rand . Intn ( len ( cases ))] ,
186
+ Value : .5 ,
123
187
}
124
188
}
125
189
126
- func integerNode (depth int ) ast.Node {
190
+ func integerNode (_ int ) ast.Node {
127
191
return & ast.IntegerNode {
128
- Value : rand . Intn ( 3 ) ,
192
+ Value : 1 ,
129
193
}
130
194
}
131
195
132
- func stringNode (depth int ) ast.Node {
133
- corpus := []string {
134
- "a" , "b" , "c" ,
196
+ func stringNode (_ int ) ast.Node {
197
+ words := []string {
198
+ "foo" ,
199
+ "bar" ,
135
200
}
136
201
return & ast.StringNode {
137
- Value : corpus [rand .Intn (len (corpus ))],
202
+ Value : words [rand .Intn (len (words ))],
138
203
}
139
204
}
140
205
141
- func booleanNode (depth int ) ast.Node {
206
+ func booleanNode (_ int ) ast.Node {
142
207
return & ast.BoolNode {
143
208
Value : maybe (),
144
209
}
145
210
}
146
211
147
- func identifierNode (depth int ) ast.Node {
212
+ func identifierNode (_ int ) ast.Node {
148
213
return & ast.IdentifierNode {
149
- Value : names [rand .Intn (len (names ))],
214
+ Value : dict [rand .Intn (len (dict ))],
150
215
}
151
216
}
152
217
153
218
func memberNode (depth int ) ast.Node {
154
- cases := []string {
155
- "a" ,
156
- "b" ,
157
- "obj" ,
158
- }
159
-
160
219
return & ast.MemberNode {
161
220
Node : node (depth - 1 ),
162
221
Property : weightedRandom ([]fnWeight {
163
- {func (_ int ) ast.Node { return & ast.StringNode {Value : cases [rand .Intn (len (cases ))]} }, 5 },
222
+ {func (_ int ) ast.Node { return & ast.StringNode {Value : dict [rand .Intn (len (dict ))]} }, 5 },
164
223
{node , 1 },
165
224
})(depth - 1 ),
166
225
Optional : maybe (),
167
226
}
168
227
}
169
228
170
229
func unaryNode (depth int ) ast.Node {
171
- cases := []string {
172
- "-" ,
173
- "!" ,
174
- "not" ,
175
- }
230
+ cases := []string {"-" , "!" , "not" }
176
231
return & ast.UnaryNode {
177
232
Operator : cases [rand .Intn (len (cases ))],
178
233
Node : node (depth - 1 ),
179
234
}
180
235
}
181
236
182
237
func binaryNode (depth int ) ast.Node {
183
- cases := []string {
184
- "or" ,
185
- "||" ,
186
- "and" ,
187
- "&&" ,
188
- "==" ,
189
- "!=" ,
190
- "<" ,
191
- ">" ,
192
- ">=" ,
193
- "<=" ,
194
- "in" ,
195
- "matches" ,
196
- "contains" ,
197
- "startsWith" ,
198
- "endsWith" ,
199
- ".." ,
200
- "+" ,
201
- "-" ,
202
- "*" ,
203
- "/" ,
204
- "%" ,
205
- "**" ,
206
- "^" ,
207
- }
208
238
return & ast.BinaryNode {
209
- Operator : cases [rand .Intn (len (cases ))],
239
+ Operator : operators [rand .Intn (len (operators ))],
210
240
Left : node (depth - 1 ),
211
241
Right : node (depth - 1 ),
212
242
}
213
243
}
214
244
215
245
func methodNode (depth int ) ast.Node {
216
- cases := []string {
217
- "fn" ,
218
- "head" ,
219
- }
220
-
221
246
return & ast.MemberNode {
222
247
Node : node (depth - 1 ),
223
- Property : & ast.StringNode {Value : cases [rand .Intn (len (cases ))]},
248
+ Property : & ast.StringNode {Value : dict [rand .Intn (len (dict ))]},
224
249
Optional : maybe (),
225
250
}
226
251
}
227
252
228
- func funcNode (depth int ) ast.Node {
229
- cases := []string {
230
- "add" ,
231
- "div" ,
232
- }
233
-
253
+ func funcNode (_ int ) ast.Node {
234
254
return & ast.IdentifierNode {
235
- Value : cases [rand .Intn (len (cases ))],
255
+ Value : dict [rand .Intn (len (dict ))],
236
256
}
237
257
}
238
258
239
259
func callNode (depth int ) ast.Node {
240
260
var args []ast.Node
241
261
max := weightedRandomInt ([]intWeight {
262
+ {0 , 100 },
242
263
{1 , 100 },
243
264
{2 , 50 },
244
265
{3 , 25 },
@@ -262,36 +283,29 @@ func builtinNode(depth int) ast.Node {
262
283
max := weightedRandomInt ([]intWeight {
263
284
{1 , 100 },
264
285
{2 , 50 },
265
- {3 , 25 },
286
+ {3 , 50 },
266
287
{4 , 10 },
267
- {5 , 5 },
268
288
})
269
289
for i := 0 ; i < max ; i ++ {
270
290
args = append (args , node (depth - 1 ))
271
291
}
272
292
return & ast.BuiltinNode {
273
- Name : builtin . Names [rand .Intn (len (builtin . Names ))],
293
+ Name : builtins [rand .Intn (len (builtins ))],
274
294
Arguments : args ,
275
295
}
276
296
}
277
297
278
298
func predicateNode (depth int ) ast.Node {
279
- cases := []string {
280
- "all" ,
281
- "none" ,
282
- "any" ,
283
- "one" ,
284
- "filter" ,
285
- "map" ,
286
- "count" ,
287
- }
288
299
return & ast.BuiltinNode {
289
- Name : cases [rand .Intn (len (cases ))],
290
- Arguments : []ast.Node {node (depth - 1 ), node (depth - 1 )},
300
+ Name : predicates [rand .Intn (len (predicates ))],
301
+ Arguments : []ast.Node {
302
+ node (depth - 1 ),
303
+ node (depth - 1 ),
304
+ },
291
305
}
292
306
}
293
307
294
- func pointerNode (depth int ) ast.Node {
308
+ func pointerNode (_ int ) ast.Node {
295
309
return & ast.PointerNode {}
296
310
}
297
311
@@ -301,8 +315,6 @@ func arrayNode(depth int) ast.Node {
301
315
{1 , 100 },
302
316
{2 , 50 },
303
317
{3 , 25 },
304
- {4 , 10 },
305
- {5 , 5 },
306
318
})
307
319
for i := 0 ; i < max ; i ++ {
308
320
items = append (items , node (depth - 1 ))
@@ -318,8 +330,6 @@ func mapNode(depth int) ast.Node {
318
330
{1 , 100 },
319
331
{2 , 50 },
320
332
{3 , 25 },
321
- {4 , 10 },
322
- {5 , 5 },
323
333
})
324
334
for i := 0 ; i < max ; i ++ {
325
335
items = append (items , & ast.PairNode {
0 commit comments