generated from cmsc430/assign06-test
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterp.rkt
197 lines (180 loc) · 5.63 KB
/
interp.rkt
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
#lang racket
(provide (all-defined-out))
(require "syntax.rkt")
;; type Value =
;; | Integer
;; | Boolean
;; | Character
;; | String
;; | (Box Value)
;; | (Cons Value Value)
;; | Function
;; type Function =
;; | (Values ... -> Answer)
;; type Answer = Value | 'err
;; type REnv = (Listof (List Variable Value))
;; type FAnswer = Answer | 'procedure
;; This is used because procedures aren't 'read'-able, so we use
;; the symbol 'procedure for such value
;; Prog -> FAnswer
(define (interp e)
(match (interp-env (desugar e) '())
[(? procedure?) 'procedure]
[a a]))
;; Expr REnv -> Answer
(define (interp-env e r)
(match e
;; produce fresh strings each time a literal is eval'd
[(? string? s) (string-copy s)]
[(? value? v) v]
[''() '()]
[`',(? symbol? x) x]
[(list (? prim? p) es ...)
(let ((as (interp-env* es r)))
(interp-prim p as))]
[`(if ,e0 ,e1 ,e2)
(match (interp-env e0 r)
['err 'err]
[v
(if v
(interp-env e1 r)
(interp-env e2 r))])]
[(? symbol? x)
(lookup r x)]
[`(let ,(list `(,xs ,es) ...) ,e)
(match (interp-env* es r)
['err 'err]
[vs
(interp-env e (append (zip xs vs) r))])]
[`(letrec ,(list `(,xs ,es) ...) ,e)
(letrec ((r* (λ ()
(append
(zip xs
;; η-expansion to delay evaluating r*
;; relies on RHSs being functions
(map (λ (l) (λ vs (apply (interp-env l (r*)) vs)))
es))
r))))
(interp-env e (r*)))]
[`(λ (,xs ...) ,e)
(λ vs
(if (= (length vs) (length xs))
(interp-env e (append (zip xs vs) r))
'err))]
[`(λ (,xs ... . ,x) ,e)
(λ vs
(if (>= (length vs) (length xs))
(interp-env e (append (zip/remainder xs vs x) r))
'err))]
[`(apply ,e0 ,e1)
(let ((v0 (interp-env e0 r))
(vs (interp-env e1 r)))
(if (list? vs)
(apply v0 vs)
'err))]
[`(,e . ,es)
(match (interp-env* (cons e es) r)
[(list f vs ...)
(if (procedure? f)
(apply f vs)
'err)])]
[_ 'err]))
;; (Listof Expr) REnv (Listof Defn) -> (Listof Value) | 'err
(define (interp-env* es r)
(match es
['() '()]
[(cons e es)
(match (interp-env e r)
['err 'err]
[v (cons v (interp-env* es r))])]))
;; (Listof (List Expr Expr)) Expr REnv -> Answer
(define (interp-cond-env cs en r)
(match cs
['() (interp-env en r)]
[(cons `(,eq ,ea) cs)
(match (interp-env eq r)
['err 'err]
[v
(if v
(interp-env ea r)
(interp-cond-env cs en r))])]))
;; Any -> Boolean
(define (prim? x)
(and (symbol? x)
(memq x '(add1 sub1 zero? abs - char? boolean? integer? integer->char char->integer
string? box? empty? cons cons? box unbox car cdr string-length
make-string string-ref = < <= char=? boolean=? + eq? gensym))))
;; Any -> Boolean
(define (value? x)
(or (integer? x)
(boolean? x)
(char? x)
(string? x)))
;; Prim (Listof Answer) -> Answer
(define (interp-prim p as)
(match (cons p as)
[(list p (? value?) ... 'err _ ...) 'err]
[(list '- (? integer? i0)) (- i0)]
[(list '- (? integer? i0) (? integer? i1)) (- i0 i1)]
[(list 'abs (? integer? i0)) (abs i0)]
[(list 'add1 (? integer? i0)) (+ i0 1)]
[(list 'sub1 (? integer? i0)) (- i0 1)]
[(list 'zero? (? integer? i0)) (zero? i0)]
[(list 'char? v0) (char? v0)]
[(list 'integer? v0) (integer? v0)]
[(list 'boolean? v0) (boolean? v0)]
[(list 'integer->char (? codepoint? i0)) (integer->char i0)]
[(list 'char->integer (? char? c)) (char->integer c)]
[(list '+ (? integer? i0) (? integer? i1)) (+ i0 i1)]
[(list 'cons v0 v1) (cons v0 v1)]
[(list 'car (? cons? v0)) (car v0)]
[(list 'cdr (? cons? v0)) (cdr v0)]
[(list 'string? v0) (string? v0)]
[(list 'box? v0) (box? v0)]
[(list 'empty? v0) (empty? v0)]
[(list 'cons? v0) (cons? v0)]
[(list 'cons v0 v1) (cons v0 v1)]
[(list 'box v0) (box v0)]
[(list 'unbox (? box? v0)) (unbox v0)]
[(list 'string-length (? string? v0)) (string-length v0)]
[(list 'make-string (? natural? v0) (? char? v1)) (make-string v0 v1)]
[(list 'string-ref (? string? v0) (? natural? v1))
(if (< v1 (string-length v0))
(string-ref v0 v1)
'err)]
[(list '= (? integer? v0) (? integer? v1)) (= v0 v1)]
[(list '< (? integer? v0) (? integer? v1)) (< v0 v1)]
[(list '<= (? integer? v0) (? integer? v1)) (<= v0 v1)]
[(list 'char=? (? char? v0) (? char? v1)) (char=? v0 v1)]
[(list 'boolean=? (? boolean? v0) (? boolean? v1)) (boolean=? v0 v1)]
[(list 'eq? v0 v1) (eq? v0 v1)]
[(list 'gensym) (gensym)]
[_ 'err]))
;; REnv Variable -> Answer
(define (lookup env x)
(match env
['() 'err]
[(cons (list y v) env)
(match (symbol=? x y)
[#t v]
[#f (lookup env x)])]))
;; REnv Variable Value -> Value
(define (ext r x v)
(cons (list x v) r))
;; Any -> Boolean
(define (codepoint? x)
(and (integer? x)
(<= 0 x #x10FFFF)
(not (<= #xD800 x #xDFFF))))
;; (Listof A) (Listof B) -> (Listof (List A B))
(define (zip xs ys)
(match* (xs ys)
[('() '()) '()]
[((cons x xs) (cons y ys))
(cons (list x y) (zip xs ys))]))
;; like zip but ys can be longer and remainder is associated with r
(define (zip/remainder xs ys r)
(match* (xs ys)
[('() ys) (list (list r ys))]
[((cons x xs) (cons y ys))
(cons (list x y) (zip/remainder xs ys r))]))