compiler macros
[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))
462 (map compile-expr 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
44ae163d
BT
467(defspecial if (loc args)
468 (pmatch args
469 ((,cond ,then . ,else)
30439aa8
BT
470 (make-conditional
471 loc
472 (call-primitive loc 'not
473 (call-primitive loc 'nil? (compile-expr cond)))
474 (compile-expr then)
1a58ce20
RT
475 (compile-expr `(progn ,@else))))
476 (else (report-error loc "Bad if" args))))
44ae163d
BT
477
478(defspecial defconst (loc args)
479 (pmatch args
480 ((,sym ,value . ,doc)
b094d98b 481 (proclaim-special! sym)
1a58ce20
RT
482 (make-seq
483 loc
484 (make-call loc
485 (make-module-ref loc runtime 'proclaim-special! #t)
486 (list (make-const loc sym)))
487 (make-seq loc
488 (set-variable! loc sym (compile-expr value))
489 (make-const loc sym))))
490 (else (report-error loc "Bad defconst" args))))
de9f26b5 491
44ae163d
BT
492(defspecial defvar (loc args)
493 (pmatch args
1a58ce20 494 ((,sym)
b094d98b 495 (proclaim-special! sym)
1a58ce20
RT
496 (make-seq loc
497 (make-call loc
498 (make-module-ref loc runtime 'proclaim-special! #t)
499 (list (make-const loc sym)))
500 (make-const loc sym)))
44ae163d 501 ((,sym ,value . ,doc)
b094d98b 502 (proclaim-special! sym)
1a58ce20
RT
503 (make-seq
504 loc
505 (make-call loc
506 (make-module-ref loc runtime 'proclaim-special! #t)
507 (list (make-const loc sym)))
508 (make-seq
509 loc
510 (make-conditional
511 loc
512 (make-call loc
bd0f2917 513 (make-module-ref loc runtime 'symbol-default-bound? #t)
1a58ce20
RT
514 (list (make-const loc sym)))
515 (make-void loc)
bd0f2917
RT
516 (make-call loc
517 (make-module-ref loc runtime 'set-symbol-default-value! #t)
518 (list (make-const loc sym)
519 (compile-expr value))))
1a58ce20
RT
520 (make-const loc sym))))
521 (else (report-error loc "Bad defvar" args))))
44ae163d
BT
522
523(defspecial setq (loc args)
f5742cf0
BT
524 (define (car* x) (if (null? x) '() (car x)))
525 (define (cdr* x) (if (null? x) '() (cdr x)))
526 (define (cadr* x) (car* (cdr* x)))
527 (define (cddr* x) (cdr* (cdr* x)))
6fc3eae4 528 (list->seq
44ae163d 529 loc
f5742cf0
BT
530 (let loop ((args args) (last (nil-value loc)))
531 (if (null? args)
532 (list last)
533 (let ((sym (car args))
534 (val (compile-expr (cadr* args))))
535 (if (not (symbol? sym))
1a58ce20 536 (report-error loc "expected symbol in setq" args)
f5742cf0 537 (cons
eaeda0d5 538 (set-variable! loc sym val)
f5742cf0 539 (loop (cddr* args)
eaeda0d5 540 (reference-variable loc sym)))))))))
f5742cf0 541
44ae163d
BT
542(defspecial let (loc args)
543 (pmatch args
c64c51eb
BT
544 ((,varlist . ,body)
545 (let ((bindings (map (cut parse-let-binding loc <>) varlist)))
546 (receive (decls forms) (parse-body body)
547 (receive (lexical dynamic)
548 (partition
1a58ce20 549 (compose (cut bind-lexically? <> decls)
c64c51eb
BT
550 car)
551 bindings)
c64c51eb
BT
552 (let ((make-values (lambda (for)
553 (map (lambda (el) (compile-expr (cdr el)))
554 for)))
555 (make-body (lambda () (compile-expr `(progn ,@forms)))))
66be42cb
BT
556 (ensure-globals!
557 loc
558 (map car dynamic)
559 (if (null? lexical)
560 (make-dynlet loc
1a58ce20 561 (map (compose (cut make-const loc <>) car)
66be42cb
BT
562 dynamic)
563 (map (compose compile-expr cdr)
564 dynamic)
565 (make-body))
566 (let* ((lexical-syms (map (lambda (el) (gensym)) lexical))
567 (dynamic-syms (map (lambda (el) (gensym)) dynamic))
568 (all-syms (append lexical-syms dynamic-syms))
569 (vals (append (make-values lexical)
570 (make-values dynamic))))
571 (make-let loc
572 all-syms
573 all-syms
574 vals
575 (with-lexical-bindings
576 (fluid-ref bindings-data)
577 (map car lexical)
578 lexical-syms
579 (lambda ()
580 (if (null? dynamic)
581 (make-body)
582 (make-dynlet loc
583 (map
1a58ce20
RT
584 (compose (cut make-const
585 loc
586 <>)
587 car)
66be42cb
BT
588 dynamic)
589 (map
590 (lambda (sym)
591 (make-lexical-ref
592 loc
593 sym
594 sym))
595 dynamic-syms)
1a58ce20
RT
596 (make-body))))))))))))))
597 (else (report-error loc "bad let args"))))
44ae163d
BT
598
599(defspecial let* (loc args)
600 (pmatch args
c64c51eb
BT
601 ((,varlist . ,body)
602 (let ((bindings (map (cut parse-let-binding loc <>) varlist)))
603 (receive (decls forms) (parse-body body)
c64c51eb
BT
604 (let iterate ((tail bindings))
605 (if (null? tail)
606 (compile-expr `(progn ,@forms))
607 (let ((sym (caar tail))
608 (value (compile-expr (cdar tail))))
1a58ce20 609 (if (bind-lexically? sym decls)
c64c51eb
BT
610 (let ((target (gensym)))
611 (make-let loc
612 `(,target)
613 `(,target)
614 `(,value)
615 (with-lexical-bindings
616 (fluid-ref bindings-data)
617 `(,sym)
618 `(,target)
619 (lambda () (iterate (cdr tail))))))
66be42cb
BT
620 (ensure-globals!
621 loc
622 (list sym)
623 (make-dynlet loc
1a58ce20 624 (list (make-const loc sym))
66be42cb 625 (list value)
1a58ce20
RT
626 (iterate (cdr tail)))))))))))
627 (else (report-error loc "Bad let*" args))))
44ae163d 628
44ae163d 629(defspecial flet (loc args)
44ae163d
BT
630 (pmatch args
631 ((,bindings . ,body)
6bb004c4
BT
632 (let ((names+vals (map (cut parse-flet-binding loc <>) bindings)))
633 (receive (decls forms) (parse-body body)
634 (let ((names (map car names+vals))
635 (vals (map cdr names+vals))
636 (gensyms (map (lambda (x) (gensym)) names+vals)))
eaeda0d5 637 (with-function-bindings
6bb004c4
BT
638 (fluid-ref bindings-data)
639 names
640 gensyms
641 (lambda ()
642 (make-let loc
643 names
644 gensyms
645 (map compile-expr vals)
1a58ce20
RT
646 (compile-expr `(progn ,@forms)))))))))
647 (else (report-error loc "bad flet" args))))
44ae163d 648
1c2f9636 649(defspecial labels (loc args)
44ae163d
BT
650 (pmatch args
651 ((,bindings . ,body)
1c2f9636
BT
652 (let ((names+vals (map (cut parse-flet-binding loc <>) bindings)))
653 (receive (decls forms) (parse-body body)
654 (let ((names (map car names+vals))
655 (vals (map cdr names+vals))
656 (gensyms (map (lambda (x) (gensym)) names+vals)))
eaeda0d5 657 (with-function-bindings
1c2f9636
BT
658 (fluid-ref bindings-data)
659 names
660 gensyms
661 (lambda ()
662 (make-letrec #f
663 loc
664 names
665 gensyms
666 (map compile-expr vals)
1a58ce20
RT
667 (compile-expr `(progn ,@forms)))))))))
668 (else (report-error loc "bad labels" args))))
44ae163d
BT
669
670;;; guile-ref allows building TreeIL's module references from within
671;;; elisp as a way to access data within the Guile universe. The module
672;;; and symbol referenced are static values, just like (@ module symbol)
673;;; does!
674
675(defspecial guile-ref (loc args)
676 (pmatch args
677 ((,module ,sym) (guard (and (list? module) (symbol? sym)))
1a58ce20
RT
678 (make-module-ref loc module sym #t))
679 (else (report-error loc "bad guile-ref" args))))
44ae163d 680
5b744b67
BT
681(defspecial guile-private-ref (loc args)
682 (pmatch args
683 ((,module ,sym) (guard (and (list? module) (symbol? sym)))
1a58ce20
RT
684 (make-module-ref loc module sym #f))
685 (else (report-error loc "bad guile-private-ref" args))))
5b744b67 686
44ae163d
BT
687;;; guile-primitive allows to create primitive references, which are
688;;; still a little faster.
689
690(defspecial guile-primitive (loc args)
691 (pmatch args
692 ((,sym)
1a58ce20
RT
693 (make-primitive-ref loc sym))
694 (else (report-error loc "bad guile-primitive" args))))
44ae163d 695
1a58ce20 696(defspecial %function (loc args)
44ae163d
BT
697 (pmatch args
698 (((lambda ,args . ,body))
d9806be1 699 (compile-lambda loc '() args body))
1a58ce20
RT
700 (((closure ,env ,args . ,body))
701 (let ((bindings (map (lambda (x) (list (car x) (cdr x)))
702 (filter pair? env))))
703 (compile-expr
704 (let ((form `(let ,bindings
705 (declare ,@(map (lambda (x) (list 'lexical x))
706 bindings))
707 (function (lambda ,args
708 (declare
709 (lexical
710 ,@(filter-map
711 (lambda (x)
712 (cond
713 ((memq x '(&optional &rest))
714 #f)
715 ((symbol? x)
716 x)
717 ((list? x)
718 (car x))))
719 args)))
720 ,@body)))))
721 form))))
67cb2c27 722 ((,sym) (guard (symbol? sym))
1a58ce20
RT
723 (reference-function loc sym))
724 ((,x)
725 (make-const loc x))
726 (else (report-error loc "bad function" args))))
727
728(defspecial function (loc args)
729 (pmatch args
730 ((,sym) (guard (symbol? sym))
731 (make-const loc sym))
732 (else ((cdr compile-%function) loc args))))
de9f26b5 733
44ae163d
BT
734(defspecial defmacro (loc args)
735 (pmatch args
736 ((,name ,args . ,body)
74c009da 737 (if (not (symbol? name))
f4e5e411 738 (report-error loc "expected symbol as macro name" name)
2ce5e740 739 (let* ((tree-il
6fc3eae4 740 (make-seq
2ce5e740 741 loc
5ddd9645 742 (set-function!
6fc3eae4
AW
743 loc
744 name
5ddd9645 745 (make-call
2ce5e740 746 loc
5ddd9645
BT
747 (make-module-ref loc '(guile) 'cons #t)
748 (list (make-const loc 'macro)
749 (compile-lambda loc
750 `((name . ,name))
751 args
752 body))))
6fc3eae4 753 (make-const loc name))))
66be42cb 754 (compile tree-il #:from 'tree-il #:to 'value)
1a58ce20
RT
755 tree-il)))
756 (else (report-error loc "bad defmacro" args))))
abcf4a9e 757
0dbfdeef 758(defspecial #{`}# (loc args)
44ae163d
BT
759 (pmatch args
760 ((,val)
1a58ce20
RT
761 (process-backquote loc val))
762 (else (report-error loc "bad backquote" args))))
1e018f6c 763
44ae163d
BT
764(defspecial quote (loc args)
765 (pmatch args
766 ((,val)
1a58ce20
RT
767 (make-const loc val))
768 (else (report-error loc "bad quote" args))))
abcf4a9e 769
d273b826
BT
770(defspecial %funcall (loc args)
771 (pmatch args
772 ((,function . ,arguments)
5ddd9645
BT
773 (make-call loc
774 (compile-expr function)
1a58ce20
RT
775 (map compile-expr arguments)))
776 (else (report-error loc "bad %funcall" args))))
d273b826 777
03e00c5c
BT
778(defspecial %set-lexical-binding-mode (loc args)
779 (pmatch args
780 ((,val)
1a58ce20
RT
781 (set-lexical-binding-mode val)
782 (make-void loc))
783 (else (report-error loc "bad %set-lexical-binding-mode" args))))
784
a92f076c
RT
785(define (eget s p)
786 (if (symbol-fbound? 'get)
787 ((symbol-function 'get) s p)
788 #nil))
789
44ae163d 790;;; Compile a compound expression to Tree-IL.
74c009da 791
44ae163d
BT
792(define (compile-pair loc expr)
793 (let ((operator (car expr))
794 (arguments (cdr expr)))
795 (cond
77a06476
RT
796 ((find-operator operator 'special-operator)
797 => (lambda (special-operator-function)
798 (special-operator-function loc arguments)))
44ae163d
BT
799 ((find-operator operator 'macro)
800 => (lambda (macro-function)
801 (compile-expr (apply macro-function arguments))))
a92f076c
RT
802 ((and (symbol? operator)
803 (eget operator '%compiler-macro))
804 => (lambda (compiler-macro-function)
805 (let ((new (compiler-macro-function expr)))
806 (if (eq? new expr)
807 (compile-expr `(%funcall (%function ,operator) ,@arguments))
808 (compile-expr new)))))
44ae163d 809 (else
1a58ce20 810 (compile-expr `(%funcall (%function ,operator) ,@arguments))))))
abcf4a9e 811
44ae163d
BT
812;;; Compile a symbol expression. This is a variable reference or maybe
813;;; some special value like nil.
cef997e8 814
44ae163d
BT
815(define (compile-symbol loc sym)
816 (case sym
817 ((nil) (nil-value loc))
818 ((t) (t-value loc))
eaeda0d5 819 (else (reference-variable loc sym))))
51248e6e 820
c983a199 821;;; Compile a single expression to TreeIL.
51248e6e 822
a90d9c85 823(define (compile-expr expr)
51248e6e
DK
824 (let ((loc (location expr)))
825 (cond
f4e5e411
BT
826 ((symbol? expr)
827 (compile-symbol loc expr))
828 ((pair? expr)
829 (compile-pair loc expr))
830 (else (make-const loc expr)))))
51248e6e 831
51248e6e
DK
832(define (compile-tree-il expr env opts)
833 (values
e5a361d1 834 (with-fluids ((bindings-data (make-bindings)))
66be42cb 835 (compile-expr expr))
f4e5e411
BT
836 env
837 env))