1 ;;; Guile Scheme specification
3 ;; Copyright (C) 2001 Free Software Foundation, Inc.
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)
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.
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.
22 (define-module (language scheme translate)
23 :use-module (system base pmatch)
24 :use-module (system base language)
25 :use-module (system il ghil)
26 :use-module (ice-9 receive)
27 :use-module (srfi srfi-39)
28 :use-module ((system base compile) :select (syntax-error))
32 ;; Module in which compile-time code (macros) is evaluated.
33 (define &compile-time-module (make-parameter #f))
35 (define (eval-at-compile-time exp)
36 "Evaluate @var{exp} in the current compile-time module."
39 (save-module-excursion
41 (eval exp (&compile-time-module)))))
44 (format #f "~a: compile-time evaluation failed" exp)
47 (define (translate x e)
48 (parameterize ((&compile-time-module (make-module)))
50 ;; Import only core bindings in the macro module.
51 (module-use! (&compile-time-module) the-root-module)
53 (call-with-ghil-environment (make-ghil-mod e) '()
55 (make-ghil-lambda env #f vars #f (trans env #f x))))))
62 (define (expand-macro e)
63 ;; Similar to `macroexpand' in `boot-9.scm' except that it does not expand
64 ;; `define-macro' and `defmacro'.
68 (val (and (symbol? head)
70 (module-ref (&compile-time-module) head)))))
72 ((defmacro define-macro)
73 ;; Normally, these are expanded as `defmacro:transformer' but we
74 ;; don't want it to happen since they are handled by `trans-pair'.
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))))
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)))
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.
97 (let ((ref (false-if-exception
98 (module-ref (&compile-time-module) head))))
101 (save-module-excursion
103 (let ((transformer (macro-transformer ref))
104 (syntax-error syntax-error))
105 (set-current-module (&compile-time-module))
108 (transformer (copy-tree e) (current-module)))
111 (format #f "~a: macro transformer failed"
113 (cons key args))))))))
123 (define %scheme-primitives
124 '(not null? eq? eqv? equal? pair? list? cons car cdr set-car! set-cdr!))
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))
133 (define (trans e l x)
135 (let ((y (expand-macro x)))
137 (trans-pair e (or (location x) l) (car x) (cdr x))
140 (let ((y (symbol-expand x)))
142 (make-ghil-ref e l (ghil-lookup e y))
144 (else (make-ghil-quote e l x))))
146 (define (symbol-expand x)
147 (let loop ((s (symbol->string x)))
148 (let ((i (string-rindex s #\.)))
150 (let ((sym (string->symbol (substring s (1+ i)))))
151 `(slot ,(loop (substring s 0 i)) (quote ,sym)))
152 (string->symbol s)))))
154 (define (valid-bindings? bindings . it-is-for-do)
155 (define (valid-binding? b)
157 ((,sym ,var) (guard (symbol? sym)) #t)
158 ((,sym ,var ,update) (guard (pair? it-is-for-do) (symbol? sym)) #t)
160 (and (list? bindings) (and-map valid-binding? bindings)))
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))
166 (define (make:void) (make-ghil-void e l))
168 (syntax-error l (format #f "bad ~A" head) (cons head tail)))
169 ;; have to use a case first, because pmatch treats e.g. (quote foo)
170 ;; and (unquote foo) specially
176 (else (bad-syntax))))
181 ((,obj) (make-ghil-quote e l obj))
182 (else (bad-syntax))))
187 ((,obj) (make-ghil-quasiquote e l (trans-quasiquote e l obj)))
188 (else (bad-syntax))))
193 ((,name ,val) (guard (symbol? name))
194 (make-ghil-define e l (ghil-lookup e name) (trans:x val)))
196 ;; (define (NAME FORMALS...) BODY...)
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)))
202 (else (bad-syntax))))
205 ((defmacro define-macro)
206 ;; Evaluate the macro definition in the current compile-time module.
207 (eval-at-compile-time (cons head tail))
209 ;; FIXME: We need to evaluate them in the runtime module as well.
215 ((,name ,val) (guard (symbol? name))
216 (make-ghil-set e l (ghil-lookup e name) (trans:x val)))
218 ;; (set! (NAME ARGS...) VAL)
219 (((,name . ,args) ,val) (guard (symbol? name))
220 ;; -> ((setter NAME) ARGS... VAL)
221 (trans:pair `((setter ,name) . (,@args ,val))))
223 (else (bad-syntax))))
225 ;; (if TEST THEN [ELSE])
229 (make-ghil-if e l (trans:x test) (trans:x then) (make:void)))
231 (make-ghil-if e l (trans:x test) (trans:x then) (trans:x else)))
232 (else (bad-syntax))))
236 (make-ghil-and e l (map trans:x tail)))
240 (make-ghil-or e l (map trans:x tail)))
244 (make-ghil-begin e l (map trans:x tail)))
248 ;; (let NAME ((SYM VAL) ...) BODY...)
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)))))
257 ;; Note: this differs from `begin'
258 (make-ghil-begin e l (list (trans:body body))))
260 ;; (let ((SYM VAL) ...) BODY...)
261 ((,bindings . ,body) (guard (valid-bindings? bindings))
262 (let ((vals (map trans:x (map cadr bindings))))
263 (call-with-ghil-bindings e (map car bindings)
265 (make-ghil-bind e l vars vals (trans:body body))))))
266 (else (bad-syntax))))
268 ;; (let* ((SYM VAL) ...) BODY...)
272 (trans:pair `(let () ,@body)))
273 ((((,sym ,val) . ,rest) . ,body) (guard (symbol? sym))
274 (trans:pair `(let ((,sym ,val)) (let* ,rest ,@body))))
275 (else (bad-syntax))))
277 ;; (letrec ((SYM VAL) ...) BODY...)
280 ((,bindings . ,body) (guard (valid-bindings? bindings))
281 (call-with-ghil-bindings e (map car bindings)
283 (let ((vals (map trans:x (map cadr bindings))))
284 (make-ghil-bind e l vars vals (trans:body body))))))
285 (else (bad-syntax))))
287 ;; (cond (CLAUSE BODY...) ...)
291 (((else . ,body)) (trans:body body))
292 (((,test) . ,rest) (trans:pair `(or ,test (cond ,@rest))))
293 (((,test => ,proc) . ,rest)
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))))
298 (else (bad-syntax))))
300 ;; (case EXP ((KEY...) BODY...) ...)
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))
312 ,(loop (cdr ls)))))))))
313 (else (bad-syntax))))
315 ;; (do ((SYM VAL [UPDATE]) ...) (TEST RESULT...) BODY...)
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))
325 `(letrec ((_l (lambda ,sym
327 (let () (void) ,@result)
328 (let () (void) ,@body
329 (_l ,@(map next sym update)))))))
331 (else (bad-syntax))))
333 ;; (lambda FORMALS BODY...)
337 (receive (syms rest) (parse-formals formals)
338 (call-with-ghil-environment e syms
340 (make-ghil-lambda env l vars rest (trans-body env l body))))))
341 (else (bad-syntax))))
347 (((else . ,body)) (trans:pair `(begin ,@body)))
348 (((,keys . ,body) . ,rest) (guard (list? keys) (and-map symbol? keys))
349 (if (memq 'load-toplevel keys)
351 (primitive-eval `(begin ,@(copy-tree body)))
352 (trans:pair `(begin ,@body)))
354 (else (bad-syntax)))))
357 (if (memq head %scheme-primitives)
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)
362 (make-ghil-call e l (trans:x head) (map trans:x tail)))))))
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)))
370 (if (eq? (car x) 'unquote)
371 (make-ghil-unquote e l (trans e l obj))
372 (make-ghil-unquote-splicing e l (trans e l obj))))
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))))))
377 (define (trans-body e l body)
378 (define (define->binding df)
380 ((,name ,val) (guard (symbol? name)) (list name val))
381 (((,name . ,formals) . ,body) (guard (symbol? name))
382 (list name `(lambda ,formals ,@body)))
383 (else (syntax-error (location df) "bad define" df))))
385 (let loop ((ls body) (ds '()))
387 (() (syntax-error l "bad body" body))
389 (loop (cdr ls) (cons (car ls) ds)))
392 (trans-pair e l 'begin ls)
393 (trans-pair e l 'letrec (cons (map define->binding ds) ls)))))))
395 (define (parse-formals formals)
398 ((symbol? formals) (values (list formals) #t))
399 ;; (lambda (x y z) ...)
400 ((list? formals) (values formals #f))
401 ;; (lambda (x y . z) ...)
403 (let loop ((l formals) (v '()))
405 (loop (cdr l) (cons (car l) v))
406 (values (reverse! (cons l v)) #t))))
407 (else (syntax-error (location formals) "bad formals" formals))))
411 (let ((props (source-properties x)))
412 (and (not (null? props))
413 (cons (assq-ref props 'line) (assq-ref props 'column))))))