-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenv.scm
206 lines (159 loc) · 5.59 KB
/
env.scm
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
;; Based on the Scheme dynamic type inferencer by Andrew Wright.
;----------------------------------------------------------------------------
; Environment management
;----------------------------------------------------------------------------
;; Environments are lists of pairs, the first component being the key
;; General environment operations:
;;
;; empty-env: Env
;; gen-binding: Key x Value -> Binding
;; binding-key: Binding -> Key
;; binding-value: Binding -> Value
;; binding-show: Binding -> Symbol*
;; extend-env-with-binding: Env x Binding -> Env
;; extend-env-with-env: Env x Env -> Env
;; env-lookup: Key x Env -> (Binding + False)
;; env->list: Env -> Binding*
;; env-show: Env -> Symbol*
;; env-size: Env -> Int
;; Environments stacks are lists of environments, the first element in
;; the list being the current environment. The lookup operation
;; traverses the entire stack until a key is found or the last element
;; in the stack is reached. All other operations apply to the current
;; environment.
;;
;; make-env-stack: Env -> Stack Env
;; extend-env-stack-with-binding: Stack Env x Binding -> Stack Env
;; extend-env-stack-with-env: Stack Env x Env -> Stack Env
;; pop-env-stack: Stack Env -> Stack Env
;; push-env-stack: Env x Stack Env -> Stack Env
;; env-stack-lookup: Key x Env -> (Binding + False)
; bindings
(define (env-binding? x)
(pair? x))
(define gen-binding cons)
; generates a binding, binding a symbol to a value
(define binding-key car)
; returns the key of a binding
(define binding-value cdr)
; returns the value of a binding
(define (key-show key)
; default show procedure for keys
key)
(define (value-show value)
; default show procedure for values
value)
(define (binding-show binding)
; returns a printable representation of a binding
(cons (key-show (binding-key binding))
(cons ': (value-show (binding-value binding)))))
; environments
(define-datatype env env?
(Env (first env-binding?) (rest env?))
(EmptyEnv))
(define empty-env (EmptyEnv))
; returns the empty environment
(define (env-empty? e)
(cases env e
(EmptyEnv () #t)
(Env (first rest) #f)))
(define (extend-env-with-binding e binding)
; extends env with a binding, which hides any other binding in env
; for the same key
; returns the extended environment
(Env binding e))
(define (extend-env-with-env e ext-env)
; extends environment env with environment ext-env
; a binding for a key in ext-env hides any binding in env for
; the same key (see dynamic-lookup)
; returns the extended environment
(cases env ext-env
(EmptyEnv () e)
(Env (first rest)
(Env first (extend-env-with-env e rest)))
))
(define (env-lookup x e)
; returns the first pair in env that matches the key; returns #f
; if no such pair exists
(cases env e
(Env (first rest)
(if (eqv? (binding-key first) x)
first
(env-lookup x rest)))
(EmptyEnv () #f)
))
(define (env->list e)
; converts an environment to a list of bindings
(cases env e
(Env (first rest)
(cons first (env->list rest)))
(EmptyEnv () '())))
(define (env-show e)
; returns a printable list representation of an environment
(cases env e
(Env (first rest)
(cons (binding-show first) (env-show rest)))
(EmptyEnv () '())))
(define (env-size e)
; returns the number of items in the environment
(let recur ((e e) (n 0))
(cases env e
(Env (first rest)
(recur rest (+ n 1)))
(EmptyEnv () n))
))
; stacks of environments
(define-datatype env-stack env-stack?
(EnvStack (first env?) (rest env-stack?))
(EmptyEnvStack))
(define empty-env-stack (EmptyEnvStack))
(define (extend-env-stack-with-binding es binding)
(cases env-stack es
(EnvStack (first rest)
(EnvStack
(extend-env-with-binding first binding)
rest))
(EmptyEnvStack ()
(error 'extend-env-stack-with-binding
"empty environment stack"))
))
(define (extend-env-stack-with-env es env)
(cases env-stack es
(EnvStack (first rest)
(EnvStack
(extend-env-with-env first env)
rest))
(EmptyEnvStack ()
(error 'extend-env-stack-with-env
"empty environment stack"))
))
(define (pop-env-stack es)
(cases env-stack es
(EnvStack (first rest) rest)
(EmptyEnvStack ()
(error 'pop-env-stack
"empty environment stack"))
))
(define (push-env-stack e es)
(if (env? e) (EnvStack e es)
(error 'push-env-stack "invalid environment" e)))
(define (peek-env-stack es)
(cases env-stack es
(EnvStack (first rest) first)
(EmptyEnvStack ()
(error 'peek-env-stack
"empty environment stack"))
))
;; env-stack-lookup: Key x Env -> (Binding + False)
(define (env-stack-lookup x es)
(cases env-stack es
(EnvStack (first rest)
(or (env-lookup x first)
(env-stack-lookup x rest)))
(EmptyEnvStack () #f)))
(define (env-stack-show es)
(cases env-stack es
(EnvStack (first rest)
(cons (env-show first)
(env-stack-show rest)))
(EmptyEnvStack () '())))