diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi index 2825426a4..d8412154c 100644 --- a/doc/ref/api-evaluation.texi +++ b/doc/ref/api-evaluation.texi @@ -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=()] diff --git a/doc/ref/compiler.texi b/doc/ref/compiler.texi index c40a82e5d..b7054db65 100644 --- a/doc/ref/compiler.texi +++ b/doc/ref/compiler.texi @@ -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{#}. +@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 diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index 7968e989d..50cce497e 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -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 diff --git a/doc/ref/history.texi b/doc/ref/history.texi index b2b2e2d64..a258844cf 100644 --- a/doc/ref/history.texi +++ b/doc/ref/history.texi @@ -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 diff --git a/doc/ref/vm.texi b/doc/ref/vm.texi index 21817b2e3..5747e1fab 100644 --- a/doc/ref/vm.texi +++ b/doc/ref/vm.texi @@ -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 diff --git a/module/language/ghil.scm b/module/language/ghil.scm index 5180073c2..336cd9510 100644 --- a/module/language/ghil.scm +++ b/module/language/ghil.scm @@ -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) diff --git a/module/language/scheme/Makefile.am b/module/language/scheme/Makefile.am index 468543b0a..ca1d662f4 100644 --- a/module/language/scheme/Makefile.am +++ b/module/language/scheme/Makefile.am @@ -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 diff --git a/module/language/scheme/translate.scm b/module/language/scheme/compile-ghil.scm similarity index 98% rename from module/language/scheme/translate.scm rename to module/language/scheme/compile-ghil.scm index 0132ff755..19ced1df2 100644 --- a/module/language/scheme/translate.scm +++ b/module/language/scheme/compile-ghil.scm @@ -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 diff --git a/module/language/scheme/spec.scm b/module/language/scheme/spec.scm index 3f5a70916..ddcd69f12 100644 --- a/module/language/scheme/spec.scm +++ b/module/language/scheme/spec.scm @@ -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 ) diff --git a/module/oop/goops.scm b/module/oop/goops.scm index 2f6625c3f..453e0a9dd 100644 --- a/module/oop/goops.scm +++ b/module/oop/goops.scm @@ -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))