Next: , Up: Compiling to Wasm   [Contents][Index]


2.1 Invoking the compiler

In Guile’s compiler tower, Scheme code goes through several transformations before being compiled to VM bytecode. Scheme is lowered to (Guile Reference)Tree-IL, which is then lowered to (Guile Reference)Continuation Passing Style(CPS), and then finally to (Guile Reference)Bytecode. Hoot adds an additional backend that compiles CPS to Wasm.

Currently, Hoot does not use Guile’s module system and instead peforms whole program compilation using a prelude that provides R7RS-small features (and also some Guile ones, like prompts.) Support for modules will be added in a future release.

For hooking the Hoot compiler up to a build system such as GNU Make, invoke the guild compile-wasm tool:

guild compile-wasm -o foo.wasm foo.scm

When writing Scheme intended to be compiled to the Wasm target, a special form called %inline-wasm is available for implementing a section of code in WAT rather than Scheme. For example, here’s how port? is implemented:

(define (port? x)
  (%inline-wasm '(func (param $obj (ref eq))
                       (result (ref eq))
                       (if (ref eq)
                           (ref.test $port (local.get $obj))
                           (then (ref.i31 (i32.const 17)))
                           (else (ref.i31 (i32.const 1)))))
                x))

An inline Wasm form specifies a single function using WAT expressions whose parameters and result types are all (ref eq), as well as the Scheme variables that map to the parameters. The compiler then transforms and splices the function body into the procedure.

Like Guile’s built-in compiler, the Hoot compiler can also be invoked within Scheme. The (hoot compile) module provides the interface to the Wasm compiler backend.

Procedure: compile exp [#:import-abi? #f] [#:export-abi? #t] [#:from (current-language)] [#:imports %default-program-imports] [#:optimization-level (default-optimization-level)] [#:warning-level (default-warning-level)] [#:dump-cps? #f] [#:dump-wasm? #f] [#:emit-names? #f] [#:opts '()]

Compile the Scheme expression exp to Wasm and return a Wasm module.

The environment in which exp is evaluated is defined by imports, a list of module names such as (scheme time) or (hoot ffi).

When import-abi? is #t, the Wasm module will be built such that it needs to import its ABI from another module. When export-abi? is #t, the Wasm module will be built such that it exports its ABI functions. A typical use of these flags is to export the ABI from one “main” module and then import that ABI into any additional modules that are being used.

When emit-names? is #t then human-readable names will be embedded in the resulting Wasm object. By default, this is turned off as it greatly increases binary size.

See (Guile Reference)Compiling Scheme Code for more information about invoking Guile’s compiler.

Procedure: read-and-compile port [#:import-abi? #f] [#:export-abi? #t] [#:from (current-language)] [#:optimization-level (default-optimization-level)] [#:warning-level (default-warning-level)] [#:dump-cps? #f] [#:dump-wasm? #f] [#:emit-names? #f] [#:opts '()]

Like compile, but read Scheme expressions from port.

If the first expression is an import form, then only the bindings from those modules will be imported into the compilation unit. If the import form is omitted, a default set of modules will be imported. It is highly recommended to be explicit and use import.

Procedure: compile-file input-file [#:import-abi? #f] [#:export-abi? #t] [#:from (current-language)] [#:optimization-level (default-optimization-level)] [#:warning-level (default-warning-level)] [#:dump-cps? #f] [#:dump-wasm? #f] [#:emit-names? #f] [#:opts '()]

Like read-and-compile, but read the Scheme expression from input-file.


Next: High-level development tools, Up: Compiling to Wasm   [Contents][Index]