mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-10 05:50:26 +02:00
rename translate.scm to compile-ghil.scm, and more work on compiler.texi
* doc/ref/api-evaluation.texi: Fix some typos and xrefs. * doc/ref/compiler.texi (The Scheme Compiler): Document the scheme compiler, and start documenting the GHIL language. * doc/ref/guile.texi (Guile Implementation): Whoops, put autoconf after the implementation foo. Unless we want it before? * doc/ref/history.texi (The Emacs Thesis): Fix typo. * doc/ref/vm.texi (Environment Control Instructions): Rename offset to index. * module/language/ghil.scm (parse-ghil): Fix what I think was a bug -- the consumer in a mv-call shouldn't be a rest arg. * module/language/scheme/Makefile.am (SOURCES): * module/language/scheme/compile-ghil.scm: Rename this file from translate.scm. * module/oop/goops.scm: * module/language/scheme/spec.scm: Deal with renaming.
This commit is contained in:
parent
e3ba263de4
commit
ca445ba5ec
10 changed files with 208 additions and 47 deletions
|
@ -424,7 +424,7 @@ desired results. This is known as @dfn{compilation}.
|
|||
|
||||
While it is possible to compile simple Scheme expressions such as
|
||||
@code{(+ 2 2)} or even @code{"Hello world!"}, compilation is most
|
||||
interesting in th context of procedures. Compiling a lambda expression
|
||||
interesting in the context of procedures. Compiling a lambda expression
|
||||
produces a compiled procedure, which is just like a normal procedure
|
||||
except typically much faster, because it can bypass the generic
|
||||
interpreter.
|
||||
|
@ -446,8 +446,8 @@ computation are fulfilled by macros and closures. Of course one good
|
|||
counterexample is the REPL itself, or any code that reads expressions
|
||||
from a port.)
|
||||
|
||||
For more information on the compiler itself, @xref{Compiling to the
|
||||
Virtual Machine}. For information on the virtual machine, @xref{A
|
||||
For more information on the compiler itself, see @ref{Compiling to the
|
||||
Virtual Machine}. For information on the virtual machine, see @ref{A
|
||||
Virtual Machine for Guile}.
|
||||
|
||||
@deffn {Scheme Procedure} compile exp [env=#f] [from=(current-language)] [to=value] [opts=()]
|
||||
|
|
|
@ -68,7 +68,7 @@ for Scheme:
|
|||
#:version "0.5"
|
||||
#:reader read
|
||||
#:read-file read-file
|
||||
#:compilers `((,ghil . ,translate))
|
||||
#:compilers `((,ghil . ,compile-ghil))
|
||||
#:evaluator (lambda (x module) (primitive-eval x))
|
||||
#:printer write)
|
||||
@end example
|
||||
|
@ -158,28 +158,191 @@ different worlds indefinitely, as shown by the following quine:
|
|||
@node The Scheme Compiler
|
||||
@subsection The Scheme Compiler
|
||||
|
||||
macro expansion
|
||||
The job of the Scheme compiler is to expand all macros and to resolve
|
||||
all symbols to lexical variables. Its target language, GHIL, is fairly
|
||||
close to Scheme itself, so this process is not very complicated.
|
||||
|
||||
define-scheme-translator
|
||||
The Scheme compiler is driven by a table of @dfn{translators},
|
||||
declared with the @code{define-scheme-translator} form, defined in the
|
||||
module, @code{(language scheme compile-ghil)}.
|
||||
|
||||
inlining
|
||||
@deffn {Scheme Syntax} define-scheme-translator head clause1 clause2...
|
||||
The best documentation of this form is probably an example. Here is
|
||||
the translator for @code{if}:
|
||||
|
||||
format of the environment
|
||||
@example
|
||||
(define-scheme-translator if
|
||||
;; (if TEST THEN [ELSE])
|
||||
((,test ,then)
|
||||
(make-ghil-if e l (retrans test) (retrans then) (retrans '(begin))))
|
||||
((,test ,then ,else)
|
||||
(make-ghil-if e l (retrans test) (retrans then) (retrans else))))
|
||||
@end example
|
||||
|
||||
compile-time-environment
|
||||
The match syntax is from the @code{pmatch} macro, defined in
|
||||
@code{(system base pmatch)}. The result of a clause should be a valid
|
||||
GHIL value. If no clause matches, a syntax error is signalled.
|
||||
|
||||
symbols resolved as local, external, or toplevel
|
||||
In the body of the clauses, the following bindings are introduced:
|
||||
@itemize
|
||||
@item @code{e}, the current environment
|
||||
@item @code{l}, the current source location (or @code{#f})
|
||||
@item @code{retrans}, a procedure that may be called to compile
|
||||
subexpressions
|
||||
@end itemize
|
||||
|
||||
Note that translators are looked up by @emph{value}, not by name. That
|
||||
is to say, the translator is keyed under the @emph{value} of
|
||||
@code{if}, which normally prints as @code{#<primitive-builtin-macro!
|
||||
if>}.
|
||||
@end deffn
|
||||
|
||||
Users can extend the compiler by defining new translators.
|
||||
Additionally, some forms can be inlined directly to
|
||||
instructions -- @xref{Inlined Scheme Instructions}, for a list. The
|
||||
actual inliners are defined in @code{(language scheme inline)}:
|
||||
|
||||
@deffn {Scheme Syntax} define-inline head arity1 result1 arity2 result2...
|
||||
Defines an inliner for @code{head}. As in
|
||||
@code{define-scheme-translator}, inliners are keyed by value and not
|
||||
by name.
|
||||
|
||||
Expressions are matched on their arities. For example:
|
||||
|
||||
@example
|
||||
(define-inline eq?
|
||||
(x y) (eq? x y))
|
||||
@end example
|
||||
|
||||
This inlines calls to the Scheme procedure, @code{eq?}, to the
|
||||
instruction @code{eq?}.
|
||||
|
||||
A more complicated example would be:
|
||||
|
||||
@example
|
||||
(define-inline +
|
||||
() 0
|
||||
(x) x
|
||||
(x y) (add x y)
|
||||
(x y . rest) (add x (+ y . rest)))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
Compilers take two arguments, an expression and an environment, and
|
||||
return two values as well: an expression in the target language, and
|
||||
an environment suitable for the target language. The format of the
|
||||
environment is language-dependent.
|
||||
|
||||
For Scheme, an environment may be one of three things:
|
||||
@itemize
|
||||
@item @code{#f}, in which case compilation is performed in the context
|
||||
of the current module;
|
||||
@item a module, which specifies the context of the compilation; or
|
||||
@item a @dfn{compile environment}, which specifies lexical variables
|
||||
as well.
|
||||
@end itemize
|
||||
|
||||
The format of a compile environment for scheme is @code{(@var{module}
|
||||
@var{lexicals} . @var{externals})}, though users are strongly
|
||||
discouraged from constructing these environments themselves. Instead,
|
||||
if you need this functionality -- as in GOOPS' dynamic method compiler
|
||||
-- capture an environment with @code{compile-time-environment}, then
|
||||
pass that environment to @code{compile}.
|
||||
|
||||
@deffn {Scheme Procedure} compile-time-environment
|
||||
A special function known to the compiler that, when compiled, will
|
||||
return a representation of the lexical environment in place at compile
|
||||
time. Useful for supporting some forms of dynamic compilation. Returns
|
||||
@code{#f} if called from the interpreter.
|
||||
@end deffn
|
||||
|
||||
@node GHIL
|
||||
@subsection GHIL
|
||||
|
||||
ghil environments
|
||||
|
||||
structured, typed intermediate language, close to scheme
|
||||
with an s-expression representation
|
||||
|
||||
,lang ghil
|
||||
|
||||
document reified format, as it's more interesting, and gives you an idea
|
||||
|
||||
all have environment and location pointers
|
||||
|
||||
@deffn {GHIL Expression} quote exp
|
||||
A quoted expression.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} quasiquote exp
|
||||
A quasiquoted expression. The parse format understands the normal
|
||||
@code{unquote} and @code{unquote-splicing} forms as in normal Scheme.
|
||||
When constructing @var{exp} programmatically, you will need to call
|
||||
@code{make-ghil-unquote} and @code{make-ghil-unquote-splicing} as
|
||||
appropriate.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} lambda syms rest meta . body
|
||||
A closure. @var{syms} is the argument list, as a list of symbols.
|
||||
@var{rest} is a boolean, which is @code{#t} iff the last argument is a
|
||||
rest argument. @var{meta} is an association list of properties. The
|
||||
actual @var{body} should be a list of GHIL expressions.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} void
|
||||
The unspecified value.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} begin . body
|
||||
Like Scheme's @code{begin}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} bind syms exprs . body
|
||||
Like a deconstructed @code{let}: each element of @var{syms} will be
|
||||
bound to the corresponding GHIL expression in @var{exprs}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} bindrec syms exprs . body
|
||||
As @code{bind} is to @code{let}, so @code{bindrec} is to
|
||||
@code{letrec}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} set! sym val
|
||||
Like Scheme's @code{set!}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} define sym val
|
||||
Like Scheme's @code{define}, but without the lambda sugar of course.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} if test then else
|
||||
A conditional. Note that @var{else} is not optional.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} and . exps
|
||||
Like Scheme's @code{and}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} or . exps
|
||||
Like Scheme's @code{or}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} mv-bind syms rest producer . body
|
||||
Like Scheme's @code{receive} -- binds the values returned by
|
||||
applying @code{producer}, which should be a thunk, to the
|
||||
@code{lambda}-like bindings described by @var{syms} and @var{rest}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} call proc . args
|
||||
A procedure call.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} mv-call producer consumer
|
||||
Like Scheme's @code{call-with-values}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} inline op . args
|
||||
An inlined VM instruction. @var{op} should be the instruction name as
|
||||
a symbol, and @var{args} should be its arguments, as GHIL expressions.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} values . values
|
||||
Like Scheme's @code{values}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} values* . values
|
||||
@var{values} are as in the Scheme expression, @code{(apply values .
|
||||
@var{vals})}.
|
||||
@end deffn
|
||||
@deffn {GHIL Expression} compile-time-environment
|
||||
Produces, at runtime, a reification of the environment at compile
|
||||
time.
|
||||
@end deffn
|
||||
|
||||
ghil environments
|
||||
ghil-var-for-ref!, ghil-var-for-set!, ghil-var-define!, ghil-var-at-module!
|
||||
|
||||
some pre-optimization
|
||||
|
||||
real name of the game is closure elimination -- fixing letrec
|
||||
|
|
|
@ -365,8 +365,6 @@ available through both Scheme and C interfaces.
|
|||
@include scsh.texi
|
||||
@include scheme-debugging.texi
|
||||
|
||||
@include autoconf.texi
|
||||
|
||||
@node Guile Implementation
|
||||
@chapter Guile Implementation
|
||||
|
||||
|
@ -390,6 +388,8 @@ Also Schemers as closet compiler writers.
|
|||
@include vm.texi
|
||||
@include compiler.texi
|
||||
|
||||
@include autoconf.texi
|
||||
|
||||
@include fdl.texi
|
||||
|
||||
@iftex
|
||||
|
|
|
@ -42,9 +42,9 @@ seen in Emacs' current and continued existence, spanning more than a
|
|||
quarter-century.
|
||||
|
||||
Besides providing for modification of a program by others, extension
|
||||
languages are good for /intension/ as well. Programs built in ``the
|
||||
Emacs way'' are pleasurable and easy for their authors to flesh out
|
||||
with the features that they need.
|
||||
languages are good for @emph{intension} as well. Programs built in
|
||||
``the Emacs way'' are pleasurable and easy for their authors to flesh
|
||||
out with the features that they need.
|
||||
|
||||
After the Emacs experience was appreciated more widely, a number of
|
||||
hackers started to consider how to spread this experience to the rest
|
||||
|
|
|
@ -388,46 +388,46 @@ These instructions access and mutate the environment of a compiled
|
|||
procedure -- the local bindings, the ``external'' bindings, and the
|
||||
toplevel bindings.
|
||||
|
||||
@deffn Instruction local-ref offset
|
||||
@deffn Instruction local-ref index
|
||||
Push onto the stack the value of the local variable located at
|
||||
@var{offset} within the current stack frame.
|
||||
@var{index} within the current stack frame.
|
||||
|
||||
Note that arguments and local variables are all in one block. Thus the
|
||||
first argument, if any, is at offset 0, and local bindings follow the
|
||||
first argument, if any, is at index 0, and local bindings follow the
|
||||
arguments.
|
||||
@end deffn
|
||||
|
||||
@deffn Instruction local-set offset
|
||||
@deffn Instruction local-set index
|
||||
Pop the Scheme object located on top of the stack and make it the new
|
||||
value of the local variable located at @var{offset} within the current
|
||||
value of the local variable located at @var{index} within the current
|
||||
stack frame.
|
||||
@end deffn
|
||||
|
||||
@deffn Instruction external-ref offset
|
||||
@deffn Instruction external-ref index
|
||||
Push the value of the closure variable located at position
|
||||
@var{offset} within the program's list of external variables.
|
||||
@var{index} within the program's list of external variables.
|
||||
@end deffn
|
||||
|
||||
@deffn Instruction external-set offset
|
||||
@deffn Instruction external-set index
|
||||
Pop the Scheme object located on top of the stack and make it the new
|
||||
value of the closure variable located at @var{offset} within the
|
||||
value of the closure variable located at @var{index} within the
|
||||
program's list of external variables.
|
||||
@end deffn
|
||||
|
||||
The external variable lookup algorithm should probably be made more
|
||||
efficient in the future via addressing by frame and offset. Currently,
|
||||
efficient in the future via addressing by frame and index. Currently,
|
||||
external variables are all consed onto a list, which results in O(N)
|
||||
lookup time.
|
||||
|
||||
@deffn Instruction externals
|
||||
Pushes the current list of external variables onto the stack. This
|
||||
instruction is used in the implementation of
|
||||
@code{compile-time-environment}.
|
||||
@code{compile-time-environment}. @xref{The Scheme Compiler}.
|
||||
@end deffn
|
||||
|
||||
@deffn Instruction toplevel-ref offset
|
||||
@deffn Instruction toplevel-ref index
|
||||
Push the value of the toplevel binding whose location is stored in at
|
||||
position @var{offset} in the object table.
|
||||
position @var{index} in the object table.
|
||||
|
||||
Initially, a cell in the object table that is used by
|
||||
@code{toplevel-ref} is initialized to one of two forms. The normal
|
||||
|
@ -453,9 +453,9 @@ variable has been successfully resolved.
|
|||
This instruction pushes the value of the variable onto the stack.
|
||||
@end deffn
|
||||
|
||||
@deffn Instruction toplevel-ref offset
|
||||
@deffn Instruction toplevel-ref index
|
||||
Pop a value off the stack, and set it as the value of the toplevel
|
||||
variable stored at @var{offset} in the object table. If the variable
|
||||
variable stored at @var{index} in the object table. If the variable
|
||||
has not yet been looked up, we do the lookup as in
|
||||
@code{toplevel-ref}.
|
||||
@end deffn
|
||||
|
@ -490,15 +490,13 @@ All the conditional branch instructions described below work in the
|
|||
same way:
|
||||
|
||||
@itemize
|
||||
@item They take the Scheme object located on the stack and use it as
|
||||
@item They pop off the Scheme object located on the stack and use it as
|
||||
the branch condition;
|
||||
@item If the condition is false, then program execution continues with
|
||||
the next instruction;
|
||||
@item If the condition is true, then the instruction pointer is
|
||||
increased by the offset passed as an argument to the branch
|
||||
instruction;
|
||||
@item Finally, when the instruction finished, the condition object is
|
||||
removed from the stack.
|
||||
@item Program execution proceeds with the next instruction (that is,
|
||||
the one to which the instruction pointer points).
|
||||
@end itemize
|
||||
|
||||
Note that the offset passed to the instruction is encoded on two 8-bit
|
||||
|
|
|
@ -404,7 +404,7 @@
|
|||
((call ,proc . ,args)
|
||||
(make-ghil-call env loc (retrans proc) (map retrans args)))
|
||||
|
||||
((mv-call ,producer . ,consumer)
|
||||
((mv-call ,producer ,consumer)
|
||||
(make-ghil-mv-call env loc (retrans producer) (retrans consumer)))
|
||||
|
||||
((inline ,op . ,args)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
SOURCES = translate.scm spec.scm inline.scm
|
||||
SOURCES = compile-ghil.scm spec.scm inline.scm
|
||||
modpath = language/scheme
|
||||
include $(top_srcdir)/am/guilec
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(define-module (language scheme translate)
|
||||
(define-module (language scheme compile-ghil)
|
||||
#:use-module (system base pmatch)
|
||||
#:use-module (system base language)
|
||||
#:use-module (language ghil)
|
||||
|
@ -29,7 +29,7 @@
|
|||
#:use-module (ice-9 optargs)
|
||||
#:use-module ((ice-9 syncase) #:select (sc-macro))
|
||||
#:use-module ((system base compile) #:select (syntax-error))
|
||||
#:export (translate translate-1
|
||||
#:export (compile-ghil translate-1
|
||||
*translate-table* define-scheme-translator))
|
||||
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
|||
|
||||
|
||||
|
||||
(define (translate x e opts)
|
||||
(define (compile-ghil x e opts)
|
||||
(save-module-excursion
|
||||
(lambda ()
|
||||
(and=> (cenv-module e) set-current-module)
|
||||
|
@ -158,11 +158,11 @@
|
|||
(define *translate-table* (make-hash-table))
|
||||
|
||||
(define-macro (define-scheme-translator sym . clauses)
|
||||
`(hashq-set! (@ (language scheme translate) *translate-table*)
|
||||
`(hashq-set! (@ (language scheme compile-ghil) *translate-table*)
|
||||
,sym
|
||||
(lambda (e l exp)
|
||||
(define (retrans x)
|
||||
((@ (language scheme translate) translate-1) e #f x))
|
||||
((@ (language scheme compile-ghil) translate-1) e #f x))
|
||||
(define syntax-error (@ (system base compile) syntax-error))
|
||||
(pmatch (cdr exp)
|
||||
,@clauses
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
(define-module (language scheme spec)
|
||||
#:use-module (system base language)
|
||||
#:use-module (language scheme translate)
|
||||
#:use-module (language scheme compile-ghil)
|
||||
#:use-module (language ghil spec)
|
||||
#:export (scheme))
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
|||
#:version "0.5"
|
||||
#:reader read
|
||||
#:read-file read-file
|
||||
#:compilers `((,ghil . ,translate))
|
||||
#:compilers `((,ghil . ,compile-ghil))
|
||||
#:evaluator (lambda (x module) (primitive-eval x))
|
||||
#:printer write
|
||||
)
|
||||
|
|
|
@ -1060,7 +1060,7 @@
|
|||
|
||||
(eval-case
|
||||
((load-toplevel compile-toplevel)
|
||||
(use-modules ((language scheme translate) :select (define-scheme-translator))
|
||||
(use-modules ((language scheme compile-ghil) :select (define-scheme-translator))
|
||||
((language ghil) :select (make-ghil-inline))
|
||||
(system base pmatch))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue