Warning: This is the manual of the legacy Guile 2.0 series. You may want to read the manual of the current stable series instead.

Next: , Previous: , Up: Compiling to the Virtual Machine   [Contents][Index]


9.4.2 The Scheme Compiler

The job of the Scheme compiler is to expand all macros and all of Scheme to its most primitive expressions. The definition of “primitive” is given by the inventory of constructs provided by Tree-IL, the target language of the Scheme compiler: procedure applications, conditionals, lexical references, etc. This is described more fully in the next section.

The tricky and amusing thing about the Scheme-to-Tree-IL compiler is that it is completely implemented by the macro expander. Since the macro expander has to run over all of the source code already in order to expand macros, it might as well do the analysis at the same time, producing Tree-IL expressions directly.

Because this compiler is actually the macro expander, it is extensible. Any macro which the user writes becomes part of the compiler.

The Scheme-to-Tree-IL expander may be invoked using the generic compile procedure:

(compile '(+ 1 2) #:from 'scheme #:to 'tree-il)
⇒
 #<<application> src: #f
                 proc: #<<toplevel-ref> src: #f name: +>
                 args: (#<<const> src: #f exp: 1>
                        #<<const> src: #f exp: 2>)>

Or, since Tree-IL is so close to Scheme, it is often useful to expand Scheme to Tree-IL, then translate back to Scheme. For that reason the expander provides two interfaces. The former is equivalent to calling (macroexpand '(+ 1 2) 'c), where the 'c is for “compile”. With 'e (the default), the result is translated back to Scheme:

(macroexpand '(+ 1 2))
⇒ (+ 1 2)
(macroexpand '(let ((x 10)) (* x x)))
⇒ (let ((x84 10)) (* x84 x84))

The second example shows that as part of its job, the macro expander renames lexically-bound variables. The original names are preserved when compiling to Tree-IL, but can’t be represented in Scheme: a lexical binding only has one name. It is for this reason that the native output of the expander is not Scheme. There’s too much information we would lose if we translated to Scheme directly: lexical variable names, source locations, and module hygiene.

Note however that macroexpand does not have the same signature as compile-tree-il. compile-tree-il is a small wrapper around macroexpand, to make it conform to the general form of compiler procedures in Guile’s language tower.

Compiler procedures take three arguments: an expression, an environment, and a keyword list of options. They return three values: the compiled expression, the corresponding environment for the target language, and a “continuation environment”. The compiled expression and environment will serve as input to the next language’s compiler. The “continuation environment” can be used to compile another expression from the same source language within the same module.

For example, you might compile the expression, (define-module (foo)). This will result in a Tree-IL expression and environment. But if you compiled a second expression, you would want to take into account the compile-time effect of compiling the previous expression, which puts the user in the (foo) module. That is purpose of the “continuation environment”; you would pass it as the environment when compiling the subsequent expression.

For Scheme, an environment is a module. By default, the compile and compile-file procedures compile in a fresh module, such that bindings and macros introduced by the expression being compiled are isolated:

(eq? (current-module) (compile '(current-module)))
⇒ #f

(compile '(define hello 'world))
(defined? 'hello)
⇒ #f

(define / *)
(eq? (compile '/) /)
⇒ #f

Similarly, changes to the current-reader fluid (see current-reader) are isolated:

(compile '(fluid-set! current-reader (lambda args 'fail)))
(fluid-ref current-reader)
⇒ #f

Nevertheless, having the compiler and compilee share the same name space can be achieved by explicitly passing (current-module) as the compilation environment:

(define hello 'world)
(compile 'hello #:env (current-module))
⇒ world

Next: , Previous: , Up: Compiling to the Virtual Machine   [Contents][Index]