Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / module / language / elisp / compile-tree-il.scm
CommitLineData
dfbc6e9d 1;;; Guile Emacs Lisp
51248e6e 2
7081d4f9 3;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
51248e6e
DK
4
5;; This program is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
e4257331 7;; the Free Software Foundation; either version 3, or (at your option)
51248e6e 8;; any later version.
abcf4a9e 9;;
51248e6e
DK
10;; This program 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
13;; GNU General Public License for more details.
abcf4a9e 14;;
51248e6e
DK
15;; You should have received a copy of the GNU General Public License
16;; along with this program; see the file COPYING. If not, write to
17;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18;; Boston, MA 02111-1307, USA.
19
20;;; Code:
21
22(define-module (language elisp compile-tree-il)
5d221ca3 23 #:use-module (language elisp bindings)
44ae163d 24 #:use-module (language elisp runtime)
51248e6e
DK
25 #:use-module (language tree-il)
26 #:use-module (system base pmatch)
74c009da 27 #:use-module (system base compile)
dfbc6e9d 28 #:use-module (srfi srfi-1)
eda83f0a
BT
29 #:use-module (srfi srfi-8)
30 #:use-module (srfi srfi-11)
31 #:use-module (srfi srfi-26)
44ae163d
BT
32 #:export (compile-tree-il
33 compile-progn
34 compile-if
35 compile-defconst
36 compile-defvar
37 compile-setq
38 compile-let
39 compile-lexical-let
40 compile-flet
41 compile-let*
42 compile-lexical-let*
43 compile-flet*
44 compile-without-void-checks
45 compile-with-always-lexical
46 compile-guile-ref
47 compile-guile-primitive
48 compile-while
49 compile-function
50 compile-defmacro
51 compile-defun
0dbfdeef 52 #{compile-`}#
44ae163d 53 compile-quote))
51248e6e 54
c983a199
BT
55;;; Certain common parameters (like the bindings data structure or
56;;; compiler options) are not always passed around but accessed using
57;;; fluids to simulate dynamic binding (hey, this is about elisp).
a90d9c85 58
c983a199
BT
59;;; The bindings data structure to keep track of symbol binding related
60;;; data.
abcf4a9e 61
a90d9c85
DK
62(define bindings-data (make-fluid))
63
c983a199 64;;; Store for which symbols (or all/none) void checks are disabled.
abcf4a9e 65
a0899974 66(define disable-void-check (make-fluid))
a90d9c85 67
c983a199
BT
68;;; Store which symbols (or all/none) should always be bound lexically,
69;;; even with ordinary let and as lambda arguments.
c808c926 70
abcf4a9e 71(define always-lexical (make-fluid))
a90d9c85 72
c983a199
BT
73;;; Find the source properties of some parsed expression if there are
74;;; any associated with it.
51248e6e
DK
75
76(define (location x)
77 (and (pair? x)
78 (let ((props (source-properties x)))
79 (and (not (null? props))
80 props))))
81
c983a199 82;;; Values to use for Elisp's nil and t.
4530432e 83
f4e5e411
BT
84(define (nil-value loc)
85 (make-const loc (@ (language elisp runtime) nil-value)))
4530432e 86
f4e5e411
BT
87(define (t-value loc)
88 (make-const loc (@ (language elisp runtime) t-value)))
4530432e 89
c983a199 90;;; Modules that contain the value and function slot bindings.
344927c3
DK
91
92(define runtime '(language elisp runtime))
abcf4a9e 93
37099846 94(define value-slot (@ (language elisp runtime) value-slot-module))
344927c3 95
abcf4a9e 96(define function-slot (@ (language elisp runtime) function-slot-module))
344927c3 97
c983a199
BT
98;;; The backquoting works the same as quasiquotes in Scheme, but the
99;;; forms are named differently; to make easy adaptions, we define these
100;;; predicates checking for a symbol being the car of an
101;;; unquote/unquote-splicing/backquote form.
9b5ff6a6 102
9b5ff6a6 103(define (unquote? sym)
0dbfdeef 104 (and (symbol? sym) (eq? sym '#{,}#)))
9b5ff6a6
DK
105
106(define (unquote-splicing? sym)
0dbfdeef 107 (and (symbol? sym) (eq? sym '#{,@}#)))
9b5ff6a6 108
c983a199 109;;; Build a call to a primitive procedure nicely.
50abfe76
DK
110
111(define (call-primitive loc sym . args)
a881a4ae 112 (make-primcall loc sym args))
50abfe76 113
c983a199
BT
114;;; Error reporting routine for syntax/compilation problems or build
115;;; code for a runtime-error output.
344927c3
DK
116
117(define (report-error loc . args)
118 (apply error args))
119
50abfe76 120(define (runtime-error loc msg . args)
a881a4ae
AW
121 (make-primcall loc 'error
122 (cons (make-const loc msg) args)))
50abfe76 123
c983a199
BT
124;;; Generate code to ensure a global symbol is there for further use of
125;;; a given symbol. In general during the compilation, those needed are
126;;; only tracked with the bindings data structure. Afterwards, however,
127;;; for all those needed symbols the globals are really generated with
128;;; this routine.
344927c3 129
1b1195f2 130(define (generate-ensure-global loc sym module)
7081d4f9
AW
131 (make-call loc
132 (make-module-ref loc runtime 'ensure-fluid! #t)
133 (list (make-const loc module)
134 (make-const loc sym))))
f28de791 135
2ce5e740 136(define (ensuring-globals loc bindings body)
6fc3eae4 137 (list->seq
2ce5e740
BT
138 loc
139 `(,@(map-globals-needed (fluid-ref bindings)
140 (lambda (mod sym)
141 (generate-ensure-global loc sym mod)))
142 ,body)))
143
c983a199
BT
144;;; Build a construct that establishes dynamic bindings for certain
145;;; variables. We may want to choose between binding with fluids and
146;;; with-fluids* and using just ordinary module symbols and
147;;; setting/reverting their values with a dynamic-wind.
1b1195f2
DK
148
149(define (let-dynamic loc syms module vals body)
f4e5e411
BT
150 (call-primitive
151 loc
152 'with-fluids*
a881a4ae
AW
153 (make-primcall loc 'list
154 (map (lambda (sym)
155 (make-module-ref loc module sym #t))
156 syms))
157 (make-primcall loc 'list vals)
f4e5e411
BT
158 (make-lambda loc
159 '()
160 (make-lambda-case #f '() #f #f #f '() '() body #f))))
1b1195f2 161
c983a199
BT
162;;; Handle access to a variable (reference/setting) correctly depending
163;;; on whether it is currently lexically or dynamically bound. lexical
164;;; access is done only for references to the value-slot module!
a6a5cf03 165
c6920dc8
BT
166(define (access-variable loc
167 sym
168 module
169 handle-global
170 handle-lexical
171 handle-dynamic)
a6a5cf03 172 (let ((lexical (get-lexical-binding (fluid-ref bindings-data) sym)))
c6920dc8
BT
173 (cond
174 (lexical (handle-lexical lexical))
175 ((equal? module function-slot) (handle-global))
176 (else (handle-dynamic)))))
a6a5cf03 177
c983a199
BT
178;;; Generate code to reference a variable. For references in the
179;;; value-slot module, we may want to generate a lexical reference
180;;; instead if the variable has a lexical binding.
344927c3 181
a90d9c85 182(define (reference-variable loc sym module)
f4e5e411
BT
183 (access-variable
184 loc
185 sym
186 module
c6920dc8 187 (lambda () (make-module-ref loc module sym #t))
f4e5e411
BT
188 (lambda (lexical) (make-lexical-ref loc lexical lexical))
189 (lambda ()
190 (mark-global-needed! (fluid-ref bindings-data) sym module)
191 (call-primitive loc
192 'fluid-ref
193 (make-module-ref loc module sym #t)))))
344927c3 194
c983a199
BT
195;;; Generate code to set a variable. Just as with reference-variable, in
196;;; case of a reference to value-slot, we want to generate a lexical set
197;;; when the variable has a lexical binding.
344927c3 198
a90d9c85 199(define (set-variable! loc sym module value)
f4e5e411
BT
200 (access-variable
201 loc
202 sym
203 module
c6920dc8 204 (lambda ()
7081d4f9 205 (make-call
c6920dc8
BT
206 loc
207 (make-module-ref loc runtime 'set-variable! #t)
208 (list (make-const loc module) (make-const loc sym) value)))
f4e5e411
BT
209 (lambda (lexical) (make-lexical-set loc lexical lexical value))
210 (lambda ()
211 (mark-global-needed! (fluid-ref bindings-data) sym module)
212 (call-primitive loc
213 'fluid-set!
214 (make-module-ref loc module sym #t)
215 value))))
344927c3 216
c983a199
BT
217;;; Process the bindings part of a let or let* expression; that is,
218;;; check for correctness and bring it to the form ((sym1 . val1) (sym2
219;;; . val2) ...).
3a4b8635
DK
220
221(define (process-let-bindings loc bindings)
f4e5e411
BT
222 (map
223 (lambda (b)
224 (if (symbol? b)
225 (cons b 'nil)
226 (if (or (not (list? b))
227 (not (= (length b) 2)))
228 (report-error
229 loc
230 "expected symbol or list of 2 elements in let")
3a4b8635 231 (if (not (symbol? (car b)))
f4e5e411
BT
232 (report-error loc "expected symbol in let")
233 (cons (car b) (cadr b))))))
234 bindings))
3a4b8635 235
c983a199
BT
236;;; Split the let bindings into a list to be done lexically and one
237;;; dynamically. A symbol will be bound lexically if and only if: We're
238;;; processing a lexical-let (i.e. module is 'lexical), OR we're
239;;; processing a value-slot binding AND the symbol is already lexically
c6920dc8
BT
240;;; bound or is always lexical, OR we're processing a function-slot
241;;; binding.
a6a5cf03
DK
242
243(define (bind-lexically? sym module)
244 (or (eq? module 'lexical)
c6920dc8 245 (eq? module function-slot)
a6a5cf03 246 (and (equal? module value-slot)
c808c926
DK
247 (let ((always (fluid-ref always-lexical)))
248 (or (eq? always 'all)
249 (memq sym always)
250 (get-lexical-binding (fluid-ref bindings-data) sym))))))
a6a5cf03
DK
251
252(define (split-let-bindings bindings module)
253 (let iterate ((tail bindings)
254 (lexical '())
255 (dynamic '()))
256 (if (null? tail)
f4e5e411
BT
257 (values (reverse lexical) (reverse dynamic))
258 (if (bind-lexically? (caar tail) module)
259 (iterate (cdr tail) (cons (car tail) lexical) dynamic)
260 (iterate (cdr tail) lexical (cons (car tail) dynamic))))))
a6a5cf03 261
c983a199
BT
262;;; Compile let and let* expressions. The code here is used both for
263;;; let/let* and flet/flet*, just with a different bindings module.
264;;;
265;;; A special module value 'lexical means that we're doing a lexical-let
266;;; instead and the bindings should not be saved to globals at all but
267;;; be done with the lexical framework instead.
a6a5cf03 268
c983a199
BT
269;;; Let is done with a single call to let-dynamic binding them locally
270;;; to new values all "at once". If there is at least one variable to
271;;; bind lexically among the bindings, we first do a let for all of them
272;;; to evaluate all values before any bindings take place, and then call
273;;; let-dynamic for the variables to bind dynamically.
abcf4a9e 274
a6a5cf03
DK
275(define (generate-let loc module bindings body)
276 (let ((bind (process-let-bindings loc bindings)))
277 (call-with-values
f4e5e411 278 (lambda () (split-let-bindings bind module))
a6a5cf03
DK
279 (lambda (lexical dynamic)
280 (for-each (lambda (sym)
f4e5e411
BT
281 (mark-global-needed! (fluid-ref bindings-data)
282 sym
283 module))
a6a5cf03 284 (map car dynamic))
1b1195f2 285 (let ((make-values (lambda (for)
f4e5e411 286 (map (lambda (el) (compile-expr (cdr el)))
a6a5cf03
DK
287 for)))
288 (make-body (lambda ()
6fc3eae4 289 (list->seq loc (map compile-expr body)))))
a6a5cf03 290 (if (null? lexical)
f4e5e411
BT
291 (let-dynamic loc (map car dynamic) module
292 (make-values dynamic) (make-body))
293 (let* ((lexical-syms (map (lambda (el) (gensym)) lexical))
294 (dynamic-syms (map (lambda (el) (gensym)) dynamic))
295 (all-syms (append lexical-syms dynamic-syms))
296 (vals (append (make-values lexical)
297 (make-values dynamic))))
298 (make-let loc
299 all-syms
300 all-syms
301 vals
302 (with-lexical-bindings
303 (fluid-ref bindings-data)
304 (map car lexical) lexical-syms
305 (lambda ()
306 (if (null? dynamic)
307 (make-body)
308 (let-dynamic loc
309 (map car dynamic)
310 module
311 (map
312 (lambda (sym)
313 (make-lexical-ref loc
314 sym
315 sym))
316 dynamic-syms)
317 (make-body)))))))))))))
a6a5cf03 318
c983a199
BT
319;;; Let* is compiled to a cascaded set of "small lets" for each binding
320;;; in turn so that each one already sees the preceding bindings.
abcf4a9e 321
a6a5cf03
DK
322(define (generate-let* loc module bindings body)
323 (let ((bind (process-let-bindings loc bindings)))
324 (begin
325 (for-each (lambda (sym)
326 (if (not (bind-lexically? sym module))
f4e5e411
BT
327 (mark-global-needed! (fluid-ref bindings-data)
328 sym
329 module)))
a6a5cf03
DK
330 (map car bind))
331 (let iterate ((tail bind))
332 (if (null? tail)
6fc3eae4 333 (list->seq loc (map compile-expr body))
f4e5e411
BT
334 (let ((sym (caar tail))
335 (value (compile-expr (cdar tail))))
336 (if (bind-lexically? sym module)
337 (let ((target (gensym)))
338 (make-let loc
339 `(,target)
340 `(,target)
341 `(,value)
342 (with-lexical-bindings
343 (fluid-ref bindings-data)
344 `(,sym)
345 `(,target)
346 (lambda () (iterate (cdr tail))))))
347 (let-dynamic loc
348 `(,(caar tail))
349 module
350 `(,value)
351 (iterate (cdr tail))))))))))
a6a5cf03 352
c983a199
BT
353;;; Split the argument list of a lambda expression into required,
354;;; optional and rest arguments and also check it is actually valid.
355;;; Additionally, we create a list of all "local variables" (that is,
356;;; required, optional and rest arguments together) and also this one
357;;; split into those to be bound lexically and dynamically. Returned is
358;;; as multiple values: required optional rest lexical dynamic
dfbc6e9d
DK
359
360(define (bind-arg-lexical? arg)
361 (let ((always (fluid-ref always-lexical)))
362 (or (eq? always 'all)
363 (memq arg always))))
50abfe76
DK
364
365(define (split-lambda-arguments loc args)
366 (let iterate ((tail args)
367 (mode 'required)
368 (required '())
dfbc6e9d
DK
369 (optional '())
370 (lexical '())
371 (dynamic '()))
50abfe76 372 (cond
f4e5e411
BT
373 ((null? tail)
374 (let ((final-required (reverse required))
375 (final-optional (reverse optional))
376 (final-lexical (reverse lexical))
377 (final-dynamic (reverse dynamic)))
378 (values final-required
379 final-optional
380 #f
381 final-lexical
382 final-dynamic)))
383 ((and (eq? mode 'required)
384 (eq? (car tail) '&optional))
385 (iterate (cdr tail) 'optional required optional lexical dynamic))
386 ((eq? (car tail) '&rest)
387 (if (or (null? (cdr tail))
388 (not (null? (cddr tail))))
389 (report-error loc "expected exactly one symbol after &rest")
390 (let* ((rest (cadr tail))
391 (rest-lexical (bind-arg-lexical? rest))
392 (final-required (reverse required))
393 (final-optional (reverse optional))
394 (final-lexical (reverse (if rest-lexical
395 (cons rest lexical)
396 lexical)))
397 (final-dynamic (reverse (if rest-lexical
398 dynamic
399 (cons rest dynamic)))))
400 (values final-required
401 final-optional
402 rest
403 final-lexical
404 final-dynamic))))
405 (else
406 (if (not (symbol? (car tail)))
407 (report-error loc
408 "expected symbol in argument list, got"
409 (car tail))
dfbc6e9d
DK
410 (let* ((arg (car tail))
411 (bind-lexical (bind-arg-lexical? arg))
412 (new-lexical (if bind-lexical
f4e5e411
BT
413 (cons arg lexical)
414 lexical))
dfbc6e9d 415 (new-dynamic (if bind-lexical
f4e5e411
BT
416 dynamic
417 (cons arg dynamic))))
dfbc6e9d
DK
418 (case mode
419 ((required) (iterate (cdr tail) mode
420 (cons arg required) optional
421 new-lexical new-dynamic))
422 ((optional) (iterate (cdr tail) mode
423 required (cons arg optional)
424 new-lexical new-dynamic))
425 (else
f4e5e411
BT
426 (error "invalid mode in split-lambda-arguments"
427 mode)))))))))
50abfe76 428
eda83f0a
BT
429;;; Compile a lambda expression. One thing we have to be aware of is
430;;; that lambda arguments are usually dynamically bound, even when a
431;;; lexical binding is intact for a symbol. For symbols that are marked
432;;; as 'always lexical,' however, we lexically bind here as well, and
433;;; thus we get them out of the let-dynamic call and register a lexical
434;;; binding for them (the lexical target variable is already there,
435;;; namely the real lambda argument from TreeIL).
50abfe76 436
a90d9c85 437(define (compile-lambda loc args body)
de9f26b5 438 (if (not (list? args))
f4e5e411 439 (report-error loc "expected list for argument-list" args))
de9f26b5 440 (if (null? body)
eda83f0a
BT
441 (report-error loc "function body must not be empty"))
442 (receive (required optional rest lexical dynamic)
443 (split-lambda-arguments loc args)
444 (define (process-args args)
445 (define (find-pairs pairs filter)
446 (lset-intersection (lambda (name+sym x)
447 (eq? (car name+sym) x))
448 pairs
449 filter))
450 (let* ((syms (map (lambda (x) (gensym)) args))
451 (pairs (map cons args syms))
452 (lexical-pairs (find-pairs pairs lexical))
453 (dynamic-pairs (find-pairs pairs dynamic)))
454 (values syms pairs lexical-pairs dynamic-pairs)))
455 (let*-values (((required-syms
456 required-pairs
457 required-lex-pairs
458 required-dyn-pairs)
459 (process-args required))
460 ((optional-syms
461 optional-pairs
462 optional-lex-pairs
463 optional-dyn-pairs)
464 (process-args optional))
465 ((rest-syms rest-pairs rest-lex-pairs rest-dyn-pairs)
466 (process-args (if rest (list rest) '())))
467 ((the-rest-sym) (if rest (car rest-syms) #f))
468 ((all-syms) (append required-syms
469 optional-syms
470 rest-syms))
471 ((all-lex-pairs) (append required-lex-pairs
472 optional-lex-pairs
473 rest-lex-pairs))
474 ((all-dyn-pairs) (append required-dyn-pairs
475 optional-dyn-pairs
476 rest-dyn-pairs)))
477 (for-each (lambda (sym)
478 (mark-global-needed! (fluid-ref bindings-data)
479 sym
480 value-slot))
481 dynamic)
482 (with-dynamic-bindings
483 (fluid-ref bindings-data)
484 dynamic
485 (lambda ()
486 (with-lexical-bindings
487 (fluid-ref bindings-data)
488 (map car all-lex-pairs)
489 (map cdr all-lex-pairs)
490 (lambda ()
491 (make-lambda
492 loc
493 '()
494 (make-lambda-case
495 #f
496 required
497 optional
498 rest
499 #f
500 (map (lambda (x) (nil-value loc)) optional)
501 all-syms
502 (let ((compiled-body
6fc3eae4
AW
503 (list->seq loc (map compile-expr body))))
504 (make-seq
f4e5e411 505 loc
6fc3eae4
AW
506 (if rest
507 (make-conditional
508 loc
509 (call-primitive loc
510 'null?
511 (make-lexical-ref loc
512 rest
513 the-rest-sym))
514 (make-lexical-set loc
515 rest
516 the-rest-sym
517 (nil-value loc))
eda83f0a 518 (make-void loc))
6fc3eae4
AW
519 (make-void loc))
520 (if (null? dynamic)
521 compiled-body
522 (let-dynamic loc
523 dynamic
524 value-slot
525 (map (lambda (name-sym)
526 (make-lexical-ref
527 loc
528 (car name-sym)
529 (cdr name-sym)))
530 all-dyn-pairs)
531 compiled-body))))
eda83f0a 532 #f)))))))))
50abfe76 533
c983a199
BT
534;;; Handle the common part of defconst and defvar, that is, checking for
535;;; a correct doc string and arguments as well as maybe in the future
536;;; handling the docstring somehow.
de9f26b5
DK
537
538(define (handle-var-def loc sym doc)
539 (cond
f4e5e411
BT
540 ((not (symbol? sym)) (report-error loc "expected symbol, got" sym))
541 ((> (length doc) 1) (report-error loc "too many arguments to defvar"))
542 ((and (not (null? doc)) (not (string? (car doc))))
543 (report-error loc "expected string as third argument of defvar, got"
544 (car doc)))
545 ;; TODO: Handle doc string if present.
546 (else #t)))
de9f26b5 547
44ae163d 548;;; Handle macro and special operator bindings.
74c009da 549
44ae163d 550(define (find-operator sym type)
8295b7c4
BT
551 (and
552 (symbol? sym)
553 (module-defined? (resolve-interface function-slot) sym)
44ae163d
BT
554 (let* ((op (module-ref (resolve-module function-slot) sym))
555 (op (if (fluid? op) (fluid-ref op) op)))
556 (if (and (pair? op) (eq? (car op) type))
557 (cdr op)
558 #f))))
74c009da 559
c983a199 560;;; See if a (backquoted) expression contains any unquotes.
9b5ff6a6
DK
561
562(define (contains-unquotes? expr)
563 (if (pair? expr)
f4e5e411
BT
564 (if (or (unquote? (car expr)) (unquote-splicing? (car expr)))
565 #t
566 (or (contains-unquotes? (car expr))
567 (contains-unquotes? (cdr expr))))
568 #f))
9b5ff6a6 569
c983a199
BT
570;;; Process a backquoted expression by building up the needed
571;;; cons/append calls. For splicing, it is assumed that the expression
572;;; spliced in evaluates to a list. The emacs manual does not really
573;;; state either it has to or what to do if it does not, but Scheme
574;;; explicitly forbids it and this seems reasonable also for elisp.
9b5ff6a6
DK
575
576(define (unquote-cell? expr)
577 (and (list? expr) (= (length expr) 2) (unquote? (car expr))))
abcf4a9e 578
9b5ff6a6
DK
579(define (unquote-splicing-cell? expr)
580 (and (list? expr) (= (length expr) 2) (unquote-splicing? (car expr))))
581
a90d9c85 582(define (process-backquote loc expr)
9b5ff6a6 583 (if (contains-unquotes? expr)
f4e5e411
BT
584 (if (pair? expr)
585 (if (or (unquote-cell? expr) (unquote-splicing-cell? expr))
586 (compile-expr (cadr expr))
587 (let* ((head (car expr))
588 (processed-tail (process-backquote loc (cdr expr)))
589 (head-is-list-2 (and (list? head)
590 (= (length head) 2)))
591 (head-unquote (and head-is-list-2
592 (unquote? (car head))))
593 (head-unquote-splicing (and head-is-list-2
594 (unquote-splicing?
595 (car head)))))
596 (if head-unquote-splicing
597 (call-primitive loc
598 'append
599 (compile-expr (cadr head))
600 processed-tail)
601 (call-primitive loc 'cons
602 (if head-unquote
603 (compile-expr (cadr head))
604 (process-backquote loc head))
605 processed-tail))))
606 (report-error loc
607 "non-pair expression contains unquotes"
608 expr))
609 (make-const loc expr)))
9b5ff6a6 610
c983a199
BT
611;;; Temporarily update a list of symbols that are handled specially
612;;; (disabled void check or always lexical) for compiling body. We need
613;;; to handle special cases for already all / set to all and the like.
c808c926
DK
614
615(define (with-added-symbols loc fluid syms body)
616 (if (null? body)
f4e5e411 617 (report-error loc "symbol-list construct has empty body"))
c808c926
DK
618 (if (not (or (eq? syms 'all)
619 (and (list? syms) (and-map symbol? syms))))
f4e5e411 620 (report-error loc "invalid symbol list" syms))
c808c926
DK
621 (let ((old (fluid-ref fluid))
622 (make-body (lambda ()
6fc3eae4 623 (list->seq loc (map compile-expr body)))))
c808c926 624 (if (eq? old 'all)
f4e5e411
BT
625 (make-body)
626 (let ((new (if (eq? syms 'all)
627 'all
628 (append syms old))))
629 (with-fluids ((fluid new))
630 (make-body))))))
c808c926 631
44ae163d 632;;; Special operators
abcf4a9e 633
44ae163d 634(defspecial progn (loc args)
6fc3eae4 635 (list->seq loc (map compile-expr args)))
abcf4a9e 636
44ae163d
BT
637(defspecial if (loc args)
638 (pmatch args
639 ((,cond ,then . ,else)
f4e5e411 640 (make-conditional loc
44ae163d
BT
641 (compile-expr cond)
642 (compile-expr then)
643 (if (null? else)
644 (nil-value loc)
6fc3eae4 645 (list->seq loc (map compile-expr else)))))))
44ae163d
BT
646
647(defspecial defconst (loc args)
648 (pmatch args
649 ((,sym ,value . ,doc)
de9f26b5 650 (if (handle-var-def loc sym doc)
6fc3eae4
AW
651 (make-seq loc
652 (set-variable! loc
653 sym
654 value-slot
655 (compile-expr value))
656 (make-const loc sym))))))
de9f26b5 657
44ae163d
BT
658(defspecial defvar (loc args)
659 (pmatch args
660 ((,sym) (make-const loc sym))
661 ((,sym ,value . ,doc)
de9f26b5 662 (if (handle-var-def loc sym doc)
6fc3eae4 663 (make-seq
f4e5e411 664 loc
6fc3eae4
AW
665 (make-conditional
666 loc
3f70b2dc
BT
667 (make-conditional
668 loc
6fc3eae4 669 (call-primitive
3f70b2dc 670 loc
6fc3eae4 671 'module-bound?
3f70b2dc 672 (call-primitive loc
6fc3eae4
AW
673 'resolve-interface
674 (make-const loc value-slot))
675 (make-const loc sym))
676 (call-primitive loc
677 'fluid-bound?
678 (make-module-ref loc value-slot sym #t))
679 (make-const loc #f))
680 (make-void loc)
681 (set-variable! loc sym value-slot (compile-expr value)))
682 (make-const loc sym))))))
44ae163d
BT
683
684(defspecial setq (loc args)
f5742cf0
BT
685 (define (car* x) (if (null? x) '() (car x)))
686 (define (cdr* x) (if (null? x) '() (cdr x)))
687 (define (cadr* x) (car* (cdr* x)))
688 (define (cddr* x) (cdr* (cdr* x)))
6fc3eae4 689 (list->seq
44ae163d 690 loc
f5742cf0
BT
691 (let loop ((args args) (last (nil-value loc)))
692 (if (null? args)
693 (list last)
694 (let ((sym (car args))
695 (val (compile-expr (cadr* args))))
696 (if (not (symbol? sym))
697 (report-error loc "expected symbol in setq")
698 (cons
699 (set-variable! loc sym value-slot val)
700 (loop (cddr* args)
701 (reference-variable loc sym value-slot)))))))))
702
44ae163d
BT
703(defspecial let (loc args)
704 (pmatch args
705 ((,bindings . ,body)
706 (generate-let loc value-slot bindings body))))
707
708(defspecial lexical-let (loc args)
709 (pmatch args
710 ((,bindings . ,body)
711 (generate-let loc 'lexical bindings body))))
712
713(defspecial flet (loc args)
714 (pmatch args
715 ((,bindings . ,body)
716 (generate-let loc function-slot bindings body))))
717
718(defspecial let* (loc args)
719 (pmatch args
720 ((,bindings . ,body)
721 (generate-let* loc value-slot bindings body))))
722
723(defspecial lexical-let* (loc args)
724 (pmatch args
725 ((,bindings . ,body)
726 (generate-let* loc 'lexical bindings body))))
727
728(defspecial flet* (loc args)
729 (pmatch args
730 ((,bindings . ,body)
731 (generate-let* loc function-slot bindings body))))
732
3f70b2dc
BT
733;;; Temporarily set symbols as always lexical only for the lexical scope
734;;; of a construct.
44ae163d
BT
735
736(defspecial with-always-lexical (loc args)
737 (pmatch args
738 ((,syms . ,body)
739 (with-added-symbols loc always-lexical syms body))))
740
741;;; guile-ref allows building TreeIL's module references from within
742;;; elisp as a way to access data within the Guile universe. The module
743;;; and symbol referenced are static values, just like (@ module symbol)
744;;; does!
745
746(defspecial guile-ref (loc args)
747 (pmatch args
748 ((,module ,sym) (guard (and (list? module) (symbol? sym)))
749 (make-module-ref loc module sym #t))))
750
751;;; guile-primitive allows to create primitive references, which are
752;;; still a little faster.
753
754(defspecial guile-primitive (loc args)
755 (pmatch args
756 ((,sym)
757 (make-primitive-ref loc sym))))
758
759;;; A while construct is transformed into a tail-recursive loop like
760;;; this:
761;;;
762;;; (letrec ((iterate (lambda ()
763;;; (if condition
764;;; (begin body
765;;; (iterate))
766;;; #nil))))
767;;; (iterate))
768;;;
769;;; As letrec is not directly accessible from elisp, while is
770;;; implemented here instead of with a macro.
771
772(defspecial while (loc args)
773 (pmatch args
774 ((,condition . ,body)
d221c18b 775 (let* ((itersym (gensym))
a90d9c85 776 (compiled-body (map compile-expr body))
7081d4f9
AW
777 (iter-call (make-call loc
778 (make-lexical-ref loc
779 'iterate
780 itersym)
781 (list)))
6fc3eae4 782 (full-body (list->seq loc `(,@compiled-body ,iter-call)))
d221c18b 783 (lambda-body (make-conditional loc
f4e5e411
BT
784 (compile-expr condition)
785 full-body
786 (nil-value loc)))
787 (iter-thunk (make-lambda loc
788 '()
789 (make-lambda-case #f
790 '()
791 #f
792 #f
793 #f
794 '()
795 '()
796 lambda-body
797 #f))))
798 (make-letrec loc
799 #f
800 '(iterate)
801 (list itersym)
802 (list iter-thunk)
44ae163d 803 iter-call)))))
abcf4a9e 804
44ae163d
BT
805(defspecial function (loc args)
806 (pmatch args
807 (((lambda ,args . ,body))
67cb2c27
BT
808 (compile-lambda loc args body))
809 ((,sym) (guard (symbol? sym))
3f70b2dc 810 (reference-variable loc sym function-slot))))
de9f26b5 811
44ae163d
BT
812(defspecial defmacro (loc args)
813 (pmatch args
814 ((,name ,args . ,body)
74c009da 815 (if (not (symbol? name))
f4e5e411 816 (report-error loc "expected symbol as macro name" name)
2ce5e740 817 (let* ((tree-il
6fc3eae4 818 (make-seq
2ce5e740 819 loc
6fc3eae4
AW
820 (set-variable!
821 loc
822 name
823 function-slot
824 (make-primcall loc 'cons
825 (list (make-const loc 'macro)
826 (compile-lambda loc args body))))
827 (make-const loc name))))
2ce5e740
BT
828 (compile (ensuring-globals loc bindings-data tree-il)
829 #:from 'tree-il
830 #:to 'value)
44ae163d 831 tree-il)))))
abcf4a9e 832
44ae163d
BT
833(defspecial defun (loc args)
834 (pmatch args
835 ((,name ,args . ,body)
836 (if (not (symbol? name))
837 (report-error loc "expected symbol as function name" name)
6fc3eae4
AW
838 (make-seq loc
839 (set-variable! loc
840 name
841 function-slot
842 (compile-lambda loc
843 args
844 body))
845 (make-const loc name))))))
abcf4a9e 846
0dbfdeef 847(defspecial #{`}# (loc args)
44ae163d
BT
848 (pmatch args
849 ((,val)
850 (process-backquote loc val))))
1e018f6c 851
44ae163d
BT
852(defspecial quote (loc args)
853 (pmatch args
854 ((,val)
855 (make-const loc val))))
abcf4a9e 856
44ae163d 857;;; Compile a compound expression to Tree-IL.
74c009da 858
44ae163d
BT
859(define (compile-pair loc expr)
860 (let ((operator (car expr))
861 (arguments (cdr expr)))
862 (cond
863 ((find-operator operator 'special-operator)
864 => (lambda (special-operator-function)
865 (special-operator-function loc arguments)))
866 ((find-operator operator 'macro)
867 => (lambda (macro-function)
868 (compile-expr (apply macro-function arguments))))
869 (else
7081d4f9
AW
870 (make-call loc
871 (if (symbol? operator)
872 (reference-variable loc
873 operator
874 function-slot)
875 (compile-expr operator))
876 (map compile-expr arguments))))))
abcf4a9e 877
44ae163d
BT
878;;; Compile a symbol expression. This is a variable reference or maybe
879;;; some special value like nil.
cef997e8 880
44ae163d
BT
881(define (compile-symbol loc sym)
882 (case sym
883 ((nil) (nil-value loc))
884 ((t) (t-value loc))
3f70b2dc 885 (else (reference-variable loc sym value-slot))))
51248e6e 886
c983a199 887;;; Compile a single expression to TreeIL.
51248e6e 888
a90d9c85 889(define (compile-expr expr)
51248e6e
DK
890 (let ((loc (location expr)))
891 (cond
f4e5e411
BT
892 ((symbol? expr)
893 (compile-symbol loc expr))
894 ((pair? expr)
895 (compile-pair loc expr))
896 (else (make-const loc expr)))))
51248e6e 897
c983a199
BT
898;;; Process the compiler options.
899;;; FIXME: Why is '(()) passed as options by the REPL?
a0899974 900
c808c926
DK
901(define (valid-symbol-list-arg? value)
902 (or (eq? value 'all)
903 (and (list? value) (and-map symbol? value))))
904
a0899974
DK
905(define (process-options! opt)
906 (if (and (not (null? opt))
907 (not (equal? opt '(()))))
f4e5e411
BT
908 (if (null? (cdr opt))
909 (report-error #f "Invalid compiler options" opt)
910 (let ((key (car opt))
911 (value (cadr opt)))
912 (case key
38299196
BT
913 ((#:warnings) ; ignore
914 #f)
f4e5e411
BT
915 ((#:always-lexical)
916 (if (valid-symbol-list-arg? value)
917 (fluid-set! always-lexical value)
918 (report-error #f
919 "Invalid value for #:always-lexical"
920 value)))
921 (else (report-error #f
922 "Invalid compiler option"
923 key)))))))
a0899974 924
c983a199
BT
925;;; Entry point for compilation to TreeIL. This creates the bindings
926;;; data structure, and after compiling the main expression we need to
927;;; make sure all globals for symbols used during the compilation are
928;;; created using the generate-ensure-global function.
51248e6e
DK
929
930(define (compile-tree-il expr env opts)
931 (values
f4e5e411
BT
932 (with-fluids ((bindings-data (make-bindings))
933 (disable-void-check '())
934 (always-lexical '()))
935 (process-options! opts)
2ce5e740
BT
936 (let ((compiled (compile-expr expr)))
937 (ensuring-globals (location expr) bindings-data compiled)))
f4e5e411
BT
938 env
939 env))