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