mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-30 15:00:21 +02:00
Slowly improving support for macro compilation.
* module/language/scheme/translate.scm (¤t-macros): Removed. (¤t-macro-module): Removed. (&compile-time-module): New. (eval-at-compile-time): New. (translate): Initialize `&compile-time-module'. (expand-macro)[use-syntax]: New case. [begin let...]: Don't expand these built-in macros. [else]: Rewrote the macro detection and invocation logic. Invoke macro transformers in the current compile-time module. (trans): Let `expand-macro' raise an exception if needed. (trans-pair)[defmacro define-macro]: Evaluate the macro definition in the compile-time module. * testsuite/t-match.scm: Use `use-syntax' instead of `use-modules' for `(ice-9 match)' and `(srfi srfi-9)'. * testsuite/t-records.scm: Likewise. git-archimport-id: lcourtes@laas.fr--2005-mobile/guile-vm--mobile--0.6--patch-15
This commit is contained in:
parent
e274f1c232
commit
b89fc2153e
3 changed files with 85 additions and 52 deletions
|
@ -29,18 +29,26 @@
|
||||||
:export (translate))
|
:export (translate))
|
||||||
|
|
||||||
|
|
||||||
;; Hash table containing the macros currently defined.
|
;; Module in which compile-time code (macros) is evaluated.
|
||||||
(define ¤t-macros (make-parameter #f))
|
(define &compile-time-module (make-parameter #f))
|
||||||
|
|
||||||
;; Module in which macros are evaluated.
|
(define (eval-at-compile-time exp)
|
||||||
(define ¤t-macro-module (make-parameter #f))
|
"Evaluate @var{exp} in the current compile-time module."
|
||||||
|
(catch #t
|
||||||
|
(lambda ()
|
||||||
|
(save-module-excursion
|
||||||
|
(lambda ()
|
||||||
|
(eval exp (&compile-time-module)))))
|
||||||
|
(lambda (key . args)
|
||||||
|
(syntax-error #f
|
||||||
|
(format #f "~a: compile-time evaluation failed" exp)
|
||||||
|
(cons key args)))))
|
||||||
|
|
||||||
(define (translate x e)
|
(define (translate x e)
|
||||||
(parameterize ((¤t-macros (make-hash-table))
|
(parameterize ((&compile-time-module (make-module)))
|
||||||
(¤t-macro-module (make-module)))
|
|
||||||
|
|
||||||
;; Import only core bindings in the macro module.
|
;; Import only core bindings in the macro module.
|
||||||
(module-use! (¤t-macro-module) (resolve-module '(guile-user)))
|
(module-use! (&compile-time-module) the-root-module)
|
||||||
|
|
||||||
(call-with-ghil-environment (make-ghil-mod e) '()
|
(call-with-ghil-environment (make-ghil-mod e) '()
|
||||||
(lambda (env vars)
|
(lambda (env vars)
|
||||||
|
@ -54,34 +62,57 @@
|
||||||
(define (expand-macro e)
|
(define (expand-macro e)
|
||||||
;; Similar to `macroexpand' in `boot-9.scm' except that it does not expand
|
;; Similar to `macroexpand' in `boot-9.scm' except that it does not expand
|
||||||
;; `define-macro' and `defmacro'.
|
;; `define-macro' and `defmacro'.
|
||||||
|
|
||||||
;; FIXME: This does not handle macros defined in modules used by the
|
|
||||||
;; module being compiled.
|
|
||||||
(cond
|
(cond
|
||||||
((pair? e)
|
((pair? e)
|
||||||
(let* ((head (car e))
|
(let* ((head (car e))
|
||||||
(val (and (symbol? head)
|
(val (and (symbol? head)
|
||||||
(false-if-exception
|
(false-if-exception
|
||||||
(module-ref (¤t-macro-module) head)))))
|
(module-ref (&compile-time-module) head)))))
|
||||||
(case head
|
(case head
|
||||||
((defmacro define-macro)
|
((defmacro define-macro)
|
||||||
;; Normally, these are expanded as `defmacro:transformer' but we
|
;; Normally, these are expanded as `defmacro:transformer' but we
|
||||||
;; don't want it to happen.
|
;; don't want it to happen since they are handled by `trans-pair'.
|
||||||
e)
|
e)
|
||||||
|
|
||||||
|
((use-syntax)
|
||||||
|
;; `use-syntax' is used to express a compile-time dependency
|
||||||
|
;; (because we use a macro from that module, or because one of our
|
||||||
|
;; macros uses bindings from that module). Thus, we arrange to get
|
||||||
|
;; the current compile-time module to use it.
|
||||||
|
(let* ((module-name (cadr e))
|
||||||
|
(module (false-if-exception (resolve-module module-name))))
|
||||||
|
(if (module? module)
|
||||||
|
(let ((public-if (module-public-interface module)))
|
||||||
|
(module-use! (&compile-time-module) public-if))
|
||||||
|
(syntax-error #f "invalid `use-syntax' form" e)))
|
||||||
|
'(void))
|
||||||
|
|
||||||
|
((begin let let* letrec lambda quote quasiquote if and or
|
||||||
|
set! cond case eval-case define do)
|
||||||
|
;; All these built-in macros should not be expanded.
|
||||||
|
e)
|
||||||
|
|
||||||
(else
|
(else
|
||||||
(if (defmacro? val) ;; built-in macro?
|
;; Look for a macro.
|
||||||
(expand-macro (apply (defmacro-transformer val) (cdr e)))
|
(let ((ref (false-if-exception
|
||||||
(let ((local-macro (hashq-ref (¤t-macros) head)))
|
(module-ref (&compile-time-module) head))))
|
||||||
(if (not local-macro)
|
(if (macro? ref)
|
||||||
e
|
|
||||||
(if (procedure? local-macro)
|
|
||||||
(expand-macro
|
(expand-macro
|
||||||
(save-module-excursion
|
(save-module-excursion
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(set-current-module (¤t-macro-module))
|
(let ((transformer (macro-transformer ref))
|
||||||
(apply local-macro (cdr e)))))
|
(syntax-error syntax-error))
|
||||||
(syntax-error #f (format #f "~a: invalid macro" head)
|
(set-current-module (&compile-time-module))
|
||||||
local-macro)))))))))
|
(catch #t
|
||||||
|
(lambda ()
|
||||||
|
(transformer (copy-tree e) (current-module)))
|
||||||
|
(lambda (key . args)
|
||||||
|
(syntax-error #f
|
||||||
|
(format #f "~a: macro transformer failed"
|
||||||
|
head)
|
||||||
|
(cons key args))))))))
|
||||||
|
e))))))
|
||||||
|
|
||||||
(#t e)))
|
(#t e)))
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,12 +132,10 @@
|
||||||
|
|
||||||
(define (trans e l x)
|
(define (trans e l x)
|
||||||
(cond ((pair? x)
|
(cond ((pair? x)
|
||||||
(let ((y (false-if-exception (expand-macro x))))
|
(let ((y (expand-macro x)))
|
||||||
(if (not y)
|
|
||||||
(syntax-error l "failed to expand macro" x)
|
|
||||||
(if (eq? x y)
|
(if (eq? x y)
|
||||||
(trans-pair e (or (location x) l) (car x) (cdr x))
|
(trans-pair e (or (location x) l) (car x) (cdr x))
|
||||||
(trans e l y)))))
|
(trans e l y))))
|
||||||
((symbol? x)
|
((symbol? x)
|
||||||
(let ((y (symbol-expand x)))
|
(let ((y (symbol-expand x)))
|
||||||
(if (symbol? y)
|
(if (symbol? y)
|
||||||
|
@ -164,24 +193,11 @@
|
||||||
|
|
||||||
;; simple macros
|
;; simple macros
|
||||||
((defmacro define-macro)
|
((defmacro define-macro)
|
||||||
(let* ((shortcut? (eq? head 'defmacro))
|
;; Evaluate the macro definition in the current compile-time module.
|
||||||
(macro-name (if shortcut? (car tail) (caar tail)))
|
(eval-at-compile-time (cons head tail))
|
||||||
(formal-args (if shortcut? (cadr tail) (cdar tail)))
|
|
||||||
(body (if shortcut? (cddr tail) (cdr tail))))
|
|
||||||
|
|
||||||
;; Evaluate the macro in the current macro module.
|
;; FIXME: We need to evaluate them in the runtime module as well.
|
||||||
(hashq-set! (¤t-macros) macro-name
|
(make:void))
|
||||||
(catch #t
|
|
||||||
(lambda ()
|
|
||||||
(eval `(lambda ,formal-args ,@body)
|
|
||||||
(¤t-macro-module)))
|
|
||||||
(lambda (key . args)
|
|
||||||
(syntax-error l (string-append "failed to evaluate "
|
|
||||||
"macro `" macro-name
|
|
||||||
"'")
|
|
||||||
(cons key args)))))
|
|
||||||
|
|
||||||
(make:void)))
|
|
||||||
|
|
||||||
((set!)
|
((set!)
|
||||||
(match tail
|
(match tail
|
||||||
|
@ -324,7 +340,7 @@
|
||||||
(else
|
(else
|
||||||
(if (memq head %scheme-primitives)
|
(if (memq head %scheme-primitives)
|
||||||
(<ghil-inline> e l head (map trans:x tail))
|
(<ghil-inline> e l head (map trans:x tail))
|
||||||
(if (member head %forbidden-primitives)
|
(if (memq head %forbidden-primitives)
|
||||||
(syntax-error l (format #f "`~a' is forbidden" head)
|
(syntax-error l (format #f "`~a' is forbidden" head)
|
||||||
(cons head tail))
|
(cons head tail))
|
||||||
(<ghil-call> e l (trans:x head) (map trans:x tail)))))))
|
(<ghil-call> e l (trans:x head) (map trans:x tail)))))))
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
(use-modules (ice-9 match)
|
;;; Pattern matching with `(ice-9 match)'.
|
||||||
(srfi srfi-9)) ;; record type
|
;;;
|
||||||
|
|
||||||
|
;; Both modules are compile-time dependencies, hence `use-syntax'.
|
||||||
|
(use-syntax (ice-9 match))
|
||||||
|
(use-syntax (srfi srfi-9)) ;; record type (FIXME: See `t-records.scm')
|
||||||
|
|
||||||
(define-record-type <stuff>
|
(define-record-type <stuff>
|
||||||
(%make-stuff chbouib)
|
(%make-stuff chbouib)
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
(use-modules (srfi srfi-9))
|
;;; SRFI-9 Records.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
;; SRFI-9 is a compile-time dependency (it exports the `define-record-type'
|
||||||
|
;; macro), hence the `use-syntax'.
|
||||||
|
;;
|
||||||
|
;; FIXME: The current definition of `use-syntax' in `boot-9.scm' is broken
|
||||||
|
;; and is not consistent with what happens when using:
|
||||||
|
;;
|
||||||
|
;; (define-module (module) :use-syntax (chbouib))
|
||||||
|
;;
|
||||||
|
;; This precludes the test-suite from running this program using the
|
||||||
|
;; interpreter.
|
||||||
|
(use-syntax (srfi srfi-9))
|
||||||
|
|
||||||
(define-record-type <stuff>
|
(define-record-type <stuff>
|
||||||
(%make-stuff chbouib)
|
(%make-stuff chbouib)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue