Commit | Line | Data |
---|---|---|
5161a3c0 AW |
1 | ;;; -*- mode: scheme; coding: utf-8; -*- |
2 | ||
eb037656 | 3 | ;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. |
5161a3c0 AW |
4 | ;;;; |
5 | ;;;; This library is free software; you can redistribute it and/or | |
6 | ;;;; modify it under the terms of the GNU Lesser General Public | |
7 | ;;;; License as published by the Free Software Foundation; either | |
8 | ;;;; version 3 of the License, or (at your option) any later version. | |
9 | ;;;; | |
10 | ;;;; This library is distributed in the hope that it will be useful, | |
11 | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | ;;;; Lesser General Public License for more details. | |
14 | ;;;; | |
15 | ;;;; You should have received a copy of the GNU Lesser General Public | |
16 | ;;;; License along with this library; if not, write to the Free Software | |
17 | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ;;;; | |
19 | ||
20 | \f | |
21 | ||
22 | ;;; Commentary: | |
23 | ||
b2b554ef AW |
24 | ;;; Scheme eval, written in Scheme. |
25 | ;;; | |
26 | ;;; Expressions are first expanded, by the syntax expander (i.e. | |
27 | ;;; psyntax), then memoized into internal forms. The evaluator itself | |
28 | ;;; only operates on the internal forms ("memoized expressions"). | |
29 | ;;; | |
95de4f52 AW |
30 | ;;; Environments are represented as a chain of vectors, linked through |
31 | ;;; their first elements. The terminal element of an environment is the | |
32 | ;;; module that was current when the outer lexical environment was | |
33 | ;;; entered. | |
5161a3c0 AW |
34 | ;;; |
35 | ||
36 | ;;; Code: | |
37 | ||
38 | \f | |
39 | ||
95de4f52 AW |
40 | (define (primitive-eval exp) |
41 | "Evaluate @var{exp} in the current module." | |
cfc28c80 AW |
42 | (define-syntax env-toplevel |
43 | (syntax-rules () | |
44 | ((_ env) | |
45 | (let lp ((e env)) | |
46 | (if (vector? e) | |
47 | (lp (vector-ref e 0)) | |
48 | e))))) | |
49 | ||
50 | (define-syntax make-env | |
51 | (syntax-rules () | |
52 | ((_ n init next) | |
53 | (let ((v (make-vector (1+ n) init))) | |
54 | (vector-set! v 0 next) | |
55 | v)))) | |
56 | ||
57 | (define-syntax make-env* | |
58 | (syntax-rules () | |
59 | ((_ next init ...) | |
60 | (vector next init ...)))) | |
61 | ||
62 | (define-syntax env-ref | |
63 | (syntax-rules () | |
64 | ((_ env depth width) | |
65 | (let lp ((e env) (d depth)) | |
66 | (if (zero? d) | |
67 | (vector-ref e (1+ width)) | |
68 | (lp (vector-ref e 0) (1- d))))))) | |
69 | ||
70 | (define-syntax env-set! | |
71 | (syntax-rules () | |
72 | ((_ env depth width val) | |
73 | (let lp ((e env) (d depth)) | |
74 | (if (zero? d) | |
75 | (vector-set! e (1+ width) val) | |
76 | (lp (vector-ref e 0) (1- d))))))) | |
77 | ||
95de4f52 AW |
78 | ;; This is a modified version of Oleg Kiselyov's "pmatch". |
79 | (define-syntax-rule (match e cs ...) | |
80 | (let ((v e)) (expand-clauses v cs ...))) | |
81 | ||
82 | (define-syntax expand-clauses | |
be6e40a1 | 83 | (syntax-rules () |
95de4f52 AW |
84 | ((_ v) ((error "unreachable"))) |
85 | ((_ v (pat e0 e ...) cs ...) | |
86 | (let ((fk (lambda () (expand-clauses v cs ...)))) | |
87 | (expand-pattern v pat (let () e0 e ...) (fk)))))) | |
88 | ||
89 | (define-syntax expand-pattern | |
eb037656 | 90 | (syntax-rules (_ quote unquote ?) |
95de4f52 AW |
91 | ((_ v _ kt kf) kt) |
92 | ((_ v () kt kf) (if (null? v) kt kf)) | |
93 | ((_ v (quote lit) kt kf) | |
94 | (if (equal? v (quote lit)) kt kf)) | |
95 | ((_ v (unquote exp) kt kf) | |
96 | (if (equal? v exp) kt kf)) | |
97 | ((_ v (x . y) kt kf) | |
98 | (if (pair? v) | |
99 | (let ((vx (car v)) (vy (cdr v))) | |
100 | (expand-pattern vx x (expand-pattern vy y kt kf) kf)) | |
101 | kf)) | |
eb037656 AW |
102 | ((_ v (? pred var) kt kf) |
103 | (if (pred v) (let ((var v)) kt) kf)) | |
95de4f52 AW |
104 | ((_ v #f kt kf) (if (eqv? v #f) kt kf)) |
105 | ((_ v var kt kf) (let ((var v)) kt)))) | |
106 | ||
107 | (define-syntax typecode | |
5161a3c0 AW |
108 | (lambda (x) |
109 | (syntax-case x () | |
95de4f52 AW |
110 | ((_ type) |
111 | (or (memoized-typecode (syntax->datum #'type)) | |
112 | (error "not a typecode" (syntax->datum #'type))))))) | |
113 | ||
d76d80d2 AW |
114 | (define-syntax-rule (lazy (arg ...) exp) |
115 | (letrec ((proc (lambda (arg ...) | |
116 | (set! proc exp) | |
117 | (proc arg ...)))) | |
118 | (lambda (arg ...) | |
119 | (proc arg ...)))) | |
120 | ||
95de4f52 AW |
121 | (define (compile-lexical-ref depth width) |
122 | (lambda (env) | |
123 | (env-ref env depth width))) | |
124 | ||
7fee63b9 AW |
125 | (define (primitive=? name loc module var) |
126 | "Return true if VAR is the same as the primitive bound to NAME." | |
127 | (match loc | |
128 | ((mode . loc) | |
129 | (and (match loc | |
130 | ((mod name* . public?) (eq? name* name)) | |
131 | (_ (eq? loc name))) | |
132 | ;; `module' can be #f if the module system was not yet | |
133 | ;; booted when the environment was captured. | |
134 | (or (not module) | |
135 | (eq? var (module-local-variable the-root-module name))))))) | |
136 | ||
d76d80d2 AW |
137 | (define (compile-top-call cenv loc args) |
138 | (let* ((module (env-toplevel cenv)) | |
139 | (var (%resolve-variable loc module))) | |
d76d80d2 | 140 | (define-syntax-rule (maybe-primcall (prim ...) arg ...) |
7fee63b9 AW |
141 | (let ((arg (compile arg)) |
142 | ...) | |
143 | (cond | |
144 | ((primitive=? 'prim loc module var) | |
145 | (lambda (env) (prim (arg env) ...))) | |
146 | ... | |
147 | (else (lambda (env) ((variable-ref var) (arg env) ...)))))) | |
95de4f52 | 148 | (match args |
d76d80d2 AW |
149 | (() |
150 | (lambda (env) ((variable-ref var)))) | |
95de4f52 | 151 | ((a) |
7fee63b9 AW |
152 | (maybe-primcall (1+ 1- car cdr lognot vector-length |
153 | variable-ref string-length struct-vtable) | |
154 | a)) | |
95de4f52 | 155 | ((a b) |
7fee63b9 AW |
156 | (maybe-primcall (+ - * / ash logand logior logxor |
157 | cons vector-ref struct-ref allocate-struct variable-set!) | |
158 | a b)) | |
95de4f52 | 159 | ((a b c) |
7fee63b9 | 160 | (maybe-primcall (vector-set! struct-set!) a b c)) |
95de4f52 AW |
161 | ((a b c . args) |
162 | (let ((a (compile a)) | |
163 | (b (compile b)) | |
164 | (c (compile c)) | |
165 | (args (let lp ((args args)) | |
166 | (if (null? args) | |
167 | '() | |
168 | (cons (compile (car args)) (lp (cdr args))))))) | |
169 | (lambda (env) | |
d76d80d2 | 170 | (apply (variable-ref var) (a env) (b env) (c env) |
95de4f52 AW |
171 | (let lp ((args args)) |
172 | (if (null? args) | |
173 | '() | |
174 | (cons ((car args) env) (lp (cdr args)))))))))))) | |
175 | ||
d76d80d2 AW |
176 | (define (compile-call f args) |
177 | (match f | |
178 | ((,(typecode box-ref) . (,(typecode resolve) . loc)) | |
179 | (lazy (env) (compile-top-call env loc args))) | |
180 | (_ | |
181 | (match args | |
182 | (() | |
183 | (let ((f (compile f))) | |
184 | (lambda (env) ((f env))))) | |
185 | ((a) | |
186 | (let ((f (compile f)) | |
187 | (a (compile a))) | |
188 | (lambda (env) ((f env) (a env))))) | |
189 | ((a b) | |
190 | (let ((f (compile f)) | |
191 | (a (compile a)) | |
192 | (b (compile b))) | |
193 | (lambda (env) ((f env) (a env) (b env))))) | |
194 | ((a b c) | |
195 | (let ((f (compile f)) | |
196 | (a (compile a)) | |
197 | (b (compile b)) | |
198 | (c (compile c))) | |
199 | (lambda (env) ((f env) (a env) (b env) (c env))))) | |
200 | ((a b c . args) | |
201 | (let ((f (compile f)) | |
202 | (a (compile a)) | |
203 | (b (compile b)) | |
204 | (c (compile c)) | |
205 | (args (let lp ((args args)) | |
206 | (if (null? args) | |
207 | '() | |
208 | (cons (compile (car args)) (lp (cdr args))))))) | |
209 | (lambda (env) | |
210 | (apply (f env) (a env) (b env) (c env) | |
211 | (let lp ((args args)) | |
212 | (if (null? args) | |
213 | '() | |
214 | (cons ((car args) env) (lp (cdr args))))))))))))) | |
215 | ||
fe7ecee8 | 216 | (define (compile-box-ref box) |
95de4f52 | 217 | (match box |
d76d80d2 | 218 | ((,(typecode resolve) . loc) |
fe7ecee8 AW |
219 | (lazy (cenv) |
220 | (let ((var (%resolve-variable loc (env-toplevel cenv)))) | |
221 | (lambda (env) (variable-ref var))))) | |
95de4f52 AW |
222 | ((,(typecode lexical-ref) depth . width) |
223 | (lambda (env) | |
224 | (variable-ref (env-ref env depth width)))) | |
225 | (_ | |
226 | (let ((box (compile box))) | |
227 | (lambda (env) | |
228 | (variable-ref (box env))))))) | |
229 | ||
d76d80d2 AW |
230 | (define (compile-resolve cenv loc) |
231 | (let ((var (%resolve-variable loc (env-toplevel cenv)))) | |
232 | (lambda (env) var))) | |
95de4f52 | 233 | |
7fee63b9 AW |
234 | (define (compile-top-branch cenv loc args consequent alternate) |
235 | (let* ((module (env-toplevel cenv)) | |
236 | (var (%resolve-variable loc module)) | |
237 | (consequent (compile consequent)) | |
238 | (alternate (compile alternate))) | |
239 | (define (generic-top-branch) | |
240 | (let ((test (compile-top-call cenv loc args))) | |
241 | (lambda (env) | |
242 | (if (test env) (consequent env) (alternate env))))) | |
243 | (define-syntax-rule (maybe-primcall (prim ...) arg ...) | |
244 | (cond | |
245 | ((primitive=? 'prim loc module var) | |
246 | (let ((arg (compile arg)) | |
247 | ...) | |
248 | (lambda (env) | |
249 | (if (prim (arg env) ...) | |
250 | (consequent env) | |
251 | (alternate env))))) | |
252 | ... | |
253 | (else (generic-top-branch)))) | |
254 | (match args | |
255 | ((a) | |
256 | (maybe-primcall (null? nil? pair? struct? string? vector? symbol? | |
257 | keyword? variable? bitvector? char? zero? not) | |
258 | a)) | |
259 | ((a b) | |
260 | (maybe-primcall (eq? eqv? equal? = < > <= >= logtest logbit?) | |
261 | a b)) | |
262 | (_ | |
263 | (generic-top-branch))))) | |
264 | ||
95de4f52 | 265 | (define (compile-if test consequent alternate) |
7fee63b9 AW |
266 | (match test |
267 | ((,(typecode call) | |
268 | (,(typecode box-ref) . (,(typecode resolve) . loc)) | |
269 | . args) | |
270 | (lazy (env) (compile-top-branch env loc args consequent alternate))) | |
271 | (_ | |
272 | (let ((test (compile test)) | |
273 | (consequent (compile consequent)) | |
274 | (alternate (compile alternate))) | |
275 | (lambda (env) | |
276 | (if (test env) (consequent env) (alternate env))))))) | |
95de4f52 AW |
277 | |
278 | (define (compile-quote x) | |
279 | (lambda (env) x)) | |
280 | ||
281 | (define (compile-let inits body) | |
282 | (let ((body (compile body)) | |
283 | (width (vector-length inits))) | |
284 | (case width | |
285 | ((0) (lambda (env) | |
286 | (body (make-env* env)))) | |
287 | ((1) | |
288 | (let ((a (compile (vector-ref inits 0)))) | |
289 | (lambda (env) | |
290 | (body (make-env* env (a env)))))) | |
291 | ((2) | |
292 | (let ((a (compile (vector-ref inits 0))) | |
293 | (b (compile (vector-ref inits 1)))) | |
294 | (lambda (env) | |
295 | (body (make-env* env (a env) (b env)))))) | |
296 | ((3) | |
297 | (let ((a (compile (vector-ref inits 0))) | |
298 | (b (compile (vector-ref inits 1))) | |
299 | (c (compile (vector-ref inits 2)))) | |
300 | (lambda (env) | |
301 | (body (make-env* env (a env) (b env) (c env)))))) | |
302 | ((4) | |
303 | (let ((a (compile (vector-ref inits 0))) | |
304 | (b (compile (vector-ref inits 1))) | |
305 | (c (compile (vector-ref inits 2))) | |
306 | (d (compile (vector-ref inits 3)))) | |
307 | (lambda (env) | |
308 | (body (make-env* env (a env) (b env) (c env) (d env)))))) | |
309 | (else | |
310 | (let lp ((n width) | |
311 | (k (lambda (env) | |
312 | (make-env width #f env)))) | |
313 | (if (zero? n) | |
314 | (lambda (env) | |
315 | (body (k env))) | |
316 | (lp (1- n) | |
317 | (let ((init (compile (vector-ref inits (1- n))))) | |
318 | (lambda (env) | |
319 | (let* ((x (init env)) | |
320 | (new-env (k env))) | |
321 | (env-set! new-env 0 (1- n) x) | |
322 | new-env)))))))))) | |
323 | ||
324 | (define (compile-fixed-lambda body nreq) | |
325 | (case nreq | |
326 | ((0) (lambda (env) | |
327 | (lambda () | |
328 | (body (make-env* env))))) | |
329 | ((1) (lambda (env) | |
330 | (lambda (a) | |
331 | (body (make-env* env a))))) | |
332 | ((2) (lambda (env) | |
333 | (lambda (a b) | |
334 | (body (make-env* env a b))))) | |
335 | ((3) (lambda (env) | |
336 | (lambda (a b c) | |
337 | (body (make-env* env a b c))))) | |
338 | ((4) (lambda (env) | |
339 | (lambda (a b c d) | |
340 | (body (make-env* env a b c d))))) | |
341 | ((5) (lambda (env) | |
342 | (lambda (a b c d e) | |
343 | (body (make-env* env a b c d e))))) | |
344 | ((6) (lambda (env) | |
345 | (lambda (a b c d e f) | |
346 | (body (make-env* env a b c d e f))))) | |
347 | ((7) (lambda (env) | |
348 | (lambda (a b c d e f g) | |
349 | (body (make-env* env a b c d e f g))))) | |
350 | (else | |
351 | (lambda (env) | |
352 | (lambda (a b c d e f g . more) | |
353 | (let ((env (make-env nreq #f env))) | |
354 | (env-set! env 0 0 a) | |
355 | (env-set! env 0 1 b) | |
356 | (env-set! env 0 2 c) | |
357 | (env-set! env 0 3 d) | |
358 | (env-set! env 0 4 e) | |
359 | (env-set! env 0 5 f) | |
360 | (env-set! env 0 6 g) | |
361 | (let lp ((n 7) (args more)) | |
362 | (cond | |
363 | ((= n nreq) | |
364 | (unless (null? args) | |
365 | (scm-error 'wrong-number-of-args | |
366 | "eval" "Wrong number of arguments" | |
367 | '() #f)) | |
368 | (body env)) | |
369 | ((null? args) | |
370 | (scm-error 'wrong-number-of-args | |
371 | "eval" "Wrong number of arguments" | |
372 | '() #f)) | |
373 | (else | |
374 | (env-set! env 0 n (car args)) | |
375 | (lp (1+ n) (cdr args))))))))))) | |
376 | ||
377 | (define (compile-rest-lambda body nreq rest?) | |
378 | (case nreq | |
379 | ((0) (lambda (env) | |
380 | (lambda rest | |
381 | (body (make-env* env rest))))) | |
382 | ((1) (lambda (env) | |
383 | (lambda (a . rest) | |
384 | (body (make-env* env a rest))))) | |
385 | ((2) (lambda (env) | |
386 | (lambda (a b . rest) | |
387 | (body (make-env* env a b rest))))) | |
388 | ((3) (lambda (env) | |
389 | (lambda (a b c . rest) | |
390 | (body (make-env* env a b c rest))))) | |
391 | (else | |
392 | (lambda (env) | |
393 | (lambda (a b c . more) | |
394 | (let ((env (make-env (1+ nreq) #f env))) | |
395 | (env-set! env 0 0 a) | |
396 | (env-set! env 0 1 b) | |
397 | (env-set! env 0 2 c) | |
398 | (let lp ((n 3) (args more)) | |
399 | (cond | |
400 | ((= n nreq) | |
401 | (env-set! env 0 n args) | |
402 | (body env)) | |
403 | ((null? args) | |
404 | (scm-error 'wrong-number-of-args | |
405 | "eval" "Wrong number of arguments" | |
406 | '() #f)) | |
407 | (else | |
408 | (env-set! env 0 n (car args)) | |
409 | (lp (1+ n) (cdr args))))))))))) | |
410 | ||
411 | (define (compile-opt-lambda body nreq rest? nopt ninits unbound make-alt) | |
412 | (lambda (env) | |
413 | (define alt (and make-alt (make-alt env))) | |
414 | (lambda args | |
415 | (let ((nargs (length args))) | |
416 | (cond | |
417 | ((or (< nargs nreq) (and (not rest?) (> nargs (+ nreq nopt)))) | |
418 | (if alt | |
419 | (apply alt args) | |
420 | ((scm-error 'wrong-number-of-args | |
421 | "eval" "Wrong number of arguments" | |
422 | '() #f)))) | |
423 | (else | |
424 | (let* ((nvals (+ nreq (if rest? 1 0) ninits)) | |
425 | (env (make-env nvals unbound env))) | |
426 | (define (bind-req args) | |
427 | (let lp ((i 0) (args args)) | |
428 | (cond | |
429 | ((< i nreq) | |
430 | ;; Bind required arguments. | |
431 | (env-set! env 0 i (car args)) | |
432 | (lp (1+ i) (cdr args))) | |
433 | (else | |
434 | (bind-opt args))))) | |
435 | (define (bind-opt args) | |
436 | (let lp ((i nreq) (args args)) | |
437 | (cond | |
438 | ((and (< i (+ nreq nopt)) (< i nargs)) | |
439 | (env-set! env 0 i (car args)) | |
440 | (lp (1+ i) (cdr args))) | |
441 | (else | |
442 | (bind-rest args))))) | |
443 | (define (bind-rest args) | |
444 | (when rest? | |
445 | (env-set! env 0 (+ nreq nopt) args)) | |
446 | (body env)) | |
447 | (bind-req args)))))))) | |
448 | ||
449 | (define (compile-kw-lambda body nreq rest? nopt kw ninits unbound make-alt) | |
450 | (define allow-other-keys? (car kw)) | |
451 | (define keywords (cdr kw)) | |
452 | (lambda (env) | |
453 | (define alt (and make-alt (make-alt env))) | |
454 | (lambda args | |
455 | (define (npositional args) | |
456 | (let lp ((n 0) (args args)) | |
457 | (if (or (null? args) | |
458 | (and (>= n nreq) (keyword? (car args)))) | |
459 | n | |
460 | (lp (1+ n) (cdr args))))) | |
461 | (let ((nargs (length args))) | |
462 | (cond | |
463 | ((or (< nargs nreq) | |
464 | (and alt (not rest?) (> (npositional args) (+ nreq nopt)))) | |
465 | (if alt | |
466 | (apply alt args) | |
467 | ((scm-error 'wrong-number-of-args | |
468 | "eval" "Wrong number of arguments" | |
469 | '() #f)))) | |
470 | (else | |
471 | (let* ((nvals (+ nreq (if rest? 1 0) ninits)) | |
472 | (env (make-env nvals unbound env))) | |
473 | (define (bind-req args) | |
474 | (let lp ((i 0) (args args)) | |
475 | (cond | |
476 | ((< i nreq) | |
477 | ;; Bind required arguments. | |
478 | (env-set! env 0 i (car args)) | |
479 | (lp (1+ i) (cdr args))) | |
480 | (else | |
481 | (bind-opt args))))) | |
482 | (define (bind-opt args) | |
483 | (let lp ((i nreq) (args args)) | |
484 | (cond | |
485 | ((and (< i (+ nreq nopt)) (< i nargs) | |
486 | (not (keyword? (car args)))) | |
487 | (env-set! env 0 i (car args)) | |
488 | (lp (1+ i) (cdr args))) | |
489 | (else | |
490 | (bind-rest args))))) | |
491 | (define (bind-rest args) | |
492 | (when rest? | |
493 | (env-set! env 0 (+ nreq nopt) args)) | |
494 | (bind-kw args)) | |
495 | (define (bind-kw args) | |
496 | (let lp ((args args)) | |
497 | (cond | |
498 | ((and (pair? args) (pair? (cdr args)) | |
499 | (keyword? (car args))) | |
500 | (let ((kw-pair (assq (car args) keywords)) | |
501 | (v (cadr args))) | |
502 | (if kw-pair | |
503 | ;; Found a known keyword; set its value. | |
504 | (env-set! env 0 (cdr kw-pair) v) | |
505 | ;; Unknown keyword. | |
506 | (if (not allow-other-keys?) | |
507 | ((scm-error | |
508 | 'keyword-argument-error | |
509 | "eval" "Unrecognized keyword" | |
510 | '() (list (car args)))))) | |
511 | (lp (cddr args)))) | |
512 | ((pair? args) | |
513 | (if rest? | |
514 | ;; Be lenient parsing rest args. | |
515 | (lp (cdr args)) | |
516 | ((scm-error 'keyword-argument-error | |
517 | "eval" "Invalid keyword" | |
518 | '() (list (car args)))))) | |
519 | (else | |
520 | (body env))))) | |
521 | (bind-req args)))))))) | |
522 | ||
523 | (define (compute-arity alt nreq rest? nopt kw) | |
524 | (let lp ((alt alt) (nreq nreq) (nopt nopt) (rest? rest?)) | |
525 | (if (not alt) | |
526 | (let ((arglist (list nreq | |
527 | nopt | |
528 | (if kw (cdr kw) '()) | |
529 | (and kw (car kw)) | |
530 | (and rest? '_)))) | |
531 | (values arglist nreq nopt rest?)) | |
532 | (let* ((spec (cddr alt)) | |
533 | (nreq* (car spec)) | |
534 | (rest?* (if (null? (cdr spec)) #f (cadr spec))) | |
535 | (tail (and (pair? (cdr spec)) (pair? (cddr spec)) (cddr spec))) | |
536 | (nopt* (if tail (car tail) 0)) | |
537 | (alt* (and tail (car (cddddr tail))))) | |
538 | (if (or (< nreq* nreq) | |
539 | (and (= nreq* nreq) | |
540 | (if rest? | |
541 | (and rest?* (> nopt* nopt)) | |
542 | (or rest?* (> nopt* nopt))))) | |
543 | (lp alt* nreq* nopt* rest?*) | |
544 | (lp alt* nreq nopt rest?)))))) | |
545 | ||
546 | (define (compile-general-lambda body nreq rest? nopt kw ninits unbound alt) | |
547 | (call-with-values | |
548 | (lambda () | |
549 | (compute-arity alt nreq rest? nopt kw)) | |
550 | (lambda (arglist min-nreq min-nopt min-rest?) | |
551 | (define make-alt | |
552 | (match alt | |
553 | (#f #f) | |
554 | ((body meta nreq . tail) | |
555 | (compile-lambda body meta nreq tail)))) | |
556 | (define make-closure | |
557 | (if kw | |
558 | (compile-kw-lambda body nreq rest? nopt kw ninits unbound make-alt) | |
559 | (compile-opt-lambda body nreq rest? nopt ninits unbound make-alt))) | |
560 | (lambda (env) | |
561 | (let ((proc (make-closure env))) | |
562 | (set-procedure-property! proc 'arglist arglist) | |
563 | (set-procedure-minimum-arity! proc min-nreq min-nopt min-rest?) | |
564 | proc))))) | |
565 | ||
566 | (define (compile-lambda body meta nreq tail) | |
567 | (define (set-procedure-meta meta proc) | |
568 | (match meta | |
569 | (() proc) | |
570 | (((prop . val) . meta) | |
571 | (set-procedure-meta meta | |
572 | (lambda (env) | |
573 | (let ((proc (proc env))) | |
574 | (set-procedure-property! proc prop val) | |
575 | proc)))))) | |
d76d80d2 | 576 | (let ((body (lazy (env) (compile body)))) |
95de4f52 AW |
577 | (set-procedure-meta |
578 | meta | |
579 | (match tail | |
580 | (() (compile-fixed-lambda body nreq)) | |
581 | ((rest? . tail) | |
582 | (match tail | |
583 | (() (compile-rest-lambda body nreq rest?)) | |
584 | ((nopt kw ninits unbound alt) | |
585 | (compile-general-lambda body nreq rest? nopt kw | |
586 | ninits unbound alt)))))))) | |
587 | ||
588 | (define (compile-capture-env locs body) | |
589 | (let ((body (compile body))) | |
590 | (lambda (env) | |
591 | (let* ((len (vector-length locs)) | |
592 | (new-env (make-env len #f (env-toplevel env)))) | |
593 | (let lp ((n 0)) | |
594 | (when (< n len) | |
595 | (match (vector-ref locs n) | |
596 | ((depth . width) | |
597 | (env-set! new-env 0 n (env-ref env depth width)))) | |
598 | (lp (1+ n)))) | |
599 | (body new-env))))) | |
600 | ||
601 | (define (compile-seq head tail) | |
602 | (let ((head (compile head)) | |
603 | (tail (compile tail))) | |
604 | (lambda (env) | |
605 | (head env) | |
606 | (tail env)))) | |
607 | ||
608 | (define (compile-box-set! box val) | |
609 | (let ((box (compile box)) | |
610 | (val (compile val))) | |
611 | (lambda (env) | |
612 | (let ((val (val env))) | |
613 | (variable-set! (box env) val))))) | |
614 | ||
615 | (define (compile-lexical-set! depth width x) | |
616 | (let ((x (compile x))) | |
617 | (lambda (env) | |
618 | (env-set! env depth width (x env))))) | |
619 | ||
620 | (define (compile-call-with-values producer consumer) | |
621 | (let ((producer (compile producer)) | |
622 | (consumer (compile consumer))) | |
623 | (lambda (env) | |
624 | (call-with-values (producer env) | |
625 | (consumer env))))) | |
626 | ||
627 | (define (compile-apply f args) | |
628 | (let ((f (compile f)) | |
629 | (args (compile args))) | |
630 | (lambda (env) | |
631 | (apply (f env) (args env))))) | |
632 | ||
633 | (define (compile-capture-module x) | |
634 | (let ((x (compile x))) | |
635 | (lambda (env) | |
636 | (x (current-module))))) | |
637 | ||
638 | (define (compile-call-with-prompt tag thunk handler) | |
639 | (let ((tag (compile tag)) | |
640 | (thunk (compile thunk)) | |
641 | (handler (compile handler))) | |
642 | (lambda (env) | |
643 | (call-with-prompt (tag env) (thunk env) (handler env))))) | |
644 | ||
645 | (define (compile-call/cc proc) | |
646 | (let ((proc (compile proc))) | |
647 | (lambda (env) | |
648 | (call/cc (proc env))))) | |
649 | ||
650 | (define (compile exp) | |
651 | (match exp | |
652 | ((,(typecode lexical-ref) depth . width) | |
653 | (compile-lexical-ref depth width)) | |
654 | ||
eb037656 AW |
655 | ((,(typecode call) f . args) |
656 | (compile-call f args)) | |
95de4f52 AW |
657 | |
658 | ((,(typecode box-ref) . box) | |
fe7ecee8 | 659 | (compile-box-ref box)) |
5161a3c0 | 660 | |
d76d80d2 AW |
661 | ((,(typecode resolve) . loc) |
662 | (lazy (env) (compile-resolve env loc))) | |
5161a3c0 | 663 | |
95de4f52 AW |
664 | ((,(typecode if) test consequent . alternate) |
665 | (compile-if test consequent alternate)) | |
21ec0bd9 | 666 | |
95de4f52 AW |
667 | ((,(typecode quote) . x) |
668 | (compile-quote x)) | |
669 | ||
670 | ((,(typecode let) inits . body) | |
671 | (compile-let inits body)) | |
672 | ||
673 | ((,(typecode lambda) body meta nreq . tail) | |
674 | (compile-lambda body meta nreq tail)) | |
675 | ||
676 | ((,(typecode capture-env) locs . body) | |
677 | (compile-capture-env locs body)) | |
678 | ||
679 | ((,(typecode seq) head . tail) | |
680 | (compile-seq head tail)) | |
681 | ||
682 | ((,(typecode box-set!) box . val) | |
683 | (compile-box-set! box val)) | |
684 | ||
685 | ((,(typecode lexical-set!) (depth . width) . x) | |
686 | (compile-lexical-set! depth width x)) | |
687 | ||
688 | ((,(typecode call-with-values) producer . consumer) | |
689 | (compile-call-with-values producer consumer)) | |
690 | ||
691 | ((,(typecode apply) f args) | |
692 | (compile-apply f args)) | |
693 | ||
694 | ((,(typecode capture-module) . x) | |
695 | (compile-capture-module x)) | |
696 | ||
697 | ((,(typecode call-with-prompt) tag thunk . handler) | |
698 | (compile-call-with-prompt tag thunk handler)) | |
5161a3c0 | 699 | |
95de4f52 AW |
700 | ((,(typecode call/cc) . proc) |
701 | (compile-call/cc proc)))) | |
702 | ||
d76d80d2 AW |
703 | (let ((eval (compile |
704 | (memoize-expression | |
95de4f52 AW |
705 | (if (macroexpanded? exp) |
706 | exp | |
707 | ((module-transformer (current-module)) exp))))) | |
708 | (env #f)) | |
d76d80d2 | 709 | (eval env))) |