-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathdot.go
108 lines (93 loc) · 2.5 KB
/
dot.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
package gisp
import (
"fmt"
"reflect"
p "github.com/Dwarfartisan/goparsec"
)
// NotStructError 定义struct查找错误
type NotStructError struct {
data interface{}
}
func (err NotStructError) Error() string {
return fmt.Sprintf("%v not a struct, can't be dot", err.data)
}
// NameInvalid 定义命名错误
type NameInvalid struct {
Name string
}
func (err NameInvalid) Error() string {
return fmt.Sprintf("name %s is invalid", err.Name)
}
// Dot 结构实现 Dot 表达式
type Dot struct {
obj interface{}
expr Atom
}
// Eval 方法实现 dot 的解释求值行为
func (dot Dot) Eval(env Env) (interface{}, error) {
o, err := Eval(env, dot.obj)
if err != nil {
return nil, err
}
switch obj := o.(type) {
case Toolkit:
return dot.evalToolbox(env, obj, dot.expr)
case reflect.Value:
if obj.IsValid() {
inter := obj.Interface()
switch data := inter.(type) {
case Toolbox:
return dot.evalToolbox(env, data, dot.expr)
}
}
return dot.evalValue(env, obj, dot.expr)
default:
val := reflect.ValueOf(obj)
return dot.evalValue(env, val, dot.expr)
}
}
func (dot Dot) evalToolbox(env Env, obj Toolbox, name Atom) (interface{}, error) {
if expr, ok := obj.Lookup(name.Name); ok {
return expr, nil
}
return nil, fmt.Errorf("Export expr %v from tookit %v but not found in dot %v.%v.",
name, obj, obj, name)
}
func (dot Dot) evalValue(env Env, val reflect.Value, name Atom) (interface{}, error) {
if val.Kind() == reflect.Struct {
if field := val.FieldByName(name.Name); field.IsValid() {
return Value(field), nil
}
}
if method := val.MethodByName(name.Name); method.IsValid() {
return method, nil
}
return nil, NameInvalid{name.Name}
}
// DotParser 定义了从文本中解析出 Dot 表达式的 Parser
func DotParser(st p.ParseState) (interface{}, error) {
name, err := p.Bind_(p.Rune('.'), atomNameParser)(st)
if err != nil {
return nil, err
}
return AA(name.(string)), nil
}
// DotExpr 表达式实现 Dot 的表达式求值逻辑
type DotExpr struct {
Name string
}
// Task 方法实现 dot 表达式的求值
func (de DotExpr) Task(env Env, args ...interface{}) (Lisp, error) {
if len(args) != 1 {
return nil, ParsexSignErrorf("Dot expression Args Error: except 1 arg but %v", args)
}
return Dot{args[0], AA(de.Name)}, nil
}
// DotExprParser 实现 Dot 表达式的解析构造
func DotExprParser(st p.ParseState) (interface{}, error) {
name, err := p.Bind_(p.Rune('.'), atomNameParser)(st)
if err != nil {
return nil, err
}
return DotExpr{name.(string)}, nil
}