actually compile start-stack to something useful
[bpt/guile.git] / module / language / scheme / translate.scm
CommitLineData
c7228382
KN
1;;; Guile Scheme specification
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.
2335fb97 9;;
c7228382
KN
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.
2335fb97 14;;
c7228382
KN
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 scheme translate)
1a1a10d3
AW
23 #:use-module (system base pmatch)
24 #:use-module (system base language)
25 #:use-module (system il ghil)
26 #:use-module (system il inline)
27 #:use-module (ice-9 receive)
1e6ebf54 28 #:use-module ((ice-9 syncase) #:select (sc-macro))
1a1a10d3
AW
29 #:use-module ((system base compile) #:select (syntax-error))
30 #:export (translate))
c7228382 31
2335fb97 32
c7228382 33(define (translate x e)
2e7e6969 34 (call-with-ghil-environment (make-ghil-toplevel-env) '()
7d1c45d3 35 (lambda (env vars)
fbde2b91 36 (make-ghil-lambda env #f vars #f '() (trans env (location x) x)))))
c7228382
KN
37
38\f
39;;;
40;;; Translator
41;;;
42
f03c31db 43(define *forbidden-primitives*
2335fb97
LC
44 ;; Guile's `procedure->macro' family is evil because it crosses the
45 ;; compilation boundary. One solution might be to evaluate calls to
46 ;; `procedure->memoizing-macro' at compilation time, but it may be more
47 ;; compicated than that.
29a321ae 48 '(procedure->syntax procedure->macro))
2335fb97 49
2e7e6969
AW
50;; Looks up transformers relative to the current module at
51;; compilation-time. See also the discussion of ghil-lookup in ghil.scm.
52(define (lookup-transformer head retrans)
53 (let* ((mod (current-module))
427d4a0c
AW
54 (val (and (symbol? head)
55 (and=> (module-variable mod head)
56 (lambda (var)
57 ;; unbound vars can happen if the module
58 ;; definition forward-declared them
59 (and (variable-bound? var) (variable-ref var)))))))
7d1c45d3 60 (cond
7e97ad2d 61 ((assq-ref custom-transformer-table val))
7d1c45d3
AW
62
63 ((defmacro? val)
64 (lambda (env loc exp)
65 (retrans (apply (defmacro-transformer val) (cdr exp)))))
66
1e6ebf54 67 ((eq? val sc-macro)
a52b96a7 68 ;; syncase!
8f43eb2b
AW
69 (let* ((the-syncase-module (resolve-module '(ice-9 syncase)))
70 (eec (module-ref the-syncase-module 'expansion-eval-closure))
71 (sc-expand3 (module-ref the-syncase-module 'sc-expand3)))
a52b96a7 72 (lambda (env loc exp)
8f43eb2b 73 (retrans
1b8abe55 74 (with-fluids ((eec (module-eval-closure mod)))
8f43eb2b 75 (sc-expand3 exp 'c '(compile load eval)))))))
a52b96a7 76
7e97ad2d
AW
77 ((primitive-macro? val)
78 (syntax-error #f "unhandled primitive macro" head))
79
7d1c45d3
AW
80 ((macro? val)
81 (syntax-error #f "unknown kind of macro" head))
82
83 (else #f))))
84
c7228382 85(define (trans e l x)
96969dc1 86 (define (retrans x) (trans e (location x) x))
c7228382 87 (cond ((pair? x)
7d1c45d3
AW
88 (let ((head (car x)) (tail (cdr x)))
89 (cond
2e7e6969 90 ((lookup-transformer head retrans)
7d1c45d3
AW
91 => (lambda (t) (t e l x)))
92
7d1c45d3 93 ;; FIXME: lexical/module overrides of forbidden primitives
f03c31db 94 ((memq head *forbidden-primitives*)
7d1c45d3 95 (syntax-error l (format #f "`~a' is forbidden" head)
1e6ebf54 96 (cons head tail)))
22bcbe8c 97
7d1c45d3 98 (else
22bcbe8c 99 (let ((tail (map retrans tail)))
427d4a0c
AW
100 (or (and (symbol? head)
101 (try-inline-with-env e l (cons head tail)))
22bcbe8c 102 (make-ghil-call e l (retrans head) tail)))))))
7d1c45d3 103
f21dfea6 104 ((symbol? x)
540d9d87 105 (make-ghil-ref e l (ghil-lookup e x)))
7d1c45d3 106
7d1c45d3
AW
107 ;; fixme: non-self-quoting objects like #<foo>
108 (else
10be7025 109 (make-ghil-quote e l #:obj x))))
c7228382 110
f245e62c
AW
111(define (valid-bindings? bindings . it-is-for-do)
112 (define (valid-binding? b)
113 (pmatch b
114 ((,sym ,var) (guard (symbol? sym)) #t)
115 ((,sym ,var ,update) (guard (pair? it-is-for-do) (symbol? sym)) #t)
116 (else #f)))
117 (and (list? bindings) (and-map valid-binding? bindings)))
118
7d1c45d3
AW
119(define-macro (make-pmatch-transformers env loc retranslate . body)
120 (define exp (gensym))
121 (define (make1 clause)
122 (let ((sym (car clause))
123 (clauses (cdr clause)))
7e97ad2d 124 `(cons ,sym
7d1c45d3 125 (lambda (,env ,loc ,exp)
96969dc1 126 (define (,retranslate x) (trans ,env (location x) x))
7d1c45d3
AW
127 (pmatch (cdr ,exp)
128 ,@clauses
129 (else (syntax-error ,loc (format #f "bad ~A" ',sym) ,exp)))))))
130 `(list ,@(map make1 body)))
131
d79d908e 132(define *the-compile-toplevel-symbol* 'compile-toplevel)
bd76c6d3 133
7e97ad2d 134(define custom-transformer-table
7d1c45d3
AW
135 (make-pmatch-transformers
136 e l retrans
137 (quote
c7228382 138 ;; (quote OBJ)
7d1c45d3
AW
139 ((,obj) (make-ghil-quote e l obj)))
140
141 (quasiquote
c7228382 142 ;; (quasiquote OBJ)
124c52d8 143 ((,obj) (make-ghil-quasiquote e l (trans-quasiquote e l obj 0))))
7d1c45d3
AW
144
145 (define
146 ;; (define NAME VAL)
2e7e6969
AW
147 ((,name ,val) (guard (symbol? name)
148 (ghil-toplevel-env? (ghil-env-parent e)))
7d1c45d3 149 (make-ghil-define e l (ghil-define (ghil-env-parent e) name)
5dcf8f35 150 (maybe-name-value! (retrans val) name)))
7d1c45d3
AW
151 ;; (define (NAME FORMALS...) BODY...)
152 (((,name . ,formals) . ,body) (guard (symbol? name))
153 ;; -> (define NAME (lambda FORMALS BODY...))
154 (retrans `(define ,name (lambda ,formals ,@body)))))
155
156 (set!
157 ;; (set! NAME VAL)
158 ((,name ,val) (guard (symbol? name))
159 (make-ghil-set e l (ghil-lookup e name) (retrans val)))
160
161 ;; (set! (NAME ARGS...) VAL)
162 (((,name . ,args) ,val) (guard (symbol? name))
163 ;; -> ((setter NAME) ARGS... VAL)
164 (retrans `((setter ,name) . (,@args ,val)))))
165
166 (if
c7228382 167 ;; (if TEST THEN [ELSE])
7d1c45d3
AW
168 ((,test ,then)
169 (make-ghil-if e l (retrans test) (retrans then) (retrans '(begin))))
170 ((,test ,then ,else)
171 (make-ghil-if e l (retrans test) (retrans then) (retrans else))))
c7228382 172
7d1c45d3 173 (and
c7228382 174 ;; (and EXPS...)
7d1c45d3 175 (,tail (make-ghil-and e l (map retrans tail))))
c7228382 176
7d1c45d3 177 (or
c7228382 178 ;; (or EXPS...)
7d1c45d3
AW
179 (,tail (make-ghil-or e l (map retrans tail))))
180
181 (begin
182 ;; (begin EXPS...)
183 (,tail (make-ghil-begin e l (map retrans tail))))
184
185 (let
186 ;; (let NAME ((SYM VAL) ...) BODY...)
187 ((,name ,bindings . ,body) (guard (symbol? name)
188 (valid-bindings? bindings))
189 ;; -> (letrec ((NAME (lambda (SYM...) BODY...))) (NAME VAL...))
190 (retrans `(letrec ((,name (lambda ,(map car bindings) ,@body)))
191 (,name ,@(map cadr bindings)))))
192
193 ;; (let () BODY...)
194 ((() . ,body)
195 ;; Note: this differs from `begin'
196 (make-ghil-begin e l (list (trans-body e l body))))
197
198 ;; (let ((SYM VAL) ...) BODY...)
199 ((,bindings . ,body) (guard (valid-bindings? bindings))
200 (let ((vals (map retrans (map cadr bindings))))
201 (call-with-ghil-bindings e (map car bindings)
202 (lambda (vars)
203 (make-ghil-bind e l vars vals (trans-body e l body)))))))
204
205 (let*
c7228382 206 ;; (let* ((SYM VAL) ...) BODY...)
7d1c45d3
AW
207 ((() . ,body)
208 (retrans `(let () ,@body)))
209 ((((,sym ,val) . ,rest) . ,body) (guard (symbol? sym))
210 (retrans `(let ((,sym ,val)) (let* ,rest ,@body)))))
c7228382 211
7d1c45d3 212 (letrec
c7228382 213 ;; (letrec ((SYM VAL) ...) BODY...)
7d1c45d3
AW
214 ((,bindings . ,body) (guard (valid-bindings? bindings))
215 (call-with-ghil-bindings e (map car bindings)
216 (lambda (vars)
217 (let ((vals (map retrans (map cadr bindings))))
218 (make-ghil-bind e l vars vals (trans-body e l body)))))))
c7228382 219
7d1c45d3 220 (cond
c7228382 221 ;; (cond (CLAUSE BODY...) ...)
7d1c45d3 222 (() (retrans '(begin)))
cd702346 223 (((else . ,body)) (retrans `(begin ,@body)))
7d1c45d3
AW
224 (((,test) . ,rest) (retrans `(or ,test (cond ,@rest))))
225 (((,test => ,proc) . ,rest)
226 ;; FIXME hygiene!
227 (retrans `(let ((_t ,test)) (if _t (,proc _t) (cond ,@rest)))))
228 (((,test . ,body) . ,rest)
229 (retrans `(if ,test (begin ,@body) (cond ,@rest)))))
230
231 (case
c7228382 232 ;; (case EXP ((KEY...) BODY...) ...)
7d1c45d3
AW
233 ((,exp . ,clauses)
234 (retrans
235 ;; FIXME hygiene!
236 `(let ((_t ,exp))
237 ,(let loop ((ls clauses))
238 (cond ((null? ls) '(begin))
239 ((eq? (caar ls) 'else) `(begin ,@(cdar ls)))
240 (else `(if (memv _t ',(caar ls))
241 (begin ,@(cdar ls))
242 ,(loop (cdr ls))))))))))
243
244 (do
245 ;; (do ((SYM VAL [UPDATE]) ...) (TEST RESULT...) BODY...)
246 ((,bindings (,test . ,result) . ,body)
247 (let ((sym (map car bindings))
248 (val (map cadr bindings))
249 (update (map cddr bindings)))
250 (define (next s x) (if (pair? x) (car x) s))
251 (retrans
f245e62c 252 ;; FIXME hygiene!
7d1c45d3
AW
253 `(letrec ((_l (lambda ,sym
254 (if ,test
255 (begin ,@result)
256 (begin ,@body
257 (_l ,@(map next sym update)))))))
258 (_l ,@val))))))
259
260 (lambda
261 ;; (lambda FORMALS BODY...)
262 ((,formals . ,body)
263 (receive (syms rest) (parse-formals formals)
264 (call-with-ghil-environment e syms
2e7e6969
AW
265 (lambda (env vars)
266 (receive (meta body) (parse-lambda-meta body)
267 (make-ghil-lambda env l vars rest meta
268 (trans-body env l body))))))))
7d1c45d3 269
7024b583
AW
270 ;; FIXME not hygienic
271 (delay
272 ((,expr)
273 (retrans `(make-promise (lambda () ,expr)))))
274
7d1c45d3 275 (eval-case
e0092405 276 (,clauses
7d1c45d3 277 (retrans
e0092405 278 `(begin
2e7e6969
AW
279 ;; Compilation of toplevel units is always wrapped in a lambda
280 ,@(let ((toplevel? (ghil-toplevel-env? (ghil-env-parent e))))
e0092405
AW
281 (let loop ((seen '()) (in clauses) (runtime '()))
282 (cond
283 ((null? in) runtime)
284 (else
285 (pmatch (car in)
286 ((else . ,body)
bd76c6d3 287 (if (and toplevel? (not (memq *the-compile-toplevel-symbol* seen)))
e0092405 288 (primitive-eval `(begin ,@body)))
bd76c6d3 289 (if (memq (if toplevel? *the-compile-toplevel-symbol* 'evaluate) seen)
e0092405
AW
290 runtime
291 body))
292 ((,keys . ,body) (guard (list? keys) (and-map symbol? keys))
293 (for-each (lambda (k)
294 (if (memq k seen)
295 (syntax-error l "eval-case condition seen twice" k)))
296 keys)
bd76c6d3 297 (if (and toplevel? (memq *the-compile-toplevel-symbol* keys))
e0092405
AW
298 (primitive-eval `(begin ,@body)))
299 (loop (append keys seen)
300 (cdr in)
301 (if (memq (if toplevel? 'load-toplevel 'evaluate) keys)
302 (append runtime body)
303 runtime)))
373d251b
AW
304 (else (syntax-error l "bad eval-case clause" (car in))))))))))))
305
ef24c01b
AW
306 ;; FIXME: not hygienic, relies on @apply not being shadowed
307 (apply
308 (,args (retrans `(@apply ,@args))))
309
310 (@apply
311 ((,proc ,arg1 . ,args)
312 (let ((args (cons (retrans arg1) (map retrans args))))
313 (cond ((and (symbol? proc)
314 (not (ghil-lookup e proc #f))
315 (and=> (module-variable (current-module) proc)
316 (lambda (var)
317 (and (variable-bound? var)
318 (lookup-apply-transformer (variable-ref var))))))
319 ;; that is, a variable, not part of this compilation
320 ;; unit, but defined in the toplevel environment, and has
321 ;; an apply transformer registered
322 => (lambda (t) (t e l args)))
323 (else (make-ghil-inline e l 'apply
324 (cons (retrans proc) args)))))))
325
efbd5892
AW
326 ;; FIXME: not hygienic, relies on @call-with-values not being shadowed
327 (call-with-values
328 ((,producer ,consumer)
329 (retrans `(@call-with-values ,producer ,consumer)))
330 (else #f))
331
332 (@call-with-values
333 ((,producer ,consumer)
334 (make-ghil-mv-call e l (retrans producer) (retrans consumer))))
335
76282387
AW
336 ;; FIXME: not hygienic, relies on @call-with-current-continuation
337 ;; not being shadowed
338 (call-with-current-continuation
339 ((,proc)
340 (retrans `(@call-with-current-continuation ,proc)))
341 (else #f))
342
343 (@call-with-current-continuation
344 ((,proc)
345 (make-ghil-inline e l 'call/cc (list (retrans proc)))))
346
d51406fe
AW
347 (receive
348 ((,formals ,producer-exp . ,body)
349 ;; Lovely, self-referential usage. Not strictly necessary, the
350 ;; macro would do the trick; but it's good to test the mv-bind
351 ;; code.
352 (receive (syms rest) (parse-formals formals)
353 (call-with-ghil-bindings e syms
354 (lambda (vars)
355 (make-ghil-mv-bind e l (retrans `(lambda () ,producer-exp))
356 vars rest (trans-body e l body)))))))
357
a222b0fa
AW
358 (values
359 ((,x) (retrans x))
360 (,args (make-ghil-values e l (map retrans args))))))
c7228382 361
ef24c01b
AW
362(define (lookup-apply-transformer proc)
363 (cond ((eq? proc values)
364 (lambda (e l args)
365 (make-ghil-values* e l args)))
366 (else #f)))
367
124c52d8 368(define (trans-quasiquote e l x level)
c7228382
KN
369 (cond ((not (pair? x)) x)
370 ((memq (car x) '(unquote unquote-splicing))
371 (let ((l (location x)))
f245e62c
AW
372 (pmatch (cdr x)
373 ((,obj)
124c52d8
AW
374 (cond
375 ((zero? level)
376 (if (eq? (car x) 'unquote)
377 (make-ghil-unquote e l (trans e l obj))
378 (make-ghil-unquote-splicing e l (trans e l obj))))
379 (else
380 (list (car x) (trans-quasiquote e l obj (1- level))))))
c7228382 381 (else (syntax-error l (format #f "bad ~A" (car x)) x)))))
124c52d8
AW
382 ((eq? (car x) 'quasiquote)
383 (let ((l (location x)))
384 (pmatch (cdr x)
385 ((,obj) (list 'quasiquote (trans-quasiquote e l obj (1+ level))))
386 (else (syntax-error l (format #f "bad ~A" (car x)) x)))))
387 (else (cons (trans-quasiquote e l (car x) level)
388 (trans-quasiquote e l (cdr x) level)))))
c7228382
KN
389
390(define (trans-body e l body)
391 (define (define->binding df)
f245e62c
AW
392 (pmatch (cdr df)
393 ((,name ,val) (guard (symbol? name)) (list name val))
394 (((,name . ,formals) . ,body) (guard (symbol? name))
c7228382
KN
395 (list name `(lambda ,formals ,@body)))
396 (else (syntax-error (location df) "bad define" df))))
397 ;; main
398 (let loop ((ls body) (ds '()))
be852e52
AW
399 (pmatch ls
400 (() (syntax-error l "bad body" body))
401 (((define . _) . _)
402 (loop (cdr ls) (cons (car ls) ds)))
403 (else
404 (if (null? ds)
7d1c45d3
AW
405 (trans e l `(begin ,@ls))
406 (trans e l `(letrec ,(map define->binding ds) ,@ls)))))))
c7228382
KN
407
408(define (parse-formals formals)
409 (cond
410 ;; (lambda x ...)
411 ((symbol? formals) (values (list formals) #t))
412 ;; (lambda (x y z) ...)
413 ((list? formals) (values formals #f))
414 ;; (lambda (x y . z) ...)
415 ((pair? formals)
416 (let loop ((l formals) (v '()))
417 (if (pair? l)
418 (loop (cdr l) (cons (car l) v))
419 (values (reverse! (cons l v)) #t))))
420 (else (syntax-error (location formals) "bad formals" formals))))
421
fbde2b91
AW
422(define (parse-lambda-meta body)
423 (cond ((or (null? body) (null? (cdr body))) (values '() body))
424 ((string? (car body))
425 (values `((documentation . ,(car body))) (cdr body)))
426 (else (values '() body))))
427
5dcf8f35
AW
428(define (maybe-name-value! val name)
429 (cond
430 ((ghil-lambda? val)
431 (if (not (assq-ref (ghil-lambda-meta val) 'name))
432 (set! (ghil-lambda-meta val)
433 (acons 'name name (ghil-lambda-meta val))))))
434 val)
435
c7228382
KN
436(define (location x)
437 (and (pair? x)
438 (let ((props (source-properties x)))
439 (and (not (null? props))
96969dc1
AW
440 (vector (assq-ref props 'line)
441 (assq-ref props 'column)
442 (assq-ref props 'filename))))))