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