Primcall inlining in eval.scm, lazy function body compilation
[bpt/guile.git] / module / ice-9 / eval.scm
CommitLineData
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
d76d80d2
AW
125 (define (compile-top-call cenv loc args)
126 (let* ((module (env-toplevel cenv))
127 (var (%resolve-variable loc module)))
128 (define (primitive=? name)
129 "Return true if VAR is the same as the primitive bound to NAME."
130 (match loc
131 ((mode . loc)
132 (and (match loc
133 ((mod name* . public?) (eq? name* name))
134 (_ (eq? loc name)))
135 ;; `module' can be #f if the module system was not yet
136 ;; booted when the environment was captured.
137 (or (not module)
138 (eq? var (module-local-variable the-root-module name)))))))
139 (define-syntax-rule (maybe-primcall (prim ...) arg ...)
140 (cond
141 ((primitive=? 'prim) (lambda (env) (prim (arg env) ...)))
142 ...
143 (else (lambda (env) ((variable-ref var) (arg env) ...)))))
95de4f52 144 (match args
d76d80d2
AW
145 (()
146 (lambda (env) ((variable-ref var))))
95de4f52
AW
147 ((a)
148 (let ((a (compile a)))
d76d80d2
AW
149 (maybe-primcall
150 (null? nil? pair? struct? string? vector? symbol?
151 keyword? variable? bitvector? char? zero?
152 1+ 1- car cdr lognot not vector-length
153 variable-ref string-length struct-vtable)
154 a)))
95de4f52
AW
155 ((a b)
156 (let ((a (compile a))
157 (b (compile b)))
d76d80d2
AW
158 (maybe-primcall
159 (+ - * / eq? eqv? equal? = < > <= >=
160 ash logand logior logxor logtest logbit?
161 cons vector-ref struct-ref allocate-struct variable-set!)
162 a b)))
95de4f52
AW
163 ((a b c)
164 (let ((a (compile a))
165 (b (compile b))
166 (c (compile c)))
d76d80d2 167 (maybe-primcall (vector-set! struct-set!) a b c)))
95de4f52
AW
168 ((a b c . args)
169 (let ((a (compile a))
170 (b (compile b))
171 (c (compile c))
172 (args (let lp ((args args))
173 (if (null? args)
174 '()
175 (cons (compile (car args)) (lp (cdr args)))))))
176 (lambda (env)
d76d80d2 177 (apply (variable-ref var) (a env) (b env) (c env)
95de4f52
AW
178 (let lp ((args args))
179 (if (null? args)
180 '()
181 (cons ((car args) env) (lp (cdr args))))))))))))
182
d76d80d2
AW
183 (define (compile-call f args)
184 (match f
185 ((,(typecode box-ref) . (,(typecode resolve) . loc))
186 (lazy (env) (compile-top-call env loc args)))
187 (_
188 (match args
189 (()
190 (let ((f (compile f)))
191 (lambda (env) ((f env)))))
192 ((a)
193 (let ((f (compile f))
194 (a (compile a)))
195 (lambda (env) ((f env) (a env)))))
196 ((a b)
197 (let ((f (compile f))
198 (a (compile a))
199 (b (compile b)))
200 (lambda (env) ((f env) (a env) (b env)))))
201 ((a b c)
202 (let ((f (compile f))
203 (a (compile a))
204 (b (compile b))
205 (c (compile c)))
206 (lambda (env) ((f env) (a env) (b env) (c env)))))
207 ((a b c . args)
208 (let ((f (compile f))
209 (a (compile a))
210 (b (compile b))
211 (c (compile c))
212 (args (let lp ((args args))
213 (if (null? args)
214 '()
215 (cons (compile (car args)) (lp (cdr args)))))))
216 (lambda (env)
217 (apply (f env) (a env) (b env) (c env)
218 (let lp ((args args))
219 (if (null? args)
220 '()
221 (cons ((car args) env) (lp (cdr args)))))))))))))
222
223 (define (compile-box-ref cenv box)
95de4f52 224 (match box
d76d80d2
AW
225 ((,(typecode resolve) . loc)
226 (let ((var (%resolve-variable loc (env-toplevel cenv))))
227 (lambda (env) (variable-ref var))))
95de4f52
AW
228 ((,(typecode lexical-ref) depth . width)
229 (lambda (env)
230 (variable-ref (env-ref env depth width))))
231 (_
232 (let ((box (compile box)))
233 (lambda (env)
234 (variable-ref (box env)))))))
235
d76d80d2
AW
236 (define (compile-resolve cenv loc)
237 (let ((var (%resolve-variable loc (env-toplevel cenv))))
238 (lambda (env) var)))
95de4f52
AW
239
240 (define (compile-if test consequent alternate)
241 (let ((test (compile test))
242 (consequent (compile consequent))
243 (alternate (compile alternate)))
244 (lambda (env)
245 (if (test env) (consequent env) (alternate env)))))
246
247 (define (compile-quote x)
248 (lambda (env) x))
249
250 (define (compile-let inits body)
251 (let ((body (compile body))
252 (width (vector-length inits)))
253 (case width
254 ((0) (lambda (env)
255 (body (make-env* env))))
256 ((1)
257 (let ((a (compile (vector-ref inits 0))))
258 (lambda (env)
259 (body (make-env* env (a env))))))
260 ((2)
261 (let ((a (compile (vector-ref inits 0)))
262 (b (compile (vector-ref inits 1))))
263 (lambda (env)
264 (body (make-env* env (a env) (b env))))))
265 ((3)
266 (let ((a (compile (vector-ref inits 0)))
267 (b (compile (vector-ref inits 1)))
268 (c (compile (vector-ref inits 2))))
269 (lambda (env)
270 (body (make-env* env (a env) (b env) (c env))))))
271 ((4)
272 (let ((a (compile (vector-ref inits 0)))
273 (b (compile (vector-ref inits 1)))
274 (c (compile (vector-ref inits 2)))
275 (d (compile (vector-ref inits 3))))
276 (lambda (env)
277 (body (make-env* env (a env) (b env) (c env) (d env))))))
278 (else
279 (let lp ((n width)
280 (k (lambda (env)
281 (make-env width #f env))))
282 (if (zero? n)
283 (lambda (env)
284 (body (k env)))
285 (lp (1- n)
286 (let ((init (compile (vector-ref inits (1- n)))))
287 (lambda (env)
288 (let* ((x (init env))
289 (new-env (k env)))
290 (env-set! new-env 0 (1- n) x)
291 new-env))))))))))
292
293 (define (compile-fixed-lambda body nreq)
294 (case nreq
295 ((0) (lambda (env)
296 (lambda ()
297 (body (make-env* env)))))
298 ((1) (lambda (env)
299 (lambda (a)
300 (body (make-env* env a)))))
301 ((2) (lambda (env)
302 (lambda (a b)
303 (body (make-env* env a b)))))
304 ((3) (lambda (env)
305 (lambda (a b c)
306 (body (make-env* env a b c)))))
307 ((4) (lambda (env)
308 (lambda (a b c d)
309 (body (make-env* env a b c d)))))
310 ((5) (lambda (env)
311 (lambda (a b c d e)
312 (body (make-env* env a b c d e)))))
313 ((6) (lambda (env)
314 (lambda (a b c d e f)
315 (body (make-env* env a b c d e f)))))
316 ((7) (lambda (env)
317 (lambda (a b c d e f g)
318 (body (make-env* env a b c d e f g)))))
319 (else
320 (lambda (env)
321 (lambda (a b c d e f g . more)
322 (let ((env (make-env nreq #f env)))
323 (env-set! env 0 0 a)
324 (env-set! env 0 1 b)
325 (env-set! env 0 2 c)
326 (env-set! env 0 3 d)
327 (env-set! env 0 4 e)
328 (env-set! env 0 5 f)
329 (env-set! env 0 6 g)
330 (let lp ((n 7) (args more))
331 (cond
332 ((= n nreq)
333 (unless (null? args)
334 (scm-error 'wrong-number-of-args
335 "eval" "Wrong number of arguments"
336 '() #f))
337 (body env))
338 ((null? args)
339 (scm-error 'wrong-number-of-args
340 "eval" "Wrong number of arguments"
341 '() #f))
342 (else
343 (env-set! env 0 n (car args))
344 (lp (1+ n) (cdr args)))))))))))
345
346 (define (compile-rest-lambda body nreq rest?)
347 (case nreq
348 ((0) (lambda (env)
349 (lambda rest
350 (body (make-env* env rest)))))
351 ((1) (lambda (env)
352 (lambda (a . rest)
353 (body (make-env* env a rest)))))
354 ((2) (lambda (env)
355 (lambda (a b . rest)
356 (body (make-env* env a b rest)))))
357 ((3) (lambda (env)
358 (lambda (a b c . rest)
359 (body (make-env* env a b c rest)))))
360 (else
361 (lambda (env)
362 (lambda (a b c . more)
363 (let ((env (make-env (1+ nreq) #f env)))
364 (env-set! env 0 0 a)
365 (env-set! env 0 1 b)
366 (env-set! env 0 2 c)
367 (let lp ((n 3) (args more))
368 (cond
369 ((= n nreq)
370 (env-set! env 0 n args)
371 (body env))
372 ((null? args)
373 (scm-error 'wrong-number-of-args
374 "eval" "Wrong number of arguments"
375 '() #f))
376 (else
377 (env-set! env 0 n (car args))
378 (lp (1+ n) (cdr args)))))))))))
379
380 (define (compile-opt-lambda body nreq rest? nopt ninits unbound make-alt)
381 (lambda (env)
382 (define alt (and make-alt (make-alt env)))
383 (lambda args
384 (let ((nargs (length args)))
385 (cond
386 ((or (< nargs nreq) (and (not rest?) (> nargs (+ nreq nopt))))
387 (if alt
388 (apply alt args)
389 ((scm-error 'wrong-number-of-args
390 "eval" "Wrong number of arguments"
391 '() #f))))
392 (else
393 (let* ((nvals (+ nreq (if rest? 1 0) ninits))
394 (env (make-env nvals unbound env)))
395 (define (bind-req args)
396 (let lp ((i 0) (args args))
397 (cond
398 ((< i nreq)
399 ;; Bind required arguments.
400 (env-set! env 0 i (car args))
401 (lp (1+ i) (cdr args)))
402 (else
403 (bind-opt args)))))
404 (define (bind-opt args)
405 (let lp ((i nreq) (args args))
406 (cond
407 ((and (< i (+ nreq nopt)) (< i nargs))
408 (env-set! env 0 i (car args))
409 (lp (1+ i) (cdr args)))
410 (else
411 (bind-rest args)))))
412 (define (bind-rest args)
413 (when rest?
414 (env-set! env 0 (+ nreq nopt) args))
415 (body env))
416 (bind-req args))))))))
417
418 (define (compile-kw-lambda body nreq rest? nopt kw ninits unbound make-alt)
419 (define allow-other-keys? (car kw))
420 (define keywords (cdr kw))
421 (lambda (env)
422 (define alt (and make-alt (make-alt env)))
423 (lambda args
424 (define (npositional args)
425 (let lp ((n 0) (args args))
426 (if (or (null? args)
427 (and (>= n nreq) (keyword? (car args))))
428 n
429 (lp (1+ n) (cdr args)))))
430 (let ((nargs (length args)))
431 (cond
432 ((or (< nargs nreq)
433 (and alt (not rest?) (> (npositional args) (+ nreq nopt))))
434 (if alt
435 (apply alt args)
436 ((scm-error 'wrong-number-of-args
437 "eval" "Wrong number of arguments"
438 '() #f))))
439 (else
440 (let* ((nvals (+ nreq (if rest? 1 0) ninits))
441 (env (make-env nvals unbound env)))
442 (define (bind-req args)
443 (let lp ((i 0) (args args))
444 (cond
445 ((< i nreq)
446 ;; Bind required arguments.
447 (env-set! env 0 i (car args))
448 (lp (1+ i) (cdr args)))
449 (else
450 (bind-opt args)))))
451 (define (bind-opt args)
452 (let lp ((i nreq) (args args))
453 (cond
454 ((and (< i (+ nreq nopt)) (< i nargs)
455 (not (keyword? (car args))))
456 (env-set! env 0 i (car args))
457 (lp (1+ i) (cdr args)))
458 (else
459 (bind-rest args)))))
460 (define (bind-rest args)
461 (when rest?
462 (env-set! env 0 (+ nreq nopt) args))
463 (bind-kw args))
464 (define (bind-kw args)
465 (let lp ((args args))
466 (cond
467 ((and (pair? args) (pair? (cdr args))
468 (keyword? (car args)))
469 (let ((kw-pair (assq (car args) keywords))
470 (v (cadr args)))
471 (if kw-pair
472 ;; Found a known keyword; set its value.
473 (env-set! env 0 (cdr kw-pair) v)
474 ;; Unknown keyword.
475 (if (not allow-other-keys?)
476 ((scm-error
477 'keyword-argument-error
478 "eval" "Unrecognized keyword"
479 '() (list (car args))))))
480 (lp (cddr args))))
481 ((pair? args)
482 (if rest?
483 ;; Be lenient parsing rest args.
484 (lp (cdr args))
485 ((scm-error 'keyword-argument-error
486 "eval" "Invalid keyword"
487 '() (list (car args))))))
488 (else
489 (body env)))))
490 (bind-req args))))))))
491
492 (define (compute-arity alt nreq rest? nopt kw)
493 (let lp ((alt alt) (nreq nreq) (nopt nopt) (rest? rest?))
494 (if (not alt)
495 (let ((arglist (list nreq
496 nopt
497 (if kw (cdr kw) '())
498 (and kw (car kw))
499 (and rest? '_))))
500 (values arglist nreq nopt rest?))
501 (let* ((spec (cddr alt))
502 (nreq* (car spec))
503 (rest?* (if (null? (cdr spec)) #f (cadr spec)))
504 (tail (and (pair? (cdr spec)) (pair? (cddr spec)) (cddr spec)))
505 (nopt* (if tail (car tail) 0))
506 (alt* (and tail (car (cddddr tail)))))
507 (if (or (< nreq* nreq)
508 (and (= nreq* nreq)
509 (if rest?
510 (and rest?* (> nopt* nopt))
511 (or rest?* (> nopt* nopt)))))
512 (lp alt* nreq* nopt* rest?*)
513 (lp alt* nreq nopt rest?))))))
514
515 (define (compile-general-lambda body nreq rest? nopt kw ninits unbound alt)
516 (call-with-values
517 (lambda ()
518 (compute-arity alt nreq rest? nopt kw))
519 (lambda (arglist min-nreq min-nopt min-rest?)
520 (define make-alt
521 (match alt
522 (#f #f)
523 ((body meta nreq . tail)
524 (compile-lambda body meta nreq tail))))
525 (define make-closure
526 (if kw
527 (compile-kw-lambda body nreq rest? nopt kw ninits unbound make-alt)
528 (compile-opt-lambda body nreq rest? nopt ninits unbound make-alt)))
529 (lambda (env)
530 (let ((proc (make-closure env)))
531 (set-procedure-property! proc 'arglist arglist)
532 (set-procedure-minimum-arity! proc min-nreq min-nopt min-rest?)
533 proc)))))
534
535 (define (compile-lambda body meta nreq tail)
536 (define (set-procedure-meta meta proc)
537 (match meta
538 (() proc)
539 (((prop . val) . meta)
540 (set-procedure-meta meta
541 (lambda (env)
542 (let ((proc (proc env)))
543 (set-procedure-property! proc prop val)
544 proc))))))
d76d80d2 545 (let ((body (lazy (env) (compile body))))
95de4f52
AW
546 (set-procedure-meta
547 meta
548 (match tail
549 (() (compile-fixed-lambda body nreq))
550 ((rest? . tail)
551 (match tail
552 (() (compile-rest-lambda body nreq rest?))
553 ((nopt kw ninits unbound alt)
554 (compile-general-lambda body nreq rest? nopt kw
555 ninits unbound alt))))))))
556
557 (define (compile-capture-env locs body)
558 (let ((body (compile body)))
559 (lambda (env)
560 (let* ((len (vector-length locs))
561 (new-env (make-env len #f (env-toplevel env))))
562 (let lp ((n 0))
563 (when (< n len)
564 (match (vector-ref locs n)
565 ((depth . width)
566 (env-set! new-env 0 n (env-ref env depth width))))
567 (lp (1+ n))))
568 (body new-env)))))
569
570 (define (compile-seq head tail)
571 (let ((head (compile head))
572 (tail (compile tail)))
573 (lambda (env)
574 (head env)
575 (tail env))))
576
577 (define (compile-box-set! box val)
578 (let ((box (compile box))
579 (val (compile val)))
580 (lambda (env)
581 (let ((val (val env)))
582 (variable-set! (box env) val)))))
583
584 (define (compile-lexical-set! depth width x)
585 (let ((x (compile x)))
586 (lambda (env)
587 (env-set! env depth width (x env)))))
588
589 (define (compile-call-with-values producer consumer)
590 (let ((producer (compile producer))
591 (consumer (compile consumer)))
592 (lambda (env)
593 (call-with-values (producer env)
594 (consumer env)))))
595
596 (define (compile-apply f args)
597 (let ((f (compile f))
598 (args (compile args)))
599 (lambda (env)
600 (apply (f env) (args env)))))
601
602 (define (compile-capture-module x)
603 (let ((x (compile x)))
604 (lambda (env)
605 (x (current-module)))))
606
607 (define (compile-call-with-prompt tag thunk handler)
608 (let ((tag (compile tag))
609 (thunk (compile thunk))
610 (handler (compile handler)))
611 (lambda (env)
612 (call-with-prompt (tag env) (thunk env) (handler env)))))
613
614 (define (compile-call/cc proc)
615 (let ((proc (compile proc)))
616 (lambda (env)
617 (call/cc (proc env)))))
618
619 (define (compile exp)
620 (match exp
621 ((,(typecode lexical-ref) depth . width)
622 (compile-lexical-ref depth width))
623
eb037656
AW
624 ((,(typecode call) f . args)
625 (compile-call f args))
95de4f52
AW
626
627 ((,(typecode box-ref) . box)
d76d80d2 628 (lazy (env) (compile-box-ref env box)))
5161a3c0 629
d76d80d2
AW
630 ((,(typecode resolve) . loc)
631 (lazy (env) (compile-resolve env loc)))
5161a3c0 632
95de4f52
AW
633 ((,(typecode if) test consequent . alternate)
634 (compile-if test consequent alternate))
21ec0bd9 635
95de4f52
AW
636 ((,(typecode quote) . x)
637 (compile-quote x))
638
639 ((,(typecode let) inits . body)
640 (compile-let inits body))
641
642 ((,(typecode lambda) body meta nreq . tail)
643 (compile-lambda body meta nreq tail))
644
645 ((,(typecode capture-env) locs . body)
646 (compile-capture-env locs body))
647
648 ((,(typecode seq) head . tail)
649 (compile-seq head tail))
650
651 ((,(typecode box-set!) box . val)
652 (compile-box-set! box val))
653
654 ((,(typecode lexical-set!) (depth . width) . x)
655 (compile-lexical-set! depth width x))
656
657 ((,(typecode call-with-values) producer . consumer)
658 (compile-call-with-values producer consumer))
659
660 ((,(typecode apply) f args)
661 (compile-apply f args))
662
663 ((,(typecode capture-module) . x)
664 (compile-capture-module x))
665
666 ((,(typecode call-with-prompt) tag thunk . handler)
667 (compile-call-with-prompt tag thunk handler))
5161a3c0 668
95de4f52
AW
669 ((,(typecode call/cc) . proc)
670 (compile-call/cc proc))))
671
d76d80d2
AW
672 (let ((eval (compile
673 (memoize-expression
95de4f52
AW
674 (if (macroexpanded? exp)
675 exp
676 ((module-transformer (current-module)) exp)))))
677 (env #f))
d76d80d2 678 (eval env)))