1
Fork 0
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 (&current-macros): Removed.
  (&current-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:
Ludovic Courtes 2006-07-30 21:01:40 +00:00 committed by Ludovic Courtès
parent e274f1c232
commit b89fc2153e
3 changed files with 85 additions and 52 deletions

View file

@ -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 &current-macros (make-parameter #f)) (define &compile-time-module (make-parameter #f))
;; Module in which macros are evaluated. (define (eval-at-compile-time exp)
(define &current-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 ((&current-macros (make-hash-table)) (parameterize ((&compile-time-module (make-module)))
(&current-macro-module (make-module)))
;; Import only core bindings in the macro module. ;; Import only core bindings in the macro module.
(module-use! (&current-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 (&current-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 (&current-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 (&current-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! (&current-macros) macro-name (make:void))
(catch #t
(lambda ()
(eval `(lambda ,formal-args ,@body)
(&current-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)))))))

View file

@ -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)

View file

@ -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)