-
Notifications
You must be signed in to change notification settings - Fork 4
/
parser.go
195 lines (180 loc) · 4.71 KB
/
parser.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
package gorules
import (
"errors"
"go/ast"
"go/token"
"reflect"
"strconv"
"strings"
)
// 错误定义
var (
ErrRuleEmpty = errors.New("rule is empty")
ErrTypeNotStruct = errors.New("value must struct or struct pointer")
ErrNotFoundTag = errors.New("not found tag")
ErrUnsupportToken = errors.New("unsupport token")
ErrUnsupportExpr = errors.New("unsupport expr")
ErrNotNumber = errors.New("not a number")
ErrNotBool = errors.New("not boolean")
)
// Bool 规则rule结果的布尔值,rule的参数基于base的json tag
func Bool(base interface{}, rule string) (bool, error) {
r, err := NewRule(rule)
if err != nil {
return false, err
}
return r.Bool(base)
}
// Int 规则rule的结果如果是数值型,转换为int64,否则报错
func Int(base interface{}, rule string) (int64, error) {
r, err := NewRule(rule)
if err != nil {
return 0, err
}
return r.Int(base)
}
// Float 返回规则rule结果,如果数值型返回float64,否则报错
func Float(base interface{}, rule string) (float64, error) {
r, err := NewRule(rule)
if err != nil {
return 0, err
}
return r.Float(base)
}
// 拆解rule,支持的计算类型+-*/, && ||,其他报错
// 支持二元操作
// 从struct解析找到json Tag, 若嵌套struct则用“.”连接
func getValueByTag(x reflect.Value, tag string) (interface{}, error) {
if x.Kind() == reflect.Ptr {
x = x.Elem()
}
if x.Kind() != reflect.Struct {
return x, ErrTypeNotStruct
}
t := x.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
js := getTagName(field.Tag)
if js == tag {
return x.Field(i).Interface(), nil
}
}
return nil, ErrNotFoundTag
}
func getSliceValue(x reflect.Value, idx int) (interface{}, error) {
if x.Kind() != reflect.Slice && x.Kind() != reflect.Array {
return nil, errors.New("only slice or array can get value by index")
}
if idx > x.Len()-1 {
return nil, errors.New("slice index out of range")
}
return x.Index(idx).Interface(), nil
}
func getValue(base reflect.Value, expr ast.Expr) (interface{}, error) {
nullValue := reflect.Value{}
switch t := expr.(type) {
case *ast.BinaryExpr:
x, err := getValue(base, t.X)
if err != nil {
return nullValue, err
}
y, err := getValue(base, t.Y)
if err != nil {
return nullValue, err
}
return operate(x, y, t.Op)
case *ast.Ident:
return getValueByTag(base, t.Name)
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 nullValue, errors.New("unsupport param")
}
case *ast.ParenExpr:
return getValue(base, t.X)
case *ast.SelectorExpr:
v, err := getValue(base, t.X)
if err != nil {
return nullValue, err
}
return getValueByTag(reflect.ValueOf(v), t.Sel.Name)
case *ast.IndexExpr:
idx, err := getValue(base, t.Index)
if err != nil {
return nullValue, err
}
f, ok := idx.(float64)
if !ok {
if i, ok := idx.(int64); ok {
f = float64(i)
} else {
return nullValue, errors.New("index must be int or float")
}
}
v, err := getValue(base, t.X)
if err != nil {
return nullValue, err
}
return getSliceValue(reflect.ValueOf(v), int(f))
case *ast.CallExpr:
if fexp, ok := t.Fun.(*ast.Ident); ok {
if strings.ToUpper(fexp.Name) == "IN" {
if len(t.Args) == 2 {
return isIn(base, t.Args[0], t.Args[1])
}
return nullValue, errors.New("function IN only support tow params")
}
return nullValue, errors.New("unsupport function: " + fexp.Name)
}
return nullValue, errors.New("unknow function")
default:
return nullValue, ErrUnsupportExpr
}
}
func isIn(base reflect.Value, slice ast.Expr, key ast.Expr) (bool, error) {
sv, err := getValue(base, slice)
if err != nil {
return false, err
}
kv, err := getValue(base, key)
if err != nil {
return false, err
}
svv := reflect.ValueOf(sv)
if svv.Kind() != reflect.Slice && svv.Kind() != reflect.Array {
return false, errors.New("function IN first param must be slice or array")
}
if svv.Len() == 0 {
return false, nil
}
kvv := reflect.ValueOf(kv)
switch svv.Index(0).Kind() {
case reflect.String:
for i := 0; i < svv.Len(); i++ {
if svv.Index(i).String() == kvv.String() {
return true, nil
}
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
for i := 0; i < svv.Len(); i++ {
if svv.Index(i).Int() == kvv.Int() {
return true, nil
}
}
case reflect.Float32, reflect.Float64:
for i := 0; i < svv.Len(); i++ {
if svv.Index(i).Float() == kvv.Float() {
return true, nil
}
}
default:
return false, errors.New("function IN only support: string int float")
}
return false, nil
}