eval-when
[bpt/guile.git] / module / language / elisp / compile-tree-il.scm
CommitLineData
dfbc6e9d 1;;; Guile Emacs Lisp
51248e6e 2
c32b7c4c 3;; Copyright (C) 2009, 2010, 2011, 2013 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)
1a58ce20 32 #:use-module (ice-9 format)
44ae163d
BT
33 #:export (compile-tree-il
34 compile-progn
80687f2e 35 compile-eval-when-compile
44ae163d
BT
36 compile-if
37 compile-defconst
38 compile-defvar
39 compile-setq
40 compile-let
44ae163d 41 compile-flet
1c2f9636 42 compile-labels
44ae163d 43 compile-let*
44ae163d 44 compile-guile-ref
5b744b67 45 compile-guile-private-ref
44ae163d 46 compile-guile-primitive
1a58ce20 47 compile-%function
44ae163d
BT
48 compile-function
49 compile-defmacro
50 compile-defun
0dbfdeef 51 #{compile-`}#
03e00c5c 52 compile-quote
d273b826 53 compile-%funcall
03e00c5c 54 compile-%set-lexical-binding-mode))
51248e6e 55
c983a199
BT
56;;; Certain common parameters (like the bindings data structure or
57;;; compiler options) are not always passed around but accessed using
58;;; fluids to simulate dynamic binding (hey, this is about elisp).
a90d9c85 59
c983a199
BT
60;;; The bindings data structure to keep track of symbol binding related
61;;; data.
abcf4a9e 62
a90d9c85
DK
63(define bindings-data (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)
a881a4ae 104 (make-primcall loc sym args))
50abfe76 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
eaeda0d5
BT
112(define (access-variable loc symbol handle-lexical handle-dynamic)
113 (cond
114 ((get-lexical-binding (fluid-ref bindings-data) symbol)
115 => handle-lexical)
116 (else
117 (handle-dynamic))))
344927c3 118
eaeda0d5 119(define (reference-variable loc symbol)
f4e5e411
BT
120 (access-variable
121 loc
eaeda0d5
BT
122 symbol
123 (lambda (lexical)
1a58ce20
RT
124 (if (symbol? lexical)
125 (make-lexical-ref loc symbol lexical)
126 (make-call loc lexical '())))
f4e5e411 127 (lambda ()
1a58ce20
RT
128 (make-call loc
129 (make-module-ref loc runtime 'symbol-value #t)
130 (list (make-const loc symbol))))))
344927c3 131
1a58ce20
RT
132(define (global? symbol)
133 (module-variable value-slot symbol))
66be42cb
BT
134
135(define (ensure-globals! loc names body)
1a58ce20 136 (if (and (every global? names)
eaeda0d5 137 (every symbol-interned? names))
66be42cb 138 body
5ddd9645 139 (list->seq
66be42cb
BT
140 loc
141 `(,@(map
142 (lambda (name)
1a58ce20 143 (symbol-desc name)
5ddd9645 144 (make-call loc
1a58ce20
RT
145 (make-module-ref loc runtime 'symbol-desc #t)
146 (list (make-const loc name))))
66be42cb
BT
147 names)
148 ,body))))
149
eaeda0d5 150(define (set-variable! loc symbol value)
f4e5e411
BT
151 (access-variable
152 loc
eaeda0d5
BT
153 symbol
154 (lambda (lexical)
1a58ce20
RT
155 (if (symbol? lexical)
156 (make-lexical-set loc symbol lexical value)
157 (make-call loc lexical (list value))))
c6920dc8 158 (lambda ()
eaeda0d5 159 (ensure-globals!
c6920dc8 160 loc
eaeda0d5 161 (list symbol)
1a58ce20
RT
162 (make-call loc
163 (make-module-ref loc runtime 'set-symbol-value! #t)
164 (list (make-const loc symbol)
165 value))))))
344927c3 166
eaeda0d5
BT
167(define (access-function loc symbol handle-lexical handle-global)
168 (cond
169 ((get-function-binding (fluid-ref bindings-data) symbol)
170 => handle-lexical)
171 (else
172 (handle-global))))
344927c3 173
eaeda0d5
BT
174(define (reference-function loc symbol)
175 (access-function
176 loc
177 symbol
178 (lambda (gensym) (make-lexical-ref loc symbol gensym))
1a58ce20
RT
179 (lambda ()
180 (make-module-ref loc '(elisp-functions) symbol #t))))
eaeda0d5
BT
181
182(define (set-function! loc symbol value)
183 (access-function
f4e5e411 184 loc
eaeda0d5
BT
185 symbol
186 (lambda (gensym) (make-lexical-set loc symbol gensym value))
c6920dc8 187 (lambda ()
7081d4f9 188 (make-call
c6920dc8 189 loc
eaeda0d5
BT
190 (make-module-ref loc runtime 'set-symbol-function! #t)
191 (list (make-const loc symbol) value)))))
344927c3 192
1a58ce20
RT
193(define (bind-lexically? sym decls)
194 (let ((decl (assq-ref decls sym)))
195 (or (eq? decl 'lexical)
196 (and
197 (lexical-binding?)
198 (not (special? sym))))))
a6a5cf03 199
0e5b7e74
BT
200(define (parse-let-binding loc binding)
201 (pmatch binding
202 ((unquote var)
203 (guard (symbol? var))
204 (cons var #nil))
205 ((,var)
206 (guard (symbol? var))
207 (cons var #nil))
208 ((,var ,val)
209 (guard (symbol? var))
210 (cons var val))
211 (else
212 (report-error loc "malformed variable binding" binding))))
213
214(define (parse-flet-binding loc binding)
215 (pmatch binding
216 ((,var ,args . ,body)
217 (guard (symbol? var))
218 (cons var `(function (lambda ,args ,@body))))
219 (else
220 (report-error loc "malformed function binding" binding))))
221
805b8211
BT
222(define (parse-declaration expr)
223 (pmatch expr
224 ((lexical . ,vars)
225 (map (cut cons <> 'lexical) vars))
805b8211
BT
226 (else
227 '())))
228
229(define (parse-body-1 body lambda?)
230 (let loop ((lst body)
231 (decls '())
232 (intspec #f)
233 (doc #f))
234 (pmatch lst
235 (((declare . ,x) . ,tail)
236 (loop tail (append-reverse x decls) intspec doc))
1a58ce20
RT
237 (((interactive) . ,tail)
238 (guard lambda? (not intspec))
239 (loop tail decls (cons 'interactive-form #nil) doc))
240 (((interactive ,x) . ,tail)
805b8211 241 (guard lambda? (not intspec))
1a58ce20 242 (loop tail decls (cons 'interactive-form x) doc))
805b8211 243 ((,x . ,tail)
1a58ce20 244 (guard lambda? (or (string? x) (lisp-string? x)) (not doc) (not (null? tail)))
805b8211
BT
245 (loop tail decls intspec x))
246 (else
247 (values (append-map parse-declaration decls)
248 intspec
249 doc
250 lst)))))
251
252(define (parse-lambda-body body)
253 (parse-body-1 body #t))
254
255(define (parse-body body)
256 (receive (decls intspec doc body) (parse-body-1 body #f)
257 (values decls body)))
258
16318179
BT
259;;; Partition the argument list of a lambda expression into required,
260;;; optional and rest arguments.
261
262(define (parse-lambda-list lst)
1a58ce20 263 (define (%match lst null optional rest symbol list*)
16318179
BT
264 (pmatch lst
265 (() (null))
266 ((&optional . ,tail) (optional tail))
267 ((&rest . ,tail) (rest tail))
268 ((,arg . ,tail) (guard (symbol? arg)) (symbol arg tail))
1a58ce20 269 ((,arg . ,tail) (guard (list? arg)) (list* arg tail))
16318179
BT
270 (else (fail))))
271 (define (return rreq ropt rest)
272 (values #t (reverse rreq) (reverse ropt) rest))
273 (define (fail)
274 (values #f #f #f #f))
275 (define (parse-req lst rreq)
276 (%match lst
277 (lambda () (return rreq '() #f))
278 (lambda (tail) (parse-opt tail rreq '()))
279 (lambda (tail) (parse-rest tail rreq '()))
1a58ce20
RT
280 (lambda (arg tail) (parse-req tail (cons arg rreq)))
281 (lambda (arg tail) (fail))))
16318179
BT
282 (define (parse-opt lst rreq ropt)
283 (%match lst
284 (lambda () (return rreq ropt #f))
285 (lambda (tail) (fail))
286 (lambda (tail) (parse-rest tail rreq ropt))
1a58ce20 287 (lambda (arg tail) (parse-opt tail rreq (cons (list arg) ropt)))
16318179
BT
288 (lambda (arg tail) (parse-opt tail rreq (cons arg ropt)))))
289 (define (parse-rest lst rreq ropt)
290 (%match lst
291 (lambda () (fail))
292 (lambda (tail) (fail))
293 (lambda (tail) (fail))
1a58ce20
RT
294 (lambda (arg tail) (parse-post-rest tail rreq ropt arg))
295 (lambda (arg tail) (fail))))
16318179
BT
296 (define (parse-post-rest lst rreq ropt rest)
297 (%match lst
298 (lambda () (return rreq ropt rest))
299 (lambda () (fail))
300 (lambda () (fail))
1a58ce20 301 (lambda (arg tail) (fail))
16318179
BT
302 (lambda (arg tail) (fail))))
303 (parse-req lst '()))
304
305(define (make-simple-lambda loc meta req opt init rest vars body)
306 (make-lambda loc
307 meta
308 (make-lambda-case #f req opt rest #f init vars body #f)))
50abfe76 309
c32b7c4c
AW
310(define (make-dynlet src fluids vals body)
311 (let ((f (map (lambda (x) (gensym "fluid ")) fluids))
312 (v (map (lambda (x) (gensym "valud ")) vals)))
313 (make-let src (map (lambda (_) 'fluid) fluids) f fluids
314 (make-let src (map (lambda (_) 'val) vals) v vals
315 (let lp ((f f) (v v))
316 (if (null? f)
317 body
1a58ce20
RT
318 (make-call src
319 (make-module-ref src runtime 'bind-symbol #t)
320 (list (make-lexical-ref #f 'fluid (car f))
321 (make-lexical-ref #f 'val (car v))
322 (make-lambda
323 src '()
324 (make-lambda-case
325 src '() #f #f #f '() '()
326 (lp (cdr f) (cdr v))
327 #f))))))))))
c32b7c4c 328
d9806be1 329(define (compile-lambda loc meta args body)
1a58ce20 330 (receive (valid? req-ids opts rest-id)
16318179
BT
331 (parse-lambda-list args)
332 (if valid?
333 (let* ((all-ids (append req-ids
1a58ce20 334 (and opts (map car opts))
16318179
BT
335 (or (and=> rest-id list) '())))
336 (all-vars (map (lambda (ignore) (gensym)) all-ids)))
805b8211
BT
337 (let*-values (((decls intspec doc forms)
338 (parse-lambda-body body))
339 ((lexical dynamic)
340 (partition
1a58ce20 341 (compose (cut bind-lexically? <> decls)
805b8211
BT
342 car)
343 (map list all-ids all-vars)))
344 ((lexical-ids lexical-vars) (unzip2 lexical))
345 ((dynamic-ids dynamic-vars) (unzip2 dynamic)))
346 (with-dynamic-bindings
347 (fluid-ref bindings-data)
348 dynamic-ids
349 (lambda ()
350 (with-lexical-bindings
351 (fluid-ref bindings-data)
352 lexical-ids
353 lexical-vars
354 (lambda ()
66be42cb
BT
355 (ensure-globals!
356 loc
357 dynamic-ids
663c5875
BT
358 (let* ((tree-il
359 (compile-expr
360 (if rest-id
361 `(let ((,rest-id (if ,rest-id
362 ,rest-id
363 nil)))
364 ,@forms)
365 `(progn ,@forms))))
66be42cb
BT
366 (full-body
367 (if (null? dynamic)
368 tree-il
369 (make-dynlet
370 loc
1a58ce20 371 (map (cut make-const loc <>) dynamic-ids)
66be42cb
BT
372 (map (cut make-lexical-ref loc <> <>)
373 dynamic-ids
374 dynamic-vars)
375 tree-il))))
376 (make-simple-lambda loc
1a58ce20
RT
377 (append (if intspec
378 (list intspec)
379 '())
380 (if doc
381 (list (cons 'emacs-documentation doc))
382 '())
383 meta)
66be42cb 384 req-ids
1a58ce20
RT
385 (map car opts)
386 (map (lambda (x)
387 (if (pair? (cdr x))
388 (compile-expr (car (cdr x)))
389 (make-const loc #nil)))
390 opts)
66be42cb
BT
391 rest-id
392 all-vars
393 full-body)))))))))
16318179 394 (report-error "invalid function" `(lambda ,args ,@body)))))
50abfe76 395
44ae163d 396;;; Handle macro and special operator bindings.
74c009da 397
35724ee1 398(define (find-operator name type)
8295b7c4 399 (and
35724ee1 400 (symbol? name)
1a58ce20
RT
401 (module-defined? function-slot name)
402 (let ((op (module-ref function-slot name)))
44ae163d
BT
403 (if (and (pair? op) (eq? (car op) type))
404 (cdr op)
405 #f))))
74c009da 406
9b5ff6a6
DK
407(define (contains-unquotes? expr)
408 (if (pair? expr)
f4e5e411
BT
409 (if (or (unquote? (car expr)) (unquote-splicing? (car expr)))
410 #t
411 (or (contains-unquotes? (car expr))
412 (contains-unquotes? (cdr expr))))
413 #f))
9b5ff6a6 414
c983a199
BT
415;;; Process a backquoted expression by building up the needed
416;;; cons/append calls. For splicing, it is assumed that the expression
417;;; spliced in evaluates to a list. The emacs manual does not really
418;;; state either it has to or what to do if it does not, but Scheme
419;;; explicitly forbids it and this seems reasonable also for elisp.
9b5ff6a6
DK
420
421(define (unquote-cell? expr)
422 (and (list? expr) (= (length expr) 2) (unquote? (car expr))))
abcf4a9e 423
9b5ff6a6
DK
424(define (unquote-splicing-cell? expr)
425 (and (list? expr) (= (length expr) 2) (unquote-splicing? (car expr))))
426
a90d9c85 427(define (process-backquote loc expr)
9b5ff6a6 428 (if (contains-unquotes? expr)
f4e5e411
BT
429 (if (pair? expr)
430 (if (or (unquote-cell? expr) (unquote-splicing-cell? expr))
431 (compile-expr (cadr expr))
432 (let* ((head (car expr))
433 (processed-tail (process-backquote loc (cdr expr)))
434 (head-is-list-2 (and (list? head)
435 (= (length head) 2)))
436 (head-unquote (and head-is-list-2
437 (unquote? (car head))))
438 (head-unquote-splicing (and head-is-list-2
439 (unquote-splicing?
440 (car head)))))
441 (if head-unquote-splicing
442 (call-primitive loc
443 'append
444 (compile-expr (cadr head))
445 processed-tail)
446 (call-primitive loc 'cons
447 (if head-unquote
448 (compile-expr (cadr head))
449 (process-backquote loc head))
450 processed-tail))))
451 (report-error loc
452 "non-pair expression contains unquotes"
453 expr))
454 (make-const loc expr)))
9b5ff6a6 455
44ae163d 456;;; Special operators
abcf4a9e 457
44ae163d 458(defspecial progn (loc args)
5ddd9645
BT
459 (list->seq loc
460 (if (null? args)
461 (list (nil-value loc))
a3094b12 462 (map compile-expr-1 args))))
abcf4a9e 463
80687f2e
BT
464(defspecial eval-when-compile (loc args)
465 (make-const loc (compile `(progn ,@args) #:from 'elisp #:to 'value)))
abcf4a9e 466
a3094b12
RT
467(define toplevel? (make-fluid))
468
469(define compile-time-too? (make-fluid))
470
471(defspecial eval-when (loc args)
472 (pmatch args
473 ((,situations . ,forms)
474 (let ((compile? (memq ':compile-toplevel situations))
475 (load? (memq ':load-toplevel situations))
476 (execute? (memq ':execute situations)))
477 (cond
478 ((not (fluid-ref toplevel?))
479 (if execute?
480 (compile-expr `(progn ,@forms))
481 (make-const loc #nil)))
482 (load?
483 (with-fluids ((compile-time-too?
484 (cond (compile? #t)
485 (execute? (fluid-ref compile-time-too?))
486 (else #f))))
487 (when (fluid-ref compile-time-too?)
488 (eval-elisp `(progn ,@forms)))
489 (compile-expr-1 `(progn ,@forms))))
490 ((or compile? (and execute? (fluid-ref compile-time-too?)))
491 (eval-elisp `(progn ,@forms))
492 (make-const loc #nil))
493 (else
494 (make-const loc #nil)))))))
495
44ae163d
BT
496(defspecial if (loc args)
497 (pmatch args
498 ((,cond ,then . ,else)
30439aa8
BT
499 (make-conditional
500 loc
501 (call-primitive loc 'not
502 (call-primitive loc 'nil? (compile-expr cond)))
503 (compile-expr then)
1a58ce20
RT
504 (compile-expr `(progn ,@else))))
505 (else (report-error loc "Bad if" args))))
44ae163d
BT
506
507(defspecial defconst (loc args)
508 (pmatch args
509 ((,sym ,value . ,doc)
b094d98b 510 (proclaim-special! sym)
1a58ce20
RT
511 (make-seq
512 loc
513 (make-call loc
514 (make-module-ref loc runtime 'proclaim-special! #t)
515 (list (make-const loc sym)))
516 (make-seq loc
517 (set-variable! loc sym (compile-expr value))
518 (make-const loc sym))))
519 (else (report-error loc "Bad defconst" args))))
de9f26b5 520
44ae163d
BT
521(defspecial defvar (loc args)
522 (pmatch args
1a58ce20 523 ((,sym)
b094d98b 524 (proclaim-special! sym)
1a58ce20
RT
525 (make-seq loc
526 (make-call loc
527 (make-module-ref loc runtime 'proclaim-special! #t)
528 (list (make-const loc sym)))
529 (make-const loc sym)))
44ae163d 530 ((,sym ,value . ,doc)
b094d98b 531 (proclaim-special! sym)
1a58ce20
RT
532 (make-seq
533 loc
534 (make-call loc
535 (make-module-ref loc runtime 'proclaim-special! #t)
536 (list (make-const loc sym)))
537 (make-seq
538 loc
539 (make-conditional
540 loc
541 (make-call loc
bd0f2917 542 (make-module-ref loc runtime 'symbol-default-bound? #t)
1a58ce20
RT
543 (list (make-const loc sym)))
544 (make-void loc)
bd0f2917
RT
545 (make-call loc
546 (make-module-ref loc runtime 'set-symbol-default-value! #t)
547 (list (make-const loc sym)
548 (compile-expr value))))
1a58ce20
RT
549 (make-const loc sym))))
550 (else (report-error loc "Bad defvar" args))))
44ae163d
BT
551
552(defspecial setq (loc args)
f5742cf0
BT
553 (define (car* x) (if (null? x) '() (car x)))
554 (define (cdr* x) (if (null? x) '() (cdr x)))
555 (define (cadr* x) (car* (cdr* x)))
556 (define (cddr* x) (cdr* (cdr* x)))
6fc3eae4 557 (list->seq
44ae163d 558 loc
f5742cf0
BT
559 (let loop ((args args) (last (nil-value loc)))
560 (if (null? args)
561 (list last)
562 (let ((sym (car args))
563 (val (compile-expr (cadr* args))))
564 (if (not (symbol? sym))
1a58ce20 565 (report-error loc "expected symbol in setq" args)
f5742cf0 566 (cons
eaeda0d5 567 (set-variable! loc sym val)
f5742cf0 568 (loop (cddr* args)
eaeda0d5 569 (reference-variable loc sym)))))))))
f5742cf0 570
44ae163d
BT
571(defspecial let (loc args)
572 (pmatch args
c64c51eb
BT
573 ((,varlist . ,body)
574 (let ((bindings (map (cut parse-let-binding loc <>) varlist)))
575 (receive (decls forms) (parse-body body)
576 (receive (lexical dynamic)
577 (partition
1a58ce20 578 (compose (cut bind-lexically? <> decls)
c64c51eb
BT
579 car)
580 bindings)
c64c51eb
BT
581 (let ((make-values (lambda (for)
582 (map (lambda (el) (compile-expr (cdr el)))
583 for)))
584 (make-body (lambda () (compile-expr `(progn ,@forms)))))
66be42cb
BT
585 (ensure-globals!
586 loc
587 (map car dynamic)
588 (if (null? lexical)
589 (make-dynlet loc
1a58ce20 590 (map (compose (cut make-const loc <>) car)
66be42cb
BT
591 dynamic)
592 (map (compose compile-expr cdr)
593 dynamic)
594 (make-body))
595 (let* ((lexical-syms (map (lambda (el) (gensym)) lexical))
596 (dynamic-syms (map (lambda (el) (gensym)) dynamic))
597 (all-syms (append lexical-syms dynamic-syms))
598 (vals (append (make-values lexical)
599 (make-values dynamic))))
600 (make-let loc
601 all-syms
602 all-syms
603 vals
604 (with-lexical-bindings
605 (fluid-ref bindings-data)
606 (map car lexical)
607 lexical-syms
608 (lambda ()
609 (if (null? dynamic)
610 (make-body)
611 (make-dynlet loc
612 (map
1a58ce20
RT
613 (compose (cut make-const
614 loc
615 <>)
616 car)
66be42cb
BT
617 dynamic)
618 (map
619 (lambda (sym)
620 (make-lexical-ref
621 loc
622 sym
623 sym))
624 dynamic-syms)
1a58ce20
RT
625 (make-body))))))))))))))
626 (else (report-error loc "bad let args"))))
44ae163d
BT
627
628(defspecial let* (loc args)
629 (pmatch args
c64c51eb
BT
630 ((,varlist . ,body)
631 (let ((bindings (map (cut parse-let-binding loc <>) varlist)))
632 (receive (decls forms) (parse-body body)
c64c51eb
BT
633 (let iterate ((tail bindings))
634 (if (null? tail)
635 (compile-expr `(progn ,@forms))
636 (let ((sym (caar tail))
637 (value (compile-expr (cdar tail))))
1a58ce20 638 (if (bind-lexically? sym decls)
c64c51eb
BT
639 (let ((target (gensym)))
640 (make-let loc
641 `(,target)
642 `(,target)
643 `(,value)
644 (with-lexical-bindings
645 (fluid-ref bindings-data)
646 `(,sym)
647 `(,target)
648 (lambda () (iterate (cdr tail))))))
66be42cb
BT
649 (ensure-globals!
650 loc
651 (list sym)
652 (make-dynlet loc
1a58ce20 653 (list (make-const loc sym))
66be42cb 654 (list value)
1a58ce20
RT
655 (iterate (cdr tail)))))))))))
656 (else (report-error loc "Bad let*" args))))
44ae163d 657
44ae163d 658(defspecial flet (loc args)
44ae163d
BT
659 (pmatch args
660 ((,bindings . ,body)
6bb004c4
BT
661 (let ((names+vals (map (cut parse-flet-binding loc <>) bindings)))
662 (receive (decls forms) (parse-body body)
663 (let ((names (map car names+vals))
664 (vals (map cdr names+vals))
665 (gensyms (map (lambda (x) (gensym)) names+vals)))
eaeda0d5 666 (with-function-bindings
6bb004c4
BT
667 (fluid-ref bindings-data)
668 names
669 gensyms
670 (lambda ()
671 (make-let loc
672 names
673 gensyms
674 (map compile-expr vals)
1a58ce20
RT
675 (compile-expr `(progn ,@forms)))))))))
676 (else (report-error loc "bad flet" args))))
44ae163d 677
1c2f9636 678(defspecial labels (loc args)
44ae163d
BT
679 (pmatch args
680 ((,bindings . ,body)
1c2f9636
BT
681 (let ((names+vals (map (cut parse-flet-binding loc <>) bindings)))
682 (receive (decls forms) (parse-body body)
683 (let ((names (map car names+vals))
684 (vals (map cdr names+vals))
685 (gensyms (map (lambda (x) (gensym)) names+vals)))
eaeda0d5 686 (with-function-bindings
1c2f9636
BT
687 (fluid-ref bindings-data)
688 names
689 gensyms
690 (lambda ()
691 (make-letrec #f
692 loc
693 names
694 gensyms
695 (map compile-expr vals)
1a58ce20
RT
696 (compile-expr `(progn ,@forms)))))))))
697 (else (report-error loc "bad labels" args))))
44ae163d
BT
698
699;;; guile-ref allows building TreeIL's module references from within
700;;; elisp as a way to access data within the Guile universe. The module
701;;; and symbol referenced are static values, just like (@ module symbol)
702;;; does!
703
704(defspecial guile-ref (loc args)
705 (pmatch args
706 ((,module ,sym) (guard (and (list? module) (symbol? sym)))
1a58ce20
RT
707 (make-module-ref loc module sym #t))
708 (else (report-error loc "bad guile-ref" args))))
44ae163d 709
5b744b67
BT
710(defspecial guile-private-ref (loc args)
711 (pmatch args
712 ((,module ,sym) (guard (and (list? module) (symbol? sym)))
1a58ce20
RT
713 (make-module-ref loc module sym #f))
714 (else (report-error loc "bad guile-private-ref" args))))
5b744b67 715
44ae163d
BT
716;;; guile-primitive allows to create primitive references, which are
717;;; still a little faster.
718
719(defspecial guile-primitive (loc args)
720 (pmatch args
721 ((,sym)
1a58ce20
RT
722 (make-primitive-ref loc sym))
723 (else (report-error loc "bad guile-primitive" args))))
44ae163d 724
1a58ce20 725(defspecial %function (loc args)
44ae163d
BT
726 (pmatch args
727 (((lambda ,args . ,body))
d9806be1 728 (compile-lambda loc '() args body))
1a58ce20
RT
729 (((closure ,env ,args . ,body))
730 (let ((bindings (map (lambda (x) (list (car x) (cdr x)))
731 (filter pair? env))))
732 (compile-expr
733 (let ((form `(let ,bindings
734 (declare ,@(map (lambda (x) (list 'lexical x))
735 bindings))
736 (function (lambda ,args
737 (declare
738 (lexical
739 ,@(filter-map
740 (lambda (x)
741 (cond
742 ((memq x '(&optional &rest))
743 #f)
744 ((symbol? x)
745 x)
746 ((list? x)
747 (car x))))
748 args)))
749 ,@body)))))
750 form))))
67cb2c27 751 ((,sym) (guard (symbol? sym))
1a58ce20
RT
752 (reference-function loc sym))
753 ((,x)
754 (make-const loc x))
755 (else (report-error loc "bad function" args))))
756
757(defspecial function (loc args)
758 (pmatch args
759 ((,sym) (guard (symbol? sym))
760 (make-const loc sym))
761 (else ((cdr compile-%function) loc args))))
de9f26b5 762
44ae163d
BT
763(defspecial defmacro (loc args)
764 (pmatch args
765 ((,name ,args . ,body)
74c009da 766 (if (not (symbol? name))
f4e5e411 767 (report-error loc "expected symbol as macro name" name)
2ce5e740 768 (let* ((tree-il
6fc3eae4 769 (make-seq
2ce5e740 770 loc
5ddd9645 771 (set-function!
6fc3eae4
AW
772 loc
773 name
5ddd9645 774 (make-call
2ce5e740 775 loc
5ddd9645
BT
776 (make-module-ref loc '(guile) 'cons #t)
777 (list (make-const loc 'macro)
778 (compile-lambda loc
779 `((name . ,name))
780 args
781 body))))
6fc3eae4 782 (make-const loc name))))
66be42cb 783 (compile tree-il #:from 'tree-il #:to 'value)
1a58ce20
RT
784 tree-il)))
785 (else (report-error loc "bad defmacro" args))))
abcf4a9e 786
0dbfdeef 787(defspecial #{`}# (loc args)
44ae163d
BT
788 (pmatch args
789 ((,val)
1a58ce20
RT
790 (process-backquote loc val))
791 (else (report-error loc "bad backquote" args))))
1e018f6c 792
44ae163d
BT
793(defspecial quote (loc args)
794 (pmatch args
795 ((,val)
1a58ce20
RT
796 (make-const loc val))
797 (else (report-error loc "bad quote" args))))
abcf4a9e 798
d273b826
BT
799(defspecial %funcall (loc args)
800 (pmatch args
801 ((,function . ,arguments)
5ddd9645
BT
802 (make-call loc
803 (compile-expr function)
1a58ce20
RT
804 (map compile-expr arguments)))
805 (else (report-error loc "bad %funcall" args))))
d273b826 806
03e00c5c
BT
807(defspecial %set-lexical-binding-mode (loc args)
808 (pmatch args
809 ((,val)
1a58ce20
RT
810 (set-lexical-binding-mode val)
811 (make-void loc))
812 (else (report-error loc "bad %set-lexical-binding-mode" args))))
813
a92f076c
RT
814(define (eget s p)
815 (if (symbol-fbound? 'get)
816 ((symbol-function 'get) s p)
817 #nil))
818
44ae163d 819;;; Compile a compound expression to Tree-IL.
74c009da 820
44ae163d
BT
821(define (compile-pair loc expr)
822 (let ((operator (car expr))
823 (arguments (cdr expr)))
824 (cond
77a06476
RT
825 ((find-operator operator 'special-operator)
826 => (lambda (special-operator-function)
827 (special-operator-function loc arguments)))
44ae163d
BT
828 ((find-operator operator 'macro)
829 => (lambda (macro-function)
830 (compile-expr (apply macro-function arguments))))
a92f076c
RT
831 ((and (symbol? operator)
832 (eget operator '%compiler-macro))
833 => (lambda (compiler-macro-function)
834 (let ((new (compiler-macro-function expr)))
835 (if (eq? new expr)
836 (compile-expr `(%funcall (%function ,operator) ,@arguments))
837 (compile-expr new)))))
44ae163d 838 (else
1a58ce20 839 (compile-expr `(%funcall (%function ,operator) ,@arguments))))))
abcf4a9e 840
44ae163d
BT
841;;; Compile a symbol expression. This is a variable reference or maybe
842;;; some special value like nil.
cef997e8 843
44ae163d
BT
844(define (compile-symbol loc sym)
845 (case sym
846 ((nil) (nil-value loc))
847 ((t) (t-value loc))
eaeda0d5 848 (else (reference-variable loc sym))))
51248e6e 849
c983a199 850;;; Compile a single expression to TreeIL.
51248e6e 851
a3094b12 852(define (compile-expr-1 expr)
51248e6e
DK
853 (let ((loc (location expr)))
854 (cond
f4e5e411
BT
855 ((symbol? expr)
856 (compile-symbol loc expr))
857 ((pair? expr)
858 (compile-pair loc expr))
859 (else (make-const loc expr)))))
51248e6e 860
a3094b12
RT
861(define (compile-expr expr)
862 (if (fluid-ref toplevel?)
863 (with-fluids ((toplevel? #f))
864 (compile-expr-1 expr))
865 (compile-expr-1 expr)))
866
51248e6e
DK
867(define (compile-tree-il expr env opts)
868 (values
a3094b12
RT
869 (with-fluids ((bindings-data (make-bindings))
870 (toplevel? #t)
871 (compile-time-too? #f))
872 (compile-expr-1 expr))
f4e5e411
BT
873 env
874 env))