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