-
Notifications
You must be signed in to change notification settings - Fork 2
/
env.go
85 lines (76 loc) · 1.67 KB
/
env.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
package main
import (
"fmt"
)
// env stores a local environment, possibly pointing to a caller's environment.
type env struct {
syms map[string]Sexpr
parent *env
}
// mkEnv makes a new Env.
func mkEnv(parent *env) env {
return env{
syms: map[string]Sexpr{},
parent: parent,
}
}
// EnvKeys returns the keys of an environment, including any parents' keys.
func EnvKeys(m *env) []string {
ret := []string{}
for k := range m.syms {
ret = append(ret, k)
}
if m.parent != nil {
ret = append(ret, EnvKeys(m.parent)...)
}
return ret
}
// Lookup returns the value of a symbol in an environment or its parent(s).
func (e *env) Lookup(s string) (Sexpr, bool) {
if v, ok := e.syms[s]; ok {
return v, true
}
if e.parent != nil {
return e.parent.Lookup(s)
}
return nil, false
}
// Set sets the value of a symbol in an environment.
func (e *env) Set(s string, v Sexpr) error {
if s == "t" {
return baseError("cannot bind or set t")
}
e.syms[s] = v
return nil
}
// SetTopLevel sets the value of a symbol in the top-level environment.
func (e *env) SetTopLevel(s string, v Sexpr) error {
if e.parent == nil {
return e.Set(s, v)
}
return e.parent.SetTopLevel(s, v)
}
func (e *env) Update(s string, v Sexpr) error {
if s == "t" {
return baseError("cannot bind or set t")
}
if _, ok := e.syms[s]; ok {
e.syms[s] = v
return nil
}
if e.parent != nil {
return e.parent.Update(s, v)
}
return baseErrorf("%s is not bound in any environment", s)
}
func (e *env) String() string {
ret := ""
for k, v := range e.syms {
ret += fmt.Sprintf("%s=%s\n", k, v)
}
ret += "\n"
if e.parent != nil {
ret += fmt.Sprintf("PARENT: %s\n", e.parent.String())
}
return ret
}