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