-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfunctions.go
106 lines (91 loc) · 2.66 KB
/
functions.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
package expr
import (
"reflect"
"strings"
"time"
"github.com/EchoUtopia/zerror"
)
type function struct {
name string
iFn interface{}
// the following will be set by register
// if argsNumber is -1, no limit set
argsNumber int
isVariadic bool
fn reflect.Value
returnType reflect.Type
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()
func checkFunction(name string, i interface{}) (reflect.Type, reflect.Value, error) {
v := reflect.ValueOf(i)
t := v.Type()
if t.Kind() != reflect.Func {
return nil, reflect.Value{}, zerror.BadRequest.Errorf(`[%s] is not func`, name)
}
// TODO: support variadic
if t.IsVariadic() {
return nil, reflect.Value{}, zerror.BadRequest.WithMsg(`variadic function not supported`)
}
for i := 0; i < t.NumIn(); i++ {
nik := t.In(i).Kind()
if nik != reflect.Int64 && nik != reflect.Float64 && nik != reflect.Bool && nik != reflect.String {
return nil, reflect.Value{}, zerror.BadRequest.WithMsg(`function variables only support float64, int64, string and bool`)
}
}
if t.NumOut() > 2 {
return nil, reflect.Value{}, zerror.BadRequest.WithMsg(`function returns more than 2 vars`)
} else if t.NumOut() == 2 {
if t.Out(1) != errorType {
return nil, reflect.Value{}, zerror.BadRequest.WithMsg(`function second return var must be error`)
}
} else if t.NumOut() == 1 {
if t.Out(0) == errorType {
return nil, reflect.Value{}, zerror.BadRequest.WithMsg(`func first return var can not be error`)
}
}
returnType := t.Out(0)
returnKind := returnType.Kind()
returnBool := returnKind == reflect.Bool
if !returnBool && returnKind != reflect.Int64 && returnKind != reflect.Float64 && returnKind != reflect.String {
return nil, reflect.Value{}, zerror.BadRequest.WithMsg(`function first return val type must be one of string, int64, float64 and bool`)
}
return returnType, v, nil
}
var builtinFuncs = map[string]interface{}{
`contains`: contains,
`endsWith`: endsWith,
`startsWith`: startsWith,
`length`: length,
`toLower`: toLower,
`toUpper`: toUpper,
`trim`: trim,
`concat`: concat,
`now`: now,
}
func now() string {
return time.Now().Format(time.RFC3339)
}
func contains(s, substr string) bool {
return strings.Contains(s, substr)
}
func endsWith(s, suffix string) bool {
return strings.HasSuffix(s, suffix)
}
func startsWith(s, prefix string) bool {
return strings.HasPrefix(s, prefix)
}
func length(s string) int64 {
return int64(len(s))
}
func toLower(s string) string {
return strings.ToLower(s)
}
func toUpper(s string) string {
return strings.ToUpper(s)
}
func trim(s string) string {
return strings.TrimSpace(s)
}
func concat(sa, sb string) string {
return sa + sb
}