-
Notifications
You must be signed in to change notification settings - Fork 0
/
special.go
57 lines (46 loc) · 1.34 KB
/
special.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
package goscm
import "errors"
// Special comes in two flavours - expanding and non-expanding. Expanding
// Specials are used to provide TCO, but must be expanded before they can
// be Applied in other contexts. Other Special forms can jsut be applied
// straight away.
// If you want to make a TCOExpand-type special form, the function you give
// should actually return something else to Eval.
type Special struct {
Function func (*Pair, *Environ) (SCMT, error)
TCOExpand bool
}
func (sp *Special) Eval(*Environ) (SCMT, error) {
return sp, nil
}
func (*Special) String() string {
return "#<special form>"
}
func (sp *Special) Apply(args *Pair, env *Environ) (SCMT, error) {
// Expanding functions
if sp.TCOExpand {
expanded, err := sp.Expand(args, env)
if err != nil { return SCM_Nil, err }
return expanded.Eval(env)
}
// Non-expanding functions just get called
return sp.Function(args, env)
}
func (sp *Special) Expand(args *Pair, env *Environ) (SCMT, error) {
if sp.TCOExpand {
return sp.Function(args, env)
}
return SCM_Nil, errors.New("Attempt to expand non-expanding special form")
}
func NewSpecial(f func (*Pair, *Environ) (SCMT, error)) *Special {
return &Special {
Function: f,
TCOExpand: false,
}
}
func NewSpecialTCO(f func (*Pair, *Environ) (SCMT, error)) *Special {
return &Special {
Function: f,
TCOExpand: true,
}
}