remove define-private
[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)
f245e62c 23 :use-module (system base pmatch)
c7228382
KN
24 :use-module (system base language)
25 :use-module (system il ghil)
c7228382 26 :use-module (ice-9 receive)
2335fb97 27 :use-module (srfi srfi-39)
48302624 28 :use-module ((system base compile) :select (syntax-error))
c7228382
KN
29 :export (translate))
30
2335fb97 31
b89fc215
LC
32;; Module in which compile-time code (macros) is evaluated.
33(define &compile-time-module (make-parameter #f))
34
35(define (eval-at-compile-time exp)
36 "Evaluate @var{exp} in the current compile-time module."
37 (catch #t
38 (lambda ()
39 (save-module-excursion
40 (lambda ()
41 (eval exp (&compile-time-module)))))
42 (lambda (key . args)
43 (syntax-error #f
44 (format #f "~a: compile-time evaluation failed" exp)
45 (cons key args)))))
9dbbe4bb 46
c7228382 47(define (translate x e)
b89fc215 48 (parameterize ((&compile-time-module (make-module)))
9dbbe4bb
LC
49
50 ;; Import only core bindings in the macro module.
b89fc215 51 (module-use! (&compile-time-module) the-root-module)
9dbbe4bb 52
2335fb97
LC
53 (call-with-ghil-environment (make-ghil-mod e) '()
54 (lambda (env vars)
849cefac 55 (make-ghil-lambda env #f vars #f (trans env #f x))))))
2335fb97
LC
56
57\f
58;;;
59;;; Macro tricks
60;;;
61
62(define (expand-macro e)
63 ;; Similar to `macroexpand' in `boot-9.scm' except that it does not expand
64 ;; `define-macro' and `defmacro'.
65 (cond
66 ((pair? e)
67 (let* ((head (car e))
9dbbe4bb
LC
68 (val (and (symbol? head)
69 (false-if-exception
b89fc215 70 (module-ref (&compile-time-module) head)))))
2335fb97
LC
71 (case head
72 ((defmacro define-macro)
73 ;; Normally, these are expanded as `defmacro:transformer' but we
b89fc215
LC
74 ;; don't want it to happen since they are handled by `trans-pair'.
75 e)
76
77 ((use-syntax)
78 ;; `use-syntax' is used to express a compile-time dependency
79 ;; (because we use a macro from that module, or because one of our
80 ;; macros uses bindings from that module). Thus, we arrange to get
81 ;; the current compile-time module to use it.
82 (let* ((module-name (cadr e))
83 (module (false-if-exception (resolve-module module-name))))
84 (if (module? module)
85 (let ((public-if (module-public-interface module)))
86 (module-use! (&compile-time-module) public-if))
87 (syntax-error #f "invalid `use-syntax' form" e)))
88 '(void))
89
90 ((begin let let* letrec lambda quote quasiquote if and or
91 set! cond case eval-case define do)
92 ;; All these built-in macros should not be expanded.
2335fb97 93 e)
b89fc215 94
2335fb97 95 (else
b89fc215
LC
96 ;; Look for a macro.
97 (let ((ref (false-if-exception
98 (module-ref (&compile-time-module) head))))
99 (if (macro? ref)
100 (expand-macro
101 (save-module-excursion
102 (lambda ()
103 (let ((transformer (macro-transformer ref))
104 (syntax-error syntax-error))
105 (set-current-module (&compile-time-module))
106 (catch #t
107 (lambda ()
108 (transformer (copy-tree e) (current-module)))
109 (lambda (key . args)
110 (syntax-error #f
111 (format #f "~a: macro transformer failed"
112 head)
113 (cons key args))))))))
114 e))))))
115
2335fb97 116 (#t e)))
c7228382
KN
117
118\f
119;;;
120;;; Translator
121;;;
122
2335fb97 123(define %scheme-primitives
8f5cfc81
KN
124 '(not null? eq? eqv? equal? pair? list? cons car cdr set-car! set-cdr!))
125
2335fb97
LC
126(define %forbidden-primitives
127 ;; Guile's `procedure->macro' family is evil because it crosses the
128 ;; compilation boundary. One solution might be to evaluate calls to
129 ;; `procedure->memoizing-macro' at compilation time, but it may be more
130 ;; compicated than that.
131 '(procedure->syntax procedure->macro procedure->memoizing-macro))
132
c7228382
KN
133(define (trans e l x)
134 (cond ((pair? x)
b89fc215
LC
135 (let ((y (expand-macro x)))
136 (if (eq? x y)
137 (trans-pair e (or (location x) l) (car x) (cdr x))
138 (trans e l y))))
f21dfea6 139 ((symbol? x)
ac99cb0c
KN
140 (let ((y (symbol-expand x)))
141 (if (symbol? y)
849cefac 142 (make-ghil-ref e l (ghil-lookup e y))
b6368dbb 143 (trans e l y))))
849cefac 144 (else (make-ghil-quote e l x))))
c7228382 145
ac99cb0c 146(define (symbol-expand x)
f21dfea6
KN
147 (let loop ((s (symbol->string x)))
148 (let ((i (string-rindex s #\.)))
149 (if i
ac99cb0c
KN
150 (let ((sym (string->symbol (substring s (1+ i)))))
151 `(slot ,(loop (substring s 0 i)) (quote ,sym)))
152 (string->symbol s)))))
f21dfea6 153
f245e62c
AW
154(define (valid-bindings? bindings . it-is-for-do)
155 (define (valid-binding? b)
156 (pmatch b
157 ((,sym ,var) (guard (symbol? sym)) #t)
158 ((,sym ,var ,update) (guard (pair? it-is-for-do) (symbol? sym)) #t)
159 (else #f)))
160 (and (list? bindings) (and-map valid-binding? bindings)))
161
c7228382
KN
162(define (trans-pair e l head tail)
163 (define (trans:x x) (trans e l x))
164 (define (trans:pair x) (trans-pair e l (car x) (cdr x)))
165 (define (trans:body body) (trans-body e l body))
849cefac 166 (define (make:void) (make-ghil-void e l))
c7228382
KN
167 (define (bad-syntax)
168 (syntax-error l (format #f "bad ~A" head) (cons head tail)))
f245e62c
AW
169 ;; have to use a case first, because pmatch treats e.g. (quote foo)
170 ;; and (unquote foo) specially
c7228382
KN
171 (case head
172 ;; (void)
173 ((void)
f245e62c 174 (pmatch tail
c7228382
KN
175 (() (make:void))
176 (else (bad-syntax))))
177
178 ;; (quote OBJ)
179 ((quote)
f245e62c
AW
180 (pmatch tail
181 ((,obj) (make-ghil-quote e l obj))
c7228382
KN
182 (else (bad-syntax))))
183
184 ;; (quasiquote OBJ)
185 ((quasiquote)
f245e62c
AW
186 (pmatch tail
187 ((,obj) (make-ghil-quasiquote e l (trans-quasiquote e l obj)))
c7228382
KN
188 (else (bad-syntax))))
189
fbbc50ca 190 ((define)
f245e62c 191 (pmatch tail
c7228382 192 ;; (define NAME VAL)
9f8ec6eb 193 ((,name ,val) (guard (symbol? name))
f245e62c 194 (make-ghil-define e l (ghil-lookup e name) (trans:x val)))
c7228382
KN
195
196 ;; (define (NAME FORMALS...) BODY...)
f245e62c
AW
197 (((,name . ,formals) . ,body) (guard (symbol? name))
198 ;; -> (define NAME (lambda FORMALS BODY...))
199 (let ((val (trans:x `(lambda ,formals ,@body))))
200 (make-ghil-define e l (ghil-lookup e name) val)))
c7228382
KN
201
202 (else (bad-syntax))))
203
2335fb97
LC
204 ;; simple macros
205 ((defmacro define-macro)
b89fc215
LC
206 ;; Evaluate the macro definition in the current compile-time module.
207 (eval-at-compile-time (cons head tail))
208
209 ;; FIXME: We need to evaluate them in the runtime module as well.
210 (make:void))
2335fb97 211
c7228382 212 ((set!)
f245e62c 213 (pmatch tail
c7228382 214 ;; (set! NAME VAL)
f245e62c
AW
215 ((,name ,val) (guard (symbol? name))
216 (make-ghil-set e l (ghil-lookup e name) (trans:x val)))
c7228382
KN
217
218 ;; (set! (NAME ARGS...) VAL)
f245e62c
AW
219 (((,name . ,args) ,val) (guard (symbol? name))
220 ;; -> ((setter NAME) ARGS... VAL)
221 (trans:pair `((setter ,name) . (,@args ,val))))
c7228382
KN
222
223 (else (bad-syntax))))
224
225 ;; (if TEST THEN [ELSE])
226 ((if)
f245e62c
AW
227 (pmatch tail
228 ((,test ,then)
229 (make-ghil-if e l (trans:x test) (trans:x then) (make:void)))
230 ((,test ,then ,else)
231 (make-ghil-if e l (trans:x test) (trans:x then) (trans:x else)))
c7228382
KN
232 (else (bad-syntax))))
233
234 ;; (and EXPS...)
235 ((and)
849cefac 236 (make-ghil-and e l (map trans:x tail)))
c7228382
KN
237
238 ;; (or EXPS...)
239 ((or)
849cefac 240 (make-ghil-or e l (map trans:x tail)))
c7228382
KN
241
242 ;; (begin EXPS...)
243 ((begin)
849cefac 244 (make-ghil-begin e l (map trans:x tail)))
c7228382
KN
245
246 ((let)
f245e62c 247 (pmatch tail
c7228382 248 ;; (let NAME ((SYM VAL) ...) BODY...)
f245e62c
AW
249 ((,name ,bindings . ,body) (guard (symbol? name)
250 (valid-bindings? bindings))
251 ;; -> (letrec ((NAME (lambda (SYM...) BODY...))) (NAME VAL...))
252 (trans:pair `(letrec ((,name (lambda ,(map car bindings) ,@body)))
253 (,name ,@(map cadr bindings)))))
c7228382
KN
254
255 ;; (let () BODY...)
f245e62c
AW
256 ((() . ,body)
257 ;; Note: this differs from `begin'
258 (make-ghil-begin e l (list (trans:body body))))
c7228382
KN
259
260 ;; (let ((SYM VAL) ...) BODY...)
f245e62c 261 ((,bindings . ,body) (guard (valid-bindings? bindings))
9f8ec6eb
AW
262 (let ((vals (map trans:x (map cadr bindings))))
263 (call-with-ghil-bindings e (map car bindings)
f245e62c
AW
264 (lambda (vars)
265 (make-ghil-bind e l vars vals (trans:body body))))))
c7228382
KN
266 (else (bad-syntax))))
267
268 ;; (let* ((SYM VAL) ...) BODY...)
269 ((let*)
f245e62c
AW
270 (pmatch tail
271 ((() . ,body)
272 (trans:pair `(let () ,@body)))
273 ((((,sym ,val) . ,rest) . ,body) (guard (symbol? sym))
274 (trans:pair `(let ((,sym ,val)) (let* ,rest ,@body))))
c7228382
KN
275 (else (bad-syntax))))
276
277 ;; (letrec ((SYM VAL) ...) BODY...)
278 ((letrec)
f245e62c
AW
279 (pmatch tail
280 ((,bindings . ,body) (guard (valid-bindings? bindings))
281 (call-with-ghil-bindings e (map car bindings)
282 (lambda (vars)
283 (let ((vals (map trans:x (map cadr bindings))))
284 (make-ghil-bind e l vars vals (trans:body body))))))
c7228382
KN
285 (else (bad-syntax))))
286
287 ;; (cond (CLAUSE BODY...) ...)
288 ((cond)
f245e62c 289 (pmatch tail
c7228382 290 (() (make:void))
f245e62c
AW
291 (((else . ,body)) (trans:body body))
292 (((,test) . ,rest) (trans:pair `(or ,test (cond ,@rest))))
293 (((,test => ,proc) . ,rest)
294 ;; FIXME hygiene!
295 (trans:pair `(let ((_t ,test)) (if _t (,proc _t) (cond ,@rest)))))
296 (((,test . ,body) . ,rest)
297 (trans:pair `(if ,test (begin ,@body) (cond ,@rest))))
c7228382
KN
298 (else (bad-syntax))))
299
300 ;; (case EXP ((KEY...) BODY...) ...)
301 ((case)
f245e62c
AW
302 (pmatch tail
303 ((,exp . ,clauses)
304 (trans:pair
305 ;; FIXME hygiene!
306 `(let ((_t ,exp))
307 ,(let loop ((ls clauses))
308 (cond ((null? ls) '(void))
309 ((eq? (caar ls) 'else) `(begin ,@(cdar ls)))
310 (else `(if (memv _t ',(caar ls))
311 (begin ,@(cdar ls))
312 ,(loop (cdr ls)))))))))
c7228382
KN
313 (else (bad-syntax))))
314
315 ;; (do ((SYM VAL [UPDATE]) ...) (TEST RESULT...) BODY...)
316 ((do)
f245e62c
AW
317 (pmatch tail
318 ((,bindings (,test . ,result) . ,body)
319 (let ((sym (map car bindings))
320 (val (map cadr bindings))
321 (update (map cddr bindings)))
322 (define (next s x) (if (pair? x) (car x) s))
323 (trans:pair
324 ;; FIXME hygiene!
325 `(letrec ((_l (lambda ,sym
326 (if ,test
327 (let () (void) ,@result)
328 (let () (void) ,@body
329 (_l ,@(map next sym update)))))))
9f8ec6eb 330 (_l ,@val)))))
f245e62c 331 (else (bad-syntax))))
c7228382
KN
332
333 ;; (lambda FORMALS BODY...)
334 ((lambda)
f245e62c
AW
335 (pmatch tail
336 ((,formals . ,body)
337 (receive (syms rest) (parse-formals formals)
338 (call-with-ghil-environment e syms
339 (lambda (env vars)
340 (make-ghil-lambda env l vars rest (trans-body env l body))))))
c7228382
KN
341 (else (bad-syntax))))
342
343 ((eval-case)
344 (let loop ((x tail))
f245e62c
AW
345 (pmatch x
346 (() (make:void))
347 (((else . ,body)) (trans:pair `(begin ,@body)))
348 (((,keys . ,body) . ,rest) (guard (list? keys) (and-map symbol? keys))
349 (if (memq 'load-toplevel keys)
350 (begin
351 (primitive-eval `(begin ,@(copy-tree body)))
352 (trans:pair `(begin ,@body)))
353 (loop rest)))
354 (else (bad-syntax)))))
c7228382
KN
355
356 (else
2335fb97 357 (if (memq head %scheme-primitives)
f245e62c
AW
358 (make-ghil-inline e l head (map trans:x tail))
359 (if (memq head %forbidden-primitives)
360 (syntax-error l (format #f "`~a' is forbidden" head)
361 (cons head tail))
362 (make-ghil-call e l (trans:x head) (map trans:x tail)))))))
c7228382
KN
363
364(define (trans-quasiquote e l x)
365 (cond ((not (pair? x)) x)
366 ((memq (car x) '(unquote unquote-splicing))
367 (let ((l (location x)))
f245e62c
AW
368 (pmatch (cdr x)
369 ((,obj)
c7228382 370 (if (eq? (car x) 'unquote)
849cefac
AW
371 (make-ghil-unquote e l (trans e l obj))
372 (make-ghil-unquote-splicing e l (trans e l obj))))
c7228382
KN
373 (else (syntax-error l (format #f "bad ~A" (car x)) x)))))
374 (else (cons (trans-quasiquote e l (car x))
375 (trans-quasiquote e l (cdr x))))))
376
377(define (trans-body e l body)
378 (define (define->binding df)
f245e62c
AW
379 (pmatch (cdr df)
380 ((,name ,val) (guard (symbol? name)) (list name val))
381 (((,name . ,formals) . ,body) (guard (symbol? name))
c7228382
KN
382 (list name `(lambda ,formals ,@body)))
383 (else (syntax-error (location df) "bad define" df))))
384 ;; main
385 (let loop ((ls body) (ds '()))
be852e52
AW
386 (pmatch ls
387 (() (syntax-error l "bad body" body))
388 (((define . _) . _)
389 (loop (cdr ls) (cons (car ls) ds)))
390 (else
391 (if (null? ds)
392 (trans-pair e l 'begin ls)
393 (trans-pair e l 'letrec (cons (map define->binding ds) ls)))))))
c7228382
KN
394
395(define (parse-formals formals)
396 (cond
397 ;; (lambda x ...)
398 ((symbol? formals) (values (list formals) #t))
399 ;; (lambda (x y z) ...)
400 ((list? formals) (values formals #f))
401 ;; (lambda (x y . z) ...)
402 ((pair? formals)
403 (let loop ((l formals) (v '()))
404 (if (pair? l)
405 (loop (cdr l) (cons (car l) v))
406 (values (reverse! (cons l v)) #t))))
407 (else (syntax-error (location formals) "bad formals" formals))))
408
409(define (location x)
410 (and (pair? x)
411 (let ((props (source-properties x)))
412 (and (not (null? props))
413 (cons (assq-ref props 'line) (assq-ref props 'column))))))