/
rule.go
executable file
·243 lines (222 loc) · 5.53 KB
/
rule.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package rule
import (
"errors"
"fmt"
"go/ast"
"go/parser"
"go/token"
"reflect"
"strconv"
"strings"
)
// 错误定义
var (
ErrRuleEmpty = errors.New("rule is empty")
ErrUnsupportToken = errors.New("unsupport token")
ErrUnsupportExpr = errors.New("unsupport expr")
ErrUnsupportParam = errors.New("unsupport param")
ErrNotNumber = errors.New("not a number")
ErrIndexNotNumber = errors.New("index not a number")
ErrNotBool = errors.New("not boolean")
ErrKeyNotFound = errors.New("map key not found")
fns = map[string]fn{
"contains": func(args []interface{}) (interface{}, error) {
fmt.Println("contains print: ", args)
return nil, nil
},
}
)
type fn = func(args []interface{}) (interface{}, error)
type Rule struct {
expr ast.Expr
}
func (r *Rule) SetExpr(expr string) error {
if len(expr) == 0 {
return ErrRuleEmpty
}
if exp, err := parser.ParseExpr(expr); err != nil {
return err
} else {
r.expr = exp
}
return nil
}
func (r *Rule) Bool(database map[string]interface{}) (bool, error) {
if r.expr != nil {
b, err := r.Eval(database)
if err != nil {
return false, err
}
if r, ok := b.(bool); ok {
return r, nil
}
}
return false, errors.New("expr is nil")
}
func (r *Rule) Int(database map[string]interface{}) (int64, error) {
if r.expr != nil {
b, err := r.Eval(database)
if err != nil {
return 0, err
}
switch b := b.(type) {
case int64:
return b, nil
case float64:
return int64(b), nil
}
}
return 0, errors.New("expr is nil")
}
func (r *Rule) Float(database map[string]interface{}) (float64, error) {
if r.expr != nil {
b, err := r.Eval(database)
if err != nil {
return 0, err
}
switch b := b.(type) {
case int64:
return float64(b), nil
case float64:
return b, nil
}
}
return 0, errors.New("expr is nil")
}
func (r *Rule) Eval(datasource map[string]interface{}) (interface{}, error) {
switch t := r.expr.(type) {
case *ast.UnaryExpr: // 一元表达式
r.expr = t.X
operand, err := r.Eval(datasource)
if err != nil {
return nil, err
}
oprd := reflect.ValueOf(operand)
switch t.Op {
case token.NOT: // !
if oprd.Kind() != reflect.Bool {
return false, ErrNotBool
}
return !oprd.Bool(), nil
case token.SUB: // -
if x, err := number(oprd); err == nil {
return (-1.0) * x, nil
}
return 0.0, ErrNotNumber
}
case *ast.BinaryExpr: // 二元表达式
r.expr = t.X
x, err := r.Eval(datasource)
if err != nil {
return nil, err
}
r.expr = t.Y
y, err := r.Eval(datasource)
if err != nil {
return nil, err
}
return operate(x, y, t.Op)
case *ast.Ident: // 标志符(已定义变量或常量(bool))
return evalIdent(t.Name, datasource)
case *ast.BasicLit: // 基本类型文字(当作字符串存储)
switch t.Kind {
case token.STRING:
return strings.Trim(t.Value, "\""), nil
case token.INT:
return strconv.ParseInt(t.Value, 10, 64)
case token.FLOAT:
return strconv.ParseFloat(t.Value, 64)
default:
return nil, ErrUnsupportParam
}
case *ast.ParenExpr: // 圆括号内表达式
r.expr = t.X
return r.Eval(datasource)
case *ast.SelectorExpr: // 属性或方法选择表达式
r.expr = t.X
v, err := r.Eval(datasource)
if err != nil {
return nil, err
}
return evalIdent(t.Sel.Name, v.(map[string]interface{}))
case *ast.IndexExpr: // 中括号内表达式——map或slice索引
r.expr = t.X
data, err := r.Eval(datasource)
if err != nil {
return nil, err
}
r.expr = t.Index
idx, err := r.Eval(datasource)
if err != nil {
return nil, err
}
switch data := data.(type) {
case map[string]interface{}:
if idx, isString := idx.(string); isString {
return data[idx], nil
} else {
return nil, fmt.Errorf("map here index must be string")
}
case []interface{}:
switch idx := idx.(type) {
case int:
return data[int64(idx)], nil
case int64:
return data[idx], nil
default:
return nil, fmt.Errorf("slice index index must be number")
}
default:
return nil, fmt.Errorf("IndexExpr: unsupport data type")
}
case *ast.CallExpr: // 方法调用表达式
// r.expr = t.Fun
// f, err := r.Eval(fns)
// if err != nil {
// return nil, err
// }
// switch f := f.(type) {
// case func(args []interface{}) (interface{}, error):
// if params, err := evalArg(t.Args, datasource); err != nil {
// return nil, err
// } else {
// return f(params)
// }
// }
if params, err := evalArg(t.Args, datasource); err != nil {
return nil, err
} else {
return fns[t.Fun.(*ast.Ident).Name](params)
}
}
return nil, ErrUnsupportExpr
}
func evalArg(args []ast.Expr, datasource map[string]interface{}) ([]interface{}, error) {
var result []interface{}
for _, arg := range args {
switch arg := arg.(type) {
case *ast.BasicLit:
result = append(result, arg.Value)
case *ast.Ident:
if val, err := evalIdent(arg.Name, datasource); err != nil {
return nil, err
} else {
result = append(result, val)
}
}
}
return result, nil
}
func evalIdent(key string, datasource map[string]interface{}) (interface{}, error) {
// while bool type is Ident
if key == "true" {
return true, nil
} else if key == "false" {
return false, nil
}
if value, ok := datasource[key]; ok {
return value, nil
} else {
return nil, ErrKeyNotFound
}
}