-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathaxiom.go
155 lines (150 loc) · 4.07 KB
/
axiom.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
package gisp
import (
"fmt"
"reflect"
px "github.com/Dwarfartisan/goparsec/parsex"
)
// Axiom 是基本的 LISP 公理实现,尽可能贴近原始的 LISP 公理描述,但是部分实现对实际的 golang
// 环境做了妥协
var Axiom = Toolkit{
Meta: map[string]interface{}{
"name": "axiom",
"category": "package",
},
Content: map[string]interface{}{
"quote": LispExpr(func(env Env, args ...interface{}) (Lisp, error) {
if len(args) != 1 {
return nil, fmt.Errorf("Quote Args Error: except only one arg but %v", args)
}
return Q(Q(args[0])), nil
}),
"var": LispExpr(func(env Env, args ...interface{}) (Lisp, error) {
st := px.NewStateInMemory(args)
_, err := px.Binds_(TypeAs(ATOM), px.Either(px.Try(px.Eof),
px.Bind_(px.AnyOne, px.Eof)))(st)
if err != nil {
return nil, err
}
first := args[0].(Atom)
slot := VarSlot(first.Type)
if len(args) == 1 {
err := env.Defvar(first.Name, slot)
return Q(nil), err
}
val, err := Eval(env, args[1])
slot.Set(val)
err = env.Defvar(first.Name, slot)
return Q(val), err
}),
"set": LispExpr(func(env Env, args ...interface{}) (Lisp, error) {
st := px.NewStateInMemory(args)
_, err := px.Binds_(px.Either(px.Try(TypeAs(ATOM)),
TypeAs(QUOTE)), px.AnyOne, px.Eof)(st)
if err != nil {
return nil, err
}
val, err := Eval(env, args[1])
if err != nil {
return nil, err
}
ret, err := set(env, args[0], val)
if err != nil {
return nil, err
}
return Q(ret), err
}),
"equal": TaskExpr(func(env Env, args ...interface{}) (Tasker, error) {
if len(args) != 2 {
return nil, fmt.Errorf("args error: equal need two args but only",
args)
}
return func(env Env) (interface{}, error) {
return reflect.DeepEqual(args[0], args[1]), nil
}, nil
}),
"cond": TaskExpr(func(env Env, args ...interface{}) (Tasker, error) {
cases := args[0].([]interface{})
l := len(args)
var els interface{}
if l > 1 {
els = args[1]
} else {
els = nil
}
for _, b := range cases { // FIXME: need a else
branch := b.([]interface{})
cond := branch[0].(List)
result, err := Eval(env, cond)
if err != nil {
return nil, err
}
if ok := result.(bool); ok {
return func(env Env) (interface{}, error) {
return Eval(env, branch[1])
}, nil
}
}
// else branch
if els != nil {
return func(env Env) (interface{}, error) {
return Eval(env, els)
}, nil
}
return nil, nil
}),
"car": TaskExpr(func(env Env, args ...interface{}) (Tasker, error) {
if lisp, ok := args[0].(List); ok {
return Q(lisp[0]).Eval, nil
}
return nil, ParsexSignErrorf("car args error: excpet a list but %v", args)
}),
"cdr": TaskExpr(func(env Env, args ...interface{}) (Tasker, error) {
if lisp, ok := args[0].(List); ok {
return Q(lisp[1:]).Eval, nil
}
return nil, ParsexSignErrorf("car args error: excpet a list but %v", args)
}),
// atom while true both lisp atom or go value
"atom": LispExpr(func(env Env, args ...interface{}) (Lisp, error) {
arg := args[0]
if l, ok := arg.(List); ok {
return Q(len(l) == 0), nil
}
return Q(true), nil
}),
// 照搬 cons 运算符对于 golang 嵌入没有足够的收益,这里的 concat 是一个 cons 的变形,
// 它总是返回包含所有参数的 List 。
"concat": TaskExpr(func(env Env, args ...interface{}) (Tasker, error) {
return func(env Env) (interface{}, error) {
return Q(List(args)).Eval, nil
}, nil
}),
},
}
func set(env Env, slot, arg interface{}) (interface{}, error) {
switch setter := slot.(type) {
case Atom:
err := env.Setvar(setter.Name, arg)
if err == nil {
return nil, err
}
return arg, nil
case Bracket:
return setter.SetItemBy(env, arg)
case List:
s, err := Eval(env, setter)
if err != nil {
return nil, err
}
return set(env, s, arg)
case Quote:
s, err := Eval(env, setter)
if err != nil {
return nil, err
}
return set(env, s, arg)
default:
return arg, fmt.Errorf("set error: set %v(%v) as %v is invalid",
slot, reflect.TypeOf(slot), arg)
}
}