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