1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-02 13:00:26 +02:00

Improved macro handling; started documenting the issue.

* doc/guile-vm.texi (Compiling Scheme Code): New node.

* module/language/scheme/translate.scm (&current-macro-module): New.
  (translate): Evaluate macros in `&current-macro-module'.
  (trans-pair): Likewise.

git-archimport-id: lcourtes@laas.fr--2005-mobile/guile-vm--mobile--0.6--patch-13
This commit is contained in:
Ludovic Courtes 2006-01-03 23:13:30 +00:00 committed by Ludovic Courtès
parent a316e42d98
commit 9dbbe4bb83
2 changed files with 77 additions and 18 deletions

View file

@ -121,6 +121,7 @@ The Compiler
* Overview:: * Overview::
* The Language Front-Ends:: * The Language Front-Ends::
* GHIL:: * GHIL::
* Compiling Scheme Code::
* GLIL:: * GLIL::
* The Assembler:: * The Assembler::
@ -737,6 +738,7 @@ Set}).
* Overview:: * Overview::
* The Language Front-Ends:: * The Language Front-Ends::
* GHIL:: * GHIL::
* Compiling Scheme Code::
* GLIL:: * GLIL::
* The Assembler:: * The Assembler::
@end menu @end menu
@ -815,12 +817,13 @@ the compiler to handle source written in that language. Of particular
interest is the @code{translator} slot (@pxref{GHIL}). interest is the @code{translator} slot (@pxref{GHIL}).
@end deftp @end deftp
@deffn @scmproc{} lookup-language symbol @deffn @scmproc{} lookup-language lang
Look for a language front-end named @var{symbol} and return the Look for a language front-end named @var{lang}, a symbol (e.g,
@code{<language>} record describing it if found. If @var{symbol} @code{scheme}), and return the @code{<language>} record describing it
doesn't denote a language front-end, an error is raised. Note that if found. If @var{lang} does not denote a language front-end, an
this procedure assumes that language @var{symbol} exists if there error is raised. Note that this procedure assumes that language
exist a @code{(language @var{symbol} spec)} module. @var{lang} exists if there exist a @code{(language @var{lang} spec)}
module.
@end deffn @end deffn
The @code{(system base compile)} module defines a procedure similar to The @code{(system base compile)} module defines a procedure similar to
@ -852,7 +855,7 @@ GHIL-to-GLIL compiler described in @xref{GLIL}.
@end deffn @end deffn
@node GHIL, GLIL, The Language Front-Ends, The Compiler @node GHIL, Compiling Scheme Code, The Language Front-Ends, The Compiler
@section Guile's High-Level Intermediate Language @section Guile's High-Level Intermediate Language
GHIL has constructs almost equivalent to those found in Scheme. GHIL has constructs almost equivalent to those found in Scheme.
@ -895,11 +898,45 @@ close to the fundamental primitives of Scheme.
It is the role of front-end language translators (@pxref{The Language It is the role of front-end language translators (@pxref{The Language
Front-Ends}) to produce a sequence of GHIL objects from the Front-Ends}) to produce a sequence of GHIL objects from the
human-readable, source programming language. human-readable, source programming language. The next section
describes the translator for the Scheme language.
[FIXME: Describe more.] @node Compiling Scheme Code, GLIL, GHIL, The Compiler
@section Compiling Scheme Code
@node GLIL, The Assembler, GHIL, The Compiler The language object for Scheme, as returned by @code{(lookup-language
'scheme)} (@pxref{The Language Front-Ends}), defines a translator
procedure that returns a sequence of GHIL objects given Scheme code.
Before actually performing this operation, the Scheme translator
expands macros in the original source code.
The macros that may be expanded can come from different sources:
@itemize
@item core Guile macros, such as @code{false-if-exception};
@item macros defined in modules used by the module being compiled,
e.g., @code{receive} in @code{(ice-9 receive)};
@item macros defined within the module being compiled.
@end itemize
@cindex macro
@cindex syntax transformer
@findex define-macro
@findex defmacro
The main complexity in handling macros at compilation time is that
Guile's macros are first-class objects. For instance, when using
@code{define-macro}, one actually defines a @emph{procedure} that
returns code; of course, unlike a ``regular'' procedure, it is
executed when an S-exp is @dfn{memoized} by the evaluator, i.e.,
before the actual evaluation takes place. Worse, it is possible to
turn a procedure into a macro, or @dfn{syntax transformer}, thus
removing, to some extent, the boundary between the macro expansion and
evaluation phases, @inforef{Internal Macros, , guile}.
[FIXME: explain limitations, etc.]
@node GLIL, The Assembler, Compiling Scheme Code, The Compiler
@section Guile's Low-Level Intermediate Language @section Guile's Low-Level Intermediate Language
A GHIL instruction sequence can be compiled into GLIL using the A GHIL instruction sequence can be compiled into GLIL using the

View file

@ -32,8 +32,16 @@
;; Hash table containing the macros currently defined. ;; Hash table containing the macros currently defined.
(define &current-macros (make-parameter #f)) (define &current-macros (make-parameter #f))
;; Module in which macros are evaluated.
(define &current-macro-module (make-parameter #f))
(define (translate x e) (define (translate x e)
(parameterize ((&current-macros (make-hash-table))) (parameterize ((&current-macros (make-hash-table))
(&current-macro-module (make-module)))
;; Import only core bindings in the macro module.
(module-use! (&current-macro-module) (resolve-module '(guile-user)))
(call-with-ghil-environment (make-ghil-mod e) '() (call-with-ghil-environment (make-ghil-mod e) '()
(lambda (env vars) (lambda (env vars)
(<ghil-lambda> env #f vars #f (trans env #f x)))))) (<ghil-lambda> env #f vars #f (trans env #f x))))))
@ -46,10 +54,15 @@
(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) (local-ref (list head))))) (val (and (symbol? head)
(false-if-exception
(module-ref (&current-macro-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
@ -62,7 +75,11 @@
(if (not local-macro) (if (not local-macro)
e e
(if (procedure? local-macro) (if (procedure? local-macro)
(expand-macro (apply local-macro (cdr e))) (expand-macro
(save-module-excursion
(lambda ()
(set-current-module (&current-macro-module))
(apply local-macro (cdr e)))))
(syntax-error #f (format #f "~a: invalid macro" head) (syntax-error #f (format #f "~a: invalid macro" head)
local-macro))))))))) local-macro)))))))))
(#t e))) (#t e)))
@ -152,12 +169,17 @@
(formal-args (if shortcut? (cadr tail) (cdar tail))) (formal-args (if shortcut? (cadr tail) (cdar tail)))
(body (if shortcut? (cddr tail) (cdr tail)))) (body (if shortcut? (cddr tail) (cdr tail))))
;; Evaluate the macro in the current macro module.
(hashq-set! (&current-macros) macro-name (hashq-set! (&current-macros) macro-name
;; FIXME: The lambda is evaluated in the current module. (catch #t
(primitive-eval `(lambda ,formal-args ,@body))) (lambda ()
(eval `(lambda ,formal-args ,@body)
; (format (current-error-port) "macro `~a': ~a~%" (&current-macro-module)))
; macro-name (hashq-ref (&current-macros) macro-name)) (lambda (key . args)
(syntax-error l (string-append "failed to evaluate "
"macro `" macro-name
"'")
(cons key args)))))
(make:void))) (make:void)))