-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.go
169 lines (144 loc) · 4.21 KB
/
api.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
package rule_engine
import (
"fmt"
"github.com/shopspring/decimal"
)
type Praser struct {
operator *TokenOperator
}
// if need use decimal to handle float, set useDecimal: true
// if don't require decimal, can set useDeicimal: false, will use float in calculate.
// if not spefic the type in params, Praser will try to prase the type from value.
// if spefic the type in params, Praser will use this type and analyze the value.
func GetNewPraser(params []*Param, useDecimal bool) (*Praser, error) {
oper := &TokenOperator{
decimalMode: useDecimal,
varMap: make(map[string]*TokenNode),
}
for _, param := range params {
if param == nil {
continue
}
node, err := parseParam(useDecimal, param)
if err != nil {
return nil, err
}
oper.varMap[param.Name] = node
}
return &Praser{operator: oper}, nil
}
func (p *Praser) Parse(str string) (*TokenNode, error) {
lex := NewRuleEngineLex(str, p.operator)
if res := ruleEngineParse(lex); res == Success {
return lex.resNode, nil
}
return nil, lex.err
}
func (p *Praser) CheckValue(node *TokenNode, v interface{}) bool {
param := &Param{Value: v}
vnode, err := parseParam(p.operator.decimalMode, param)
if err != nil {
return false
}
return node.Compare(vnode)
}
type Param struct {
Name string // value name
Type ValueType // value type
Value interface{} // value
}
func GetParam(key string, value interface{}) *Param {
return &Param{Name: key, Value: value}
}
func GetParamWithType(key string, valueType ValueType, value interface{}) *Param {
return &Param{Name: key, Type: valueType, Value: value}
}
type TokenNode struct {
ValueType ValueType // result type, can see ValueType
Value interface{} // result value
}
func GetTokenNode(valueType ValueType, value interface{}) *TokenNode {
return &TokenNode{ValueType: valueType, Value: value}
}
func (t *TokenNode) GetValue() interface{} {
return t.Value
}
func (t *TokenNode) GetInt() int64 {
switch t.ValueType {
case ValueTypeInteger:
return t.Value.(int64)
case ValueTypeFloat:
return int64(t.Value.(float64))
case ValueTypeDecimal:
return t.GetDecimal().IntPart()
}
panic(fmt.Sprintf("invalid type change, from %v to int, value: %v",
valueTypeNameDict[t.ValueType], t.Value))
}
func (t *TokenNode) GetBool() bool {
switch t.ValueType {
case ValueTypeBool:
return t.Value.(bool)
}
panic(fmt.Sprintf("invalid type change, from %v to bool, value: %v",
valueTypeNameDict[t.ValueType], t.Value))
}
func (t *TokenNode) GetFloat() float64 {
switch t.ValueType {
case ValueTypeInteger:
return float64(t.GetInt())
case ValueTypeFloat:
return t.Value.(float64)
case ValueTypeDecimal:
return t.GetDecimal().InexactFloat64()
}
panic(fmt.Sprintf("invalid type change, from %v to bool, value: %v",
valueTypeNameDict[t.ValueType], t.Value))
}
func (t *TokenNode) GetDecimal() decimal.Decimal {
switch t.ValueType {
case ValueTypeInteger:
return decimal.NewFromInt(t.Value.(int64))
case ValueTypeFloat:
return decimal.NewFromFloat(t.Value.(float64))
case ValueTypeDecimal:
return t.Value.(decimal.Decimal)
}
panic(fmt.Sprintf("invalid type change, from %v to bool, value: %v",
valueTypeNameDict[t.ValueType], t.Value))
}
func (t *TokenNode) GetString() string {
switch t.ValueType {
case ValueTypeString:
return t.Value.(string)
default:
return fmt.Sprintf("%v", t.Value)
}
}
func (x *TokenNode) Compare(y *TokenNode) bool {
if x.ValueType == ValueTypeNone || y.ValueType == ValueTypeNone {
return false
}
if x.ValueType == ValueTypeBool || y.ValueType == ValueTypeBool {
if x.ValueType != ValueTypeBool || y.ValueType != ValueTypeBool {
return false
}
return x.GetBool() == y.GetBool()
}
if x.ValueType == ValueTypeString || y.ValueType == ValueTypeString {
if x.ValueType != ValueTypeString || y.ValueType != ValueTypeString {
return false
}
return x.GetString() == y.GetString()
}
if x.ValueType == ValueTypeDecimal || y.ValueType == ValueTypeDecimal {
return x.GetDecimal().Equal(y.GetDecimal())
}
if x.ValueType == ValueTypeFloat || y.ValueType == ValueTypeFloat {
return isFloatEqual(x.GetFloat(), y.GetFloat())
}
if x.ValueType == ValueTypeInteger && y.ValueType == ValueTypeInteger {
return x.GetInt() == y.GetInt()
}
return false
}