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