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 (¤t-macro-module): New. (translate): Evaluate macros in `¤t-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:
parent
a316e42d98
commit
9dbbe4bb83
2 changed files with 77 additions and 18 deletions
|
@ -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
|
||||||
|
|
|
@ -32,8 +32,16 @@
|
||||||
;; Hash table containing the macros currently defined.
|
;; Hash table containing the macros currently defined.
|
||||||
(define ¤t-macros (make-parameter #f))
|
(define ¤t-macros (make-parameter #f))
|
||||||
|
|
||||||
|
;; Module in which macros are evaluated.
|
||||||
|
(define ¤t-macro-module (make-parameter #f))
|
||||||
|
|
||||||
(define (translate x e)
|
(define (translate x e)
|
||||||
(parameterize ((¤t-macros (make-hash-table)))
|
(parameterize ((¤t-macros (make-hash-table))
|
||||||
|
(¤t-macro-module (make-module)))
|
||||||
|
|
||||||
|
;; Import only core bindings in the macro module.
|
||||||
|
(module-use! (¤t-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 (¤t-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 (¤t-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! (¤t-macros) macro-name
|
(hashq-set! (¤t-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~%"
|
(¤t-macro-module)))
|
||||||
; macro-name (hashq-ref (¤t-macros) macro-name))
|
(lambda (key . args)
|
||||||
|
(syntax-error l (string-append "failed to evaluate "
|
||||||
|
"macro `" macro-name
|
||||||
|
"'")
|
||||||
|
(cons key args)))))
|
||||||
|
|
||||||
(make:void)))
|
(make:void)))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue