-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatch.go
125 lines (103 loc) · 2.07 KB
/
match.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
package match
import (
"errors"
"reflect"
ty "github.com/ghostec/match/types"
)
type Match []Case
type Case struct {
When when
Do interface{}
}
func (m Match) Int(args ...interface{}) int {
res, err := m.Result(args...)
if err != nil {
panic(err)
}
val, ok := res.(int)
if !ok {
panic("not int")
}
return val
}
func (m Match) String(args ...interface{}) string {
res, err := m.Result(args...)
if err != nil {
panic(err)
}
val, ok := res.(string)
if !ok {
panic("not string")
}
return val
}
func (m Match) Slice(args ...interface{}) *ty.Slice {
res, err := m.Result(args...)
if err != nil {
panic(err)
}
val, ok := res.(*ty.Slice)
if !ok {
panic("not slice")
}
return val
}
func (m Match) Result(args ...interface{}) (interface{}, error) {
c := m.match(args)
if c == nil {
return nil, errors.New("not matched")
}
dotype := reflect.TypeOf(c.Do)
if dotype.Kind() != reflect.Func {
return c.Do, nil
}
// from now on, c.Do is a func
dovalue := reflect.ValueOf(c.Do)
input := make([]reflect.Value, dotype.NumIn())
rshift := 0
if dotype.NumIn() > 0 && dotype.In(0) == reflect.TypeOf(Match{}) {
input[rshift] = reflect.ValueOf(m)
rshift += 1
}
for i := range c.Args {
tSlice := reflect.TypeOf(ty.NewSlice(nil))
tAny := reflect.TypeOf(ty.NewAny(nil))
value := interface{}(c.Args[i])
switch dotype.In(i + rshift) {
case tSlice:
if reflect.TypeOf(c.Args[i]) != tSlice {
value = ty.NewSlice(c.Args[i])
}
case tAny:
if reflect.TypeOf(c.Args[i]) != tAny {
value = ty.NewAny(c.Args[i])
}
}
input[rshift+i] = reflect.ValueOf(value)
}
out := dovalue.Call(input)
switch len(out) {
case 1:
return out[0].Interface(), nil
case 2:
return out[0].Interface(), out[1].Interface().(error)
default:
return nil, errors.New("more than 2 outputs")
}
}
func (m Match) match(args []interface{}) *CaseWithArgs {
for i := range m {
ok, cargs := m[i].When.match(args)
if ok {
return &CaseWithArgs{
Case: &m[i],
Args: cargs,
}
}
}
return nil
}
type CaseWithArgs struct {
*Case
Args []interface{}
}