\input texinfo    @c -*- texinfo -*-
@c %**start of header
@setfilename hoot.info
@settitle Guile Hoot
@documentencoding UTF-8
@documentlanguage en
@syncodeindex pg cp
@c %**end of header

@dircategory The Algorithmic Language Scheme
@direntry
* Hoot: (hoot).   Scheme to Wasm compiler backend for Guile and Wasm toolchain.
@end direntry

@finalout
@titlepage
@title Guile Hoot
@author David Thompson (@email{dave@@spritely.institute})
@author The Spritely Institute
@end titlepage

@contents

@ifnottex
@node Top
@top Guile Hoot

This is the manual for Guile Hoot, a Scheme to WebAssembly compiler
backend for @url{https://gnu.org/software/guile,GNU Guile} and general
purpose Wasm toolchain.

Both this manual and Guile Hoot itself are released under Apache v2.
See @ref{License} for more information.
@end ifnottex

@menu
* Introduction::                  What's the deal with Wasm, anyway?
* Compilation::                   Using the compiler and development tools.
* Reflection::                    Using Hoot modules from the host environment.
* Development::                   Developer tools.
* Deployment::                    Deploy Hoot binaries.
* Scheme reference::              Hoot-specific Scheme extensions.
* Toolchain reference::           General purpose Wasm tools.
* Contributing::                  Lend a hand!
* License::                       Copying, distributing, and using this text.
* Index::
@end menu

@node Introduction
@chapter Introduction

Guile Hoot is a Scheme to WebAssembly (henceforth referred to as
@emph{Wasm}) compiler backend for
@url{https://gnu.org/software/guile,GNU Guile} and a general purpose
Wasm toolchain.  Wasm is an abstract but low-level binary compilation
target that can run on all major web browsers, and increasingly in
other, more ``native'' contexts, as well.  For over two decades,
JavaScript has been @emph{the} official language of the web, and while
the language has improved a lot over the years, its design leaves much
to be desired. Thus web developers looked for ways to bring their
preferred language to the browser to use instead.  In the past, the
only option available was to @emph{compile that language to
JavaScript!}  This approach worked in some sense but it was unideal
because many languages do not map cleanly to JavaScript.  In the case
of Scheme, for example, the lack of a tail call facility makes
compiling tail-recursive Scheme code unpleasant.  At long last, thanks
to Wasm, it has become possible to use an alternative language with
fewer compromises and better performance.  Hoot aims to bring Guile's
``whole self'' to the web, as well as to other Wasm GC runtimes.

Hoot is being developed by the
@url{https://spritely.institute,Spritely Institute} in collaboration
with @url{https://www.igalia.com/,Igalia} to advance Spritely's
mission to build the infrastructure for a completely decentralized
social Internet.  And for that mission, what better platform to target
than the web browser?
@url{https://spritely.institute/goblins/,Goblins}, Spritely's
distributed object programming environment, is primarily written in
Guile.  So, to meet users where they are at @emph{and} not use
JavaScript at the same time, Spritely needs a Guile to Wasm compiler.

A secondary goal of Hoot is to advocate for all dynamic programming
languages' (Python, Ruby, etc.) rightful place on the client-side web.
The Wasm 1.0 specification was not a habitable environment for
languages that require a garbage collector.  The Wasm GC proposal,
among others, has made it possible for dynamic languages to target
Wasm in a real way.  However, such advances are not without their
detractors.  Without the necessary support, a useful proposal will
never make it into the core specification.  For example, strings are a
particularly controversial subject in the WebAssembly Community Group
and proposals that would greatly benefit Hoot and other languages have
not reached consensus.  Implementing and targeting emergent and useful
Wasm proposals helps those proposals find their way into the core
specification.  A rising tide lifts all boats, as they say, and while
we may be little schemers, we want our work to help advance the Wasm
standard for all dynamic languages.

@menu
* Supported platforms::           Where you can run Hoot.
* Status::                        What works.  What doesn't.
* Installation::                  Setting up Hoot.
* Tutorial::                      Compiling your first Scheme program to Wasm.
@end menu

@node Supported platforms
@section Supported platforms

Hoot's binaries conform to the Wasm 3.0 specification and are
supported on the following Wasm runtimes:

@itemize
@item Firefox 121 or later
@item Chrome 119 or later
@item Safari 26 or later
@item NodeJS 22.3.0 or later
@end itemize

Hoot is currently @emph{unsupported} on WASI runtimes.

@node Status
@section Status

Hoot is still in active development and its API should be considered
unstable and subject to change in future releases.  Hoot currently
supports the R7RS-small Scheme specification, a bit of R6RS, along
with a subset of Guile-specific functionality such as
@inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Prompts.html,
prompts}, @ref{Prompts,,,Guile Reference}}.  Maximum compatibility
with Guile is a long-term goal.

To compile Scheme to Wasm, Hoot takes advantage of the features in the
Wasm 3.0 specification.  The most important of these features are tail
calls and GC reference types.  The @code{return_call} family of
instructions has made the implementation of Scheme's tail recursive
procedure call semantics relatively straightforward.  GC reference
type instructions allow for heap allocated objects (and immediates via
the @code{i31} type) that are managed by the Wasm runtime.  This
allows Hoot to take advantage of production garbage collectors already
present in web browsers, obviating the need to implement and ship a GC
which would be both inferior to the host's and a major source of
binary bloat.

As of Wasm 3.0, there is no way to capture stack frames.  This poses
an issue for implementing Guile's delimited continuations.  Hoot works
around this limitation by using its own explicit stack.  A compiler
pass known as ``tailify'' rewrites all calls to be tail calls and
saves/restores values onto the explicitly managed stack.  This
strategy is effective but adds significant runtime overhead, in terms
of both time and space.  Fortunately, the
@url{https://github.com/WebAssembly/stack-switching,stack switching
proposal} will bring true stack frame capture to all Wasm runtimes
soon.  Once NodeJS and all major browsers have shipped support for
stack switching, Hoot can begin the migration process.

Another beneficial proposal for Hoot is the
@url{https://github.com/WebAssembly/multibyte-array-access/,multi-byte
array access proposal}.  If accepted, this proposal will allow Hoot to
greatly improve the performance of bytevector operations and emit less
code.

There's an additional Wasm proposal that Hoot has been built on that
has, unfortunately, not found its way into the core Wasm
specification:
@url{https://github.com/WebAssembly/stringref,stringref}.  We still
emit stringref instructions as it is useful in the compilation
pipeline but it is reduced to being an intermediate form.  A lowering
pass replaces stringref instructions with something resembling the
@url{https://github.com/WebAssembly/js-string-builtins,JS string
builtins proposal} but with 8-bit code units rather than 16-bit and
the unfortunate limitation that strings are copied at the Wasm/host
boundary.

@node Installation
@section Installation

@node Binary installation
@subsection Binary installation

@subsubsection Guix

Installing Hoot with @url{https://guix.gnu.org,Guix} is the best way
to get the latest version of Hoot.  Guix is both a Linux distribution
and a package manager that can be used on top of another distribution
such as Debian.

To install Hoot to a user package profile, run:

@example
guix install guile guile-hoot
@end example

To create a temporary shell environment in which to try Hoot, run:

@example
guix shell guile guile-hoot
@end example

In the case of Guix installed on another host distribution, the
following command might work more reliably:

@example
guix shell --pure guile guile-hoot
@end example

The @code{--pure} flag helps in the case where Guile has been
installed using the host distribution's package manager.

@subsubsection Debian

Hoot is currently available in Debian testing and unstable.  In time
it will reach stable, too.

@example
apt install guile-hoot
@end example

@subsubsection MacOS

Hoot is available on MacOS via the
@url{https://github.com/aconchillo/homebrew-guile,Guile tap} for
@url{https://brew.sh/,Homebrew}.

Add the Guile Homebrew tap:

@example
brew tap aconchillo/guile
@end example

If Guile is already installed with Homebrew, unlink it first because a
newer version is currently required:

@example
brew unlink guile
@end example

Then install Hoot:

@example
brew install guile-hoot
@end example

@node Building from source
@subsection Building from source

The @emph{easiest} way to get everything necessary to build Hoot is by
using the @url{https://guix.gnu.org,GNU Guix} package manager for
which we provide a @file{guix.scm} file ready for use with
@command{guix shell}:

@example
cd guile-hoot/
guix shell
@end example

@command{guix shell} will download/compile all required dependencies
and start an interactive shell that is ready to use for building Hoot.

To use Hoot without Guix requires obtaining the following dependencies:

@itemize
@item @url{https://gnu.org/s/guile,Guile} 3.0.11 or newer (required)
@item @url{https://codeberg.org/guile/fibers,Fibers} 1.4 or newer (optional)
@item @url{https://dthompson.us/projects/guile-websocket.html,Guile-websocket} 0.3.0 or newer (optional)
@end itemize

If the optional dependencies are present then Hoot will build its
@code{(hoot web-server)} module that provides a development web
server.  It is recommended to install all optional dependencies for
the best developer experience.

With a sufficiently fresh Guile, via Guix or otherwise, the build can
begin.  If you are building from a Git checkout rather than an
official release tarball, the first step is to bootstrap the build
system:

@example
./bootstrap.sh
@end example

Release tarballs have a pre-bootstrapped build system and do not
require the above step.

Now, build Hoot:

@example
./configure
make
@end example

If you'd like to install Hoot onto your system, run:

@example
sudo make install
@end example

The GNU build system defaults to @file{/usr/local} as the installation
prefix.  This can be changed by re-running the configure script:

@example
./configure --prefix=/some/where/else
sudo make install
@end example

To try out Hoot without installing it, use the @file{pre-inst-env}
wrapper to launch Guile in the context of the Hoot build directory:

@example
./pre-inst-env guile
@end example

If you installed Guile to your system, simply run @command{guile}.

If everything went well, you will be greeted with a Guile REPL prompt.
Regardless of installation status, to verify that Guile can find the
Hoot modules, run:

@lisp
scheme@@(guile-user)> ,use (hoot compile)
@end lisp

If there is no error then congratulations!  Your setup is correct.
Proceed to the tutorial for a crash course in how to use Hoot, or see
later chapters for an API reference.

@subsubsection Running the test suite

This is entirely optional, but if you'd like further verification that
your build is good (or perhaps you're packaging Hoot for
distribution), the test suite can be run via @command{make check}.  By
default, the tests are run against two Wasm runtimes: Hoot's own Wasm
interpreter and either @url{https://nodejs.org,NodeJS} (version 22+)
or @url{https://v8.dev/,V8} via the @command{d8} tool.

Getting V8 can be tricky, and will most likely require you to
@url{https://v8.dev/docs/build,compile it from source.}  It's a pain!
To skip all of that trouble and just run the tests against the
built-in interpreter, run:

@example
make check WASM_HOST=hoot
@end example

@node Tutorial
@section Tutorial

This tutorial will cover the basics of interpreting, compiling, and
running Scheme programs from the command-line, the Guile REPL, and the
web browser.

As a first step, Hoot's built-in interpreter can be used from the
command-line to evaluate simple Scheme expressions.  To launch it, run
@command{hoot repl}:

@example
$ hoot repl
Hoot x.y.z

Enter `,help' for help.
(hoot user)>
@end example

Then evaluate some expressions:

@example
(hoot user)> 42
=> 42
(hoot user)> (values 1 2 3)
=> 1
=> 2
=> 3
(hoot user)> (cons 'a 'b)
=> (a . b)
(hoot user)> (map 1+ '(1 2 3))
=> (2 3 4)
(hoot user)> (define (square x) (* x x))
(hoot user)> (square 4)
=> 16
(hoot user)> ,use (srfi srfi-1)
(hoot user)> (take '(a b c d) 3)
=> (a b c)
(hoot user)> ,quit
@end example

The @command{hoot repl} command runs a pre-built Wasm binary in
NodeJS.  That's fun, but it's even more fun to compile our own Scheme
programs to Wasm.  Let's start with a simple program in a file called
@file{tutorial.scm}:

@lisp
(import (scheme base))
(list 'hoot 'hoot)
@end lisp

This program is written in R7RS-small Scheme.  It can be compiled to
Wasm and run with a single command:

@example
guild compile-wasm --run tutorial.scm
@end example

If all went well, this will print the return value @code{(hoot hoot)}.
The @code{--run} flag is a handy way to quickly compile and test a
small program using Hoot's built-in Wasm interpreter.

Now, let's take a look at how to use Hoot's compilation API
programmatically from the Guile REPL.  Launch @command{guile}, import
the @code{(hoot compile)} module and call the @code{compile}
procedure.

@lisp
@verbatim
scheme@(guile-user)> ,use (hoot compile)
scheme@(guile-user)> (define wasm
                       (compile '(list 'hoot 'hoot)
                                #:imports '((scheme base))))
@end verbatim
@end lisp

The result is a Wasm module.  There is a lot of stuff inside, but
we're not going to focus on that right now.  We should load and run
the module to verify that it outputs @code{(hoot hoot)} like we
expect.  We can do so from the comfort of our Guile REPL because Hoot
includes a Wasm interpreter.  There's no need to use a web browser or
other Wasm runtime to try out small programs.

First, import the @code{(hoot reflect)} module.  Then, instantiate the
Wasm module to boot up the interpreter:

@lisp
@verbatim
scheme@(guile-user)> ,use (hoot reflect)
scheme@(guile-user)> (define instance (hoot-instantiate wasm))
@end verbatim
@end lisp

All that's left to do now is execute the program with
@code{hoot-load}:

@lisp
@verbatim
scheme@(guile-user)> (hoot-load instance)
$1 = #<hoot (hoot hoot)>
@end verbatim
@end lisp

Ta-da!  It feels kind of funny to compile a Scheme program to Wasm
only to load it back into Scheme, but it's a quick and easy way to
test things out when @command{guild compile-wasm --run} doesn't
provide enough flexibility.

For cases when you simply want to compile an expression and see the
result immediately, there is a faster method. Just use the
@code{compile-value} procedure instead:

@lisp
@verbatim
scheme@(guile-user)> (compile-value '(list 1 2 3))
$2 = #<hoot (1 2 3)>
@end verbatim
@end lisp

With @code{compile-value}, the compiled Wasm module is thrown away,
which is just fine for testing throwaway code.

Lists are cool but it would be a shame if we didn't talk about
compiling something a little more complicated.  Let's compile a
simple, tail-recursive procedure!  How about good ol' factorial?

@lisp
@verbatim
scheme@(guile-user)> (define hoot-factorial
                       (compile-value
                        '(let ()
                           (define (factorial x result)
                             (if (= x 1)
                                 result
                                 (factorial (- x 1)
                                            (* result x))))
                           factorial)))
@end verbatim
@end lisp

A Hoot procedure can be called just like a regular procedure:

@lisp
@verbatim
scheme@(guile-user)> (hoot-factorial 5 1)
$3 = 120
@end verbatim
@end lisp

The Hoot reflection in Guile is great for quickly iterating on code,
but what we really want is to get our programs running in a web
browser.  We've compiled a few things to Wasm now, but the resulting
modules have stayed within the confines of Hoot's Wasm interpreter.
To make something that can be loaded by a web browser, we need to
create a Wasm binary.

First, create a new directory for this tutorial:

@example
mkdir hoot-tutorial
cd hoot-tutorial
@end example

Then, write the following trivial program to @file{hello.scm}:

@lisp
(use-modules)

"Hello, world!"
@end lisp

Compile it and generate a bundle with all the necessary runtime
libraries:

@example
guild compile-wasm --bundle -o hello.wasm hello.scm
@end example

To run @file{hello.wasm}, we need to write a small JavaScript program
to boot it up.  Let's call this @file{hello.js}:

@example
@verbatim
async function load() {
  const [message] = await Scheme.load_main("hello.wasm");
  console.log(message);
}
window.addEventListener("load", load);
@end verbatim
@end example

We also need a minimal @file{index.html} web page to bring it all
together:

@example
<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="reflect.js"></script>
    <script type="text/javascript" src="hello.js"></script>
  </head>
  <body>
    Guile is a hoot!
  </body>
</html>
@end example

The file tree in @file{hoot-tutorial} should look like this:

@example
./hello.js
./hello.scm
./hello.wasm
./index.html
./reflect.js
./reflect.wasm
./wtf8.wasm
@end example

Finally, we need a local web server to serve the files.  Fortunately,
Hoot includes a simple web server for development purposes.  Start it
like so:

@example
hoot server
@end example

Visit @url{http://localhost:8080} in your web browser.  If all goes
well, the text ``Hello, world!'' will be printed in the developer
console.

We hope this tutorial has helped you get started with Hoot!  Read on
for full API documentation.

@node Compilation
@chapter Compilation

In Guile's compiler tower, Scheme code goes through several
transformations before being compiled to VM bytecode.  Scheme is
lowered to @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Tree_002dIL.html,
Tree-IL}, @ref{Tree-IL,,,Guile Reference}}, which is then lowered to
@inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Continuation_002dPassing-Style.html,
Continuation-passing style}, @ref{Continuation-Passing Style,,,Guile
Reference}}(CPS), and then finally to @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Bytecode.html,
Bytecode}, @ref{Bytecode,,,Guile Reference}}.  Hoot adds an additional
backend that compiles the CPS intermediate representation to Wasm.

In contrast to Guile's separate compilation approach where each module
is compiled individually (with the possibility of some cross-module
inlining), Hoot is a @emph{whole-program} compiler.  The user program
and all imported modules are part of the same compilation unit and the
result is a single Wasm binary.  Hoot tries to make this binary as
small as possible to minimize bandwidth usage when deployed to the
web.  To do this, Hoot uses a ``tree shaking'' approach to remove all
code is unused in a program.  Making a small change to a program and
recompiling will recompile @emph{the entire program}.  Expect longer
compilation times than you are used to with Guile.

@menu
* Compiling from the command line::       Compiling from the shell.
* Compiling from Guile::                  Compiling from Scheme.
* Compilation REPL commands::             REPL shorthands.
@end menu

@node Compiling from the command line
@section Compiling from the command line

Hoot extends Guile's @command{guild} tool with a new subcommand:
@command{compile-wasm}.

The general syntax is:

@example
guild compile-wasm [@var{options}] @var{file}
@end example

Below is a basic example that compiles @file{foo.scm} to
@file{foo.wasm} and allows access to third-party Scheme modules in the
current directory:

@example
guild compile-wasm --load-path=. --output=foo.wasm foo.scm
@end example

The available options are documented below.

@table @code
@item  --load-path=@var{dir}
@itemx -L @var{dir}
Add @var{dir} to the front of Hoot's module load path.  The
directories are searched in the order given on the command line and
before any directories in the @env{HOOT_LOAD_PATH} environment
variable.  Note that this flag does @emph{not} modify Guile's load
path.

@item  --output=@var{out-file}
@itemx -o @var{out-file}
Write output to @var{out-file}.

@item  --bundle
@itemx --bundle=@var{dir}
@itemx -b @var{dir}
When combined with @code{-o}, copy the web runtime libraries to
@var{dir} or the directory of @var{out-file} (from @code{-o}) if
@var{dir} is not specified.

@item -x @var{extension}
Add @var{extension} to the set of source file extensions.

@item  --warn=@var{warning}
@itemx -W @var{warning}
Emit warnings of type @var{warning}; use @code{--warn=help} for a list
of available warnings.

@item  --optimize=@var{opt}
@itemx -O @var{opt}
Specify optimization passes to run; use @code{-Ohelp} for a list of
available optimizations

@item -g, -g@var{n}, -g@var{opt}
Control level and kind of debugging code; use @var{-ghelp} for a list
of available options.

@item --mode=@var{mode}
Compile the Wasm in @var{mode}.

Available modes are:

@table @code
@item primary
Compile a main module: one which defines runtime facilities and which
by default makes them available to secondary modules.  This is the
default mode.

@item standalone
Like @code{primary}, but without the possibility of sharing runtime
facilities with secondary modules.

@item secondary
Compile an auxiliary module: one which imports runtime facilities
instead of defining and exporting them.

@end table

@item  --run
@itemx --run=@var{js}
Run the compiled Wasm; by default, in the Hoot virtual machine,
otherwise using @var{js}, a JavaScript shell such as NodeJS.  Useful
for quickly testing out small programs.

Consider this example program, @file{example.scm}:

@lisp
(use-modules) ; use default Guile environment
(map 1+ '(1 2 3 4 5))
@end lisp

To compile and run the above program on the Hoot VM, discarding the
Wasm at the end, run:

@example
guild compile-wasm --run example.scm
@end example

To do the same with NodeJS, run:

@example
guild compile-wasm --run=node example.scm
# => 42
@end example

The above example assumes that @command{node} is on @code{$PATH} so
adjust accordingly if that is not the case for your NodeJS
installation.

@item --async
When combined with @code{--run}, run program in async context.

Consider this example program, @file{example.scm}:

@lisp
(use-modules (fibers promises)
             (fibers timers))
(lambda (resolve reject)
  (call-with-async-result
   resolve reject
   (lambda ()
     (sleep 1)
     42)))
@end lisp

Without the @code{--async} flag, the result of running the above
program would be the procedure described by the @code{lambda} form and
nothing would happen.  When run in async mode, the runtime will wait
until the program resolves successfully with some return values or is
rejected due to an error.

@example
guild compile-wasm --run --async example.scm
# => (42)
@end example

@item --user-imports=@var{import-file}
When combined with @code{--run}, load the Scheme/JavaScript (depending
upon @code{--run}) source @var{import-file} and pass the result as
additional imports when instantiating the Wasm module.

On the Hoot VM, the file should evaluate to a 2-tier association list
of imports.  For example:

@lisp
(use-modules (rnrs bytevectors))

`(("uint8Array" . (("new"    . ,make-bytevector)
                   ("length" . ,bytevector-length)
                   ("ref"    . ,bytevector-u8-ref)
                   ("set"    . ,bytevector-u8-set!))))
@end lisp

On JavaScript, the file should define a 2-tier object of imports.  For
JavaScript runtimes that support module imports via @code{require},
like NodeJS, the imports above could be translated like this:

@example
@verbatim
exports.user_imports = {
    uint8Array: {
        new: (length) => new Uint8Array(length),
        length: (array) => array.length,
        ref: (array, index) => array[index],
        set: (array, index, value) => array[index] = value
    }
};
@end verbatim
@end example

@item --dump-tree-il
Print a debugging representation of the high-level expanded and
optimized Scheme code.

@item --dump-cps
Print a debugging representation of the low-level CPS code, before
generating WebAssembly.

@item --dump-wasm
Print a debugging representation of the generated WebAssembly code.

@end table

The following environment variables are supported:

@table @code

@item HOOT_LOAD_PATH
@vindex HOOT_LOAD_PATH

This variable may be used to augment the path that is searched for
Scheme module source code.  Its value should be a colon-separated list
of directories.

@example
$ export HOOT_LOAD_PATH="/path/to/modules:/some/other/modules"
$ guild compile-wasm -o example.wasm example.scm
@end example

@end table

@node Compiling from Guile
@section Compiling from Guile

Like Guile's built-in compiler, the Hoot compiler can also be invoked
from Scheme.  The @code{(hoot compile)} module provides the interface
to the Wasm compiler backend.

@deffn {Procedure} compile exp [#:import-abi? #f] [#:export-abi? #t] @
                   [#:imports %default-program-imports] @
                   [#:include-file %include-from-path] @
                   [#:extend-load-library (lambda (f) f)] @
                   [#:load-library (extend-load-library (builtin-module-loader import-abi?))] @
                   [#:optimization-level (default-optimization-level)] @
                   [#:warning-level (default-warning-level)] @
                   [#:dump-cps? #f] [#:dump-wasm? #f] [#:emit-names? #f] @
                   [#:opts '()]

Compile the Scheme expression @var{exp} to Wasm and return a Wasm
module.

The environment in which @var{exp} is evaluated is defined by
@var{imports}, a list of module names such as @code{(scheme time)} or
@code{(hoot ffi)}.  If not specified, a default list of imports will
be used.

When @var{import-abi?} is @code{#t}, the Wasm module will be built
such that it needs to import its ABI from another module.  When
@var{export-abi?} is @code{#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 @var{emit-names?} is @code{#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.

Associating module names with source code is handled by
@var{load-library}, a procedure that receives the module name as its
only argument and returns the source code as an s-expression, or
@code{#f} if there is no such module.  The default loader is capable
of loading modules from Hoot's standard library.  It is generally
recommended to leave @var{load-library} alone and use the default.

To load additional modules, specify @var{extend-load-library} instead.
@var{extend-load-library} is a procedure that receives one argument,
@var{load-library}, and returns a procedure with the same signature as
@var{load-library}.  Through this extension mechanism, users can load
their own modules.

Most of the time, loading user modules from the file system is all
that is needed.  Hoot has a built-in
@code{library-load-path-extension} extension procedure for this
purpose.  To demonstrate, let's first assume that the code below is
saved to @file{example.scm} in the current directory:

@lisp
(library (example)
  (export double)
  (import (scheme base))
  (define (double x) (* x 2)))
@end lisp

The compiler can then be extended to load modules from the current
directory like so:

@lisp
(compile '(double 42)
         #:imports '((scheme base) (example))
         #:extend-load-library
         (library-load-path-extension '(".")))
@end lisp

@inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Compilation.html,
See the Guile manual}, @xref{Compiling Scheme Code,,,Guile Reference}}
for more information about invoking Guile's compiler.
@end deffn

@deffn {Procedure} read-and-compile port [#:import-abi? #f] [#:export-abi? #t] @
                   [#:include-file %include-from-path] @
                   [#:extend-load-library (lambda (f) f)] @
                   [#:load-library (extend-load-library (builtin-module-loader import-abi?))] @
                   [#:optimization-level (default-optimization-level)] @
                   [#:warning-level (default-warning-level)] @
                   [#:dump-cps? #f] [#:dump-wasm? #f] [#:emit-names? #f] @
                   [#:opts '()]

Like @code{compile}, but read Scheme expressions from @var{port}.

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

@end deffn

@deffn {Procedure} compile-file input-file [#:import-abi? #f] [#:export-abi? #t] @
                   [#:include-file %include-from-path] @
                   [#:extend-load-library (lambda (f) f)] @
                   [#:load-library (extend-load-library (builtin-module-loader import-abi?))] @
                   [#:optimization-level (default-optimization-level)] @
                   [#:warning-level (default-warning-level)] @
                   [#:dump-cps? #f] [#:dump-wasm? #f] [#:emit-names? #f] @
                   [#:opts '()]

Like @code{read-and-compile}, but read the Scheme expression from
@var{input-file}.
@end deffn

@node Compilation REPL commands
@section Compilation REPL commands

The @code{(hoot repl)} module provides some REPL meta commands to make
it easy to compile Scheme programs and run them in Hoot's Wasm
interpreter.

@deffn {REPL Command} hoot-compile exp [opts ...]
Compile @var{exp} and return a Wasm module.

@var{opts} may specify the keyword arguments to pass to the
@code{compile} procedure (@pxref{Compiling from Guile}).
@end deffn

@deffn {REPL Command} hoot-compile-file file [opts ...]
Compile the source code in @var{file} and return a Wasm module.

@var{opts} may specify the keyword arguments to pass to the
@code{compile-file} procedure (@pxref{Compiling from Guile}).
@end deffn

@deffn {REPL Command} hoot-run exp [opts ...]
Compile and run @var{exp} and return the results.
@end deffn

@deffn {REPL Command} hoot-run-file file [opts ...]
Compile and run the source code in @var{file} and return the results.
@end deffn

@node Reflection
@chapter Reflection

Hoot programs are guests that run inside some host system.  Currently,
Hoot can be used from JavaScript runtimes (like web browsers and
NodeJS) and the Guile virtual machine (Scheme in your Scheme).  In
order to boot up a Hoot binary and inspect Scheme values within, we
must reflect.  Hoot provides both JavaScript and Scheme reflection
interfaces.

@menu
* JavaScript reflection::         Interacting with Hoot from JavaScript.
* Guile reflection::              Interacting with Hoot from Guile.
@end menu

@node JavaScript reflection
@section JavaScript reflection

The @code{Scheme} class is used to load a Hoot binary, start the
program, and initialize reflection.

@deftp {Class} Scheme
A Scheme runtime environment.
@end deftp

@defop {Static method} Scheme load_main source [abi] [reflect_wasm_dir "."] [user_imports @{@}]
Fetch and execute the Hoot Wasm binary at the URL @var{source} and
return an array of Scheme values produced by the program.
Alternatively, @var{source} may be a typed array or @code{ArrayBuffer}
containing the Wasm binary data.

The reflection library requires the assistance of some Wasm helper
modules, which are looked up in @var{reflect_wasm_dir}.

The @var{abi} parameter is for more advanced usage where multiple Hoot
binaries share a single application binary interface (ABI).  This
should be set to @code{@{@}} when loading the first Scheme binary.  It
is better to use the @code{load_extension} method for subsequent
binaries, though.

The @var{user_imports} parameter is for providing concrete
implementations of functions declared using the @ref{Foreign function
interface}.  It uses a two-tier nested object structure to map import
names to the functions that implement them.

For example, this Scheme code:

@lisp
(define-foreign make-text-node
  "document" "createTextNode"
  (ref string) -> (ref null extern))
@end lisp

Could be instantiated like so:

@example
@verbatim
Scheme.load_main("hello.wasm", {
  user_imports: {
    document: {
      createTextNode: Document.prototype.createTextNode.bind(document)
    }
  }
});
@end verbatim
@end example

@end defop

@defmethod Scheme load_extension path [user_imports @code{@{@}}]
Fetch and load an additional Hoot binary at the URL @var{path} that
shares the ABI of @code{this}.  Optionally, a set of user-defined
imported functions can be specified with the @var{user_imports}
parameter.
@end defmethod

All of the fundamental Scheme types have an associated JavaScript
class that can reflect their values.  Calling the @code{repr} function
on an instance of a reflected Scheme object will return a Scheme-like
printing of the object.

@example
repr(pair) // => "(1 . 2)"
@end example

@deftp {Class} Char
A Unicode character.
@end deftp

@deftp {Class} Eof
End-of-file object.
@end deftp

@deftp {Class} Null
The empty list.
@end deftp

@deftp {Class} Unspecified
The unspecified value.
@end deftp

@deftp {Class} Complex real imag
Complex number with real part @var{real} and imaginary part
@var{imag}.
@end deftp

@deftp {Class} Fraction num denom
An exact fraction with numerator @var{num} and denominator
@var{denom}.
@end deftp

The @code{HeapObject} class is the parent class of all of the
remaining Scheme types.

@deftp {Class} HeapObject
A Scheme heap object.
@end deftp

@defivar HeapObject reflector
The reflector for @code{this}, an instance of the @code{Scheme} class.
@end defivar

The @code{reflector} property can be used in conjuction with the
@code{load_extension} method to load additional Hoot binaries that
share the same ABI.

@example
heapObject.reflector.load_extension("/helper.wasm")
@end example

@deftp {Class} Procedure
A Scheme procedure.
@end deftp

Procedure instances can be invoked with the @code{call} method to
perform a Javascript to Scheme function call.

@defmethod Procedure call args@dots{}
Call procedure with @var{args} and return an array of result values.
@end defmethod

@defmethod Procedure call_async args@dots{}
Call procedure with @var{args} in an async context and return a
promise to an array of result values.  Before the procedure is called,
@var{args} is prepended with two additional arguments: a function that
resolves the promise, and a function that rejects the promise.  It is
up to the underlying Scheme procedure to use these values
appropriately to settle the promise.
@end defmethod

@deftp {Class} Pair
An immutable cons cell.
@end deftp

@deftp {Class} MutablePair
A mutable cons cell.
@end deftp

@deftp {Class} Vector
An immutable vector.
@end deftp

@deftp {Class} MutableVector
A mutable vector.
@end deftp

@deftp {Class} Bytevector
An immutable bytevector.
@end deftp

@deftp {Class} MutableBytevector
A mutable bytevector.
@end deftp

@deftp {Class} Bitvector
An immutable bitvector.
@end deftp

@deftp {Class} MutableBitvector
A mutable bitvector.
@end deftp

@deftp {Class} MutableString
A mutable string.
@end deftp

@deftp {Class} Sym
A symbol.
@end deftp

@deftp {Class} Keyword
A keyword.
@end deftp

@deftp {Class} Variable
A mutable variable.
@end deftp

@deftp {Class} AtomicBox
A mutable box with atomic updates.
@end deftp

@deftp {Class} HashTable
A hash table.
@end deftp

@deftp {Class} WeakTable
A weak key hash table.
@end deftp

@deftp {Class} Fluid
A dynamic variable.
@end deftp

@deftp {Class} DynamicState
A set of fluids.
@end deftp

@deftp {Class} Syntax
A syntax object.
@end deftp

@deftp {Class} Port
An I/O port.
@end deftp

@deftp {Class} Struct
A user-defined structure.
@end deftp

@node Guile reflection
@section Guile reflection

The @code{(hoot reflect)} module provides an interface for inspecting
and manipulating Scheme values that live within Wasm modules.  This is
the primary interface for testing compiler output directly from Guile.

@deffn {Procedure} hoot-instantiate scheme-wasm [imports '()] [reflector]
Instantiate and return a new Hoot module using the compiled Scheme
Wasm module @var{scheme-wasm} and the reflection module
@var{reflector}.  If @var{reflector} is not specified, a new reflector
instance will be created.

Optionally, @var{imports} may contain a 2-tier association list
structure of imported functions, globals, tables, and memories:

@lisp
`(("math" . (("random" . ,(lambda (x) (random x))))))
@end lisp

@end deffn

@deffn {Procedure} hoot-load module
Invoke the load thunk of @var{module} and return the reflected
result values.
@end deffn

The following procedures, @code{compile-value} and
@code{compile-call}, are convenience procedures for when you just want
to quickly compile something and see the result and you don't care
about the intermediary Wasm binary.

@deffn {Procedure} compile-value exp [imports %default-program-imports] @
                                 [load-path '()] [wasm-imports '()]

Compile @var{exp} and return the result.

Optionally, @var{imports} may specify a list of Scheme module names to
import.  If unspecified, a default set of modules providing a basic
Scheme environment will be imported.  @var{load-path} is a list of
file system directories to search for additional user modules.

Optionally, @var{wasm-imports} may contain a 2-tier association list
structure of imported Wasm functions, globals, tables, and memories.
See @code{hoot-instantiate} for an example of such a structure.
@end deffn

@deffn {Procedure} compile-call proc-exp arg-exps ... @
                                [imports %default-program-imports] @
                                [load-path '()] [wasm-imports '()]

Compile @var{proc-exp} and all @var{arg-exps}, call the procedure with
the arguments, then return the results.

See @code{compile-value} for an explanation of the keyword arguments.
@end deffn

@deffn {Procedure} hoot-module? obj
Return @code{#t} if @var{obj} is a Hoot module.
@end deffn

@deffn {Procedure} hoot-module-reflector module
Return the reflection module for @var{module}.
@end deffn

@deffn {Procedure} hoot-module-instance module
Return the Wasm instance for @var{module}.
@end deffn

@deffn {Procedure} reflector? obj
Return @code{#t} if @var{obj} is a reflector.
@end deffn

@deffn {Procedure} reflector-instance reflector
Return the Wasm instance of @var{reflector}.
@end deffn

@deffn {Procedure} reflector-abi reflector
Return the association list of ABI imports for @var{reflector}.
@end deffn

Below are the predicates and accessors for various Hoot heap types:

@deffn {Procedure} hoot-object? obj
Return @code{#t} if @var{obj} is a Hoot object.
@end deffn

@deffn {Procedure} hoot-complex? obj
Return @code{#t} if @var{obj} is a Hoot complex number.
@end deffn

@deffn {Procedure} hoot-complex-real complex
Return the real part of @var{complex}.
@end deffn

@deffn {Procedure} hoot-complex-imag complex
Return the imaginary part of @var{complex}.
@end deffn

@deffn {Procedure} hoot-fraction? obj
Return @code{#t} if @var{obj} is a Hoot fraction.
@end deffn

@deffn {Procedure} hoot-fraction-num fraction
Return the numerator of @var{fraction}
@end deffn

@deffn {Procedure} hoot-fraction-denom fraction
Return the denominator of @var{fraction}.
@end deffn

@deffn {Procedure} hoot-pair? obj
Return @code{#t} if @var{obj} is a Hoot pair.
@end deffn

@deffn {Procedure} mutable-hoot-pair? obj
Return @code{#t} if @var{obj} is a mutable Hoot pair.
@end deffn

@deffn {Procedure} hoot-pair-car pair
Return the first element of @var{pair}.
@end deffn

@deffn {Procedure} hoot-pair-cdr pair
Return the second element of @var{pair}.
@end deffn

@deffn {Procedure} hoot-vector? obj
Return @code{#t} if @var{obj} is a Hoot vector.
@end deffn

@deffn {Procedure} mutable-hoot-vector? obj
Return @code{#t} if @var{obj} is a mutable Hoot vector.
@end deffn

@deffn {Procedure} hoot-vector-length vec
Return the length of @var{vec}.
@end deffn

@deffn {Procedure} hoot-vector-ref vec i
Return the @var{i}th element of @var{vec}.
@end deffn

@deffn {Procedure} hoot-bytevector? obj
Return @code{#t} if @var{obj} is a Hoot bytevector.
@end deffn

@deffn {Procedure} mutable-hoot-bytevector? obj
Return @code{#t} if @var{obj} is a mutable Hoot bytevector.
@end deffn

@deffn {Procedure} hoot-bytevector-length bv
Return the length of @var{bv}.
@end deffn

@deffn {Procedure} hoot-bytevector-ref bv i
Return the @var{i}th byte of @var{bv}.
@end deffn

@deffn {Procedure} hoot-bitvector? obj
Return @code{#t} if @var{obj} is a Hoot bitvector.
@end deffn

@deffn {Procedure} mutable-hoot-bitvector? obj
Return @code{#t} if @var{obj} is a mutable Hoot bitvector.
@end deffn

@deffn {Procedure} hoot-bitvector-length bv
Return the length of @var{bv}.
@end deffn

@deffn {Procedure} hoot-bitvector-ref bv i
Return the @var{i}th bit of @var{bv}.
@end deffn

@deffn {Procedure} hoot-symbol? obj
Return @code{#t} if @var{obj} is a Hoot symbol.
@end deffn

@deffn {Procedure} hoot-symbol-name sym
Return the string name of @var{sym}.
@end deffn

@deffn {Procedure} hoot-keyword? obj
Return @code{#t} if @var{obj} is a Hoot keyword.
@end deffn

@deffn {Procedure} hoot-keyword-name keyword
Return the name string of @var{keyword}.
@end deffn

@deffn {Procedure} mutable-hoot-string? obj
Return @code{#t} if @var{obj} is a mutable Hoot string.
@end deffn

@deffn {Procedure} mutable-hoot-string->string str
Return the underlying string for @var{str}.
@end deffn

@deffn {Procedure} hoot-procedure? obj
Return @code{#t} if @var{obj} is a Hoot procedure.
@end deffn

@deffn {Procedure} hoot-apply proc . args
Apply the Hoot procedure @var{proc} with @var{args}.
@end deffn

@deffn {Procedure} hoot-apply-async proc . args
Apply the Hoot procedure @var{proc} in an asynchronous context.

@var{proc} should be a procedure that accepts two additional arguments
(arguments 0 and 1) in addition to @var{args}:

@itemize
@item @code{resolved}:
An opaque external value representing the successful completion of the
async operation.
@item @code{rejected}:
An opaque external value representing the failure of the async
operation.
@end itemize

You almost certainly want to be using this procedure with
@code{call-with-async-result} in the @code{(fibers promises)} module.

@end deffn

@deffn {Procedure} hoot-variable? obj
Return @code{#t} if @var{obj} is a Hoot variable.
@end deffn

@deffn {Procedure} hoot-atomic-box? obj
Return @code{#t} if @var{obj} is a Hoot atomic box.
@end deffn

@deffn {Procedure} hoot-hash-table? obj
Return @code{#t} if @var{obj} is a Hoot hash table.
@end deffn

@deffn {Procedure} hoot-weak-table? obj
Return @code{#t} if @var{obj} is a Hoot weak table.
@end deffn

@deffn {Procedure} hoot-fluid? obj
Return @code{#t} if @var{obj} is a Hoot fluid.
@end deffn

@deffn {Procedure} hoot-dynamic-state? obj
Return @code{#t} if @var{obj} is a Hoot dynamic state.
@end deffn

@deffn {Procedure} hoot-syntax? obj
Return @code{#t} if @var{obj} is a Hoot syntax object.
@end deffn

@deffn {Procedure} hoot-port? obj
Return @code{#t} if @var{obj} is a Hoot port.
@end deffn

@deffn {Procedure} hoot-struct? obj
Return @code{#t} if @var{obj} is a Hoot struct.
@end deffn

@node Development
@chapter Development

Hoot's raison d'être is whole-program, ahead-of-time compilation to
static Wasm binaries.  That is a good feature for production web
deployment, but it's less nice during development.  The biggest issue
is that whole-program compilation takes a long time, so the
edit-compile-run loop grows tedious during development.  But wait,
this is Lisp, is it not?  Doesn't Lisp eschew the edit-compile-run
loop for the read-eval-print loop?  Why yes, that is generally the
case.  It's called ``REPL-driven development'' and Hoot can do it,
too!

Hoot includes a Scheme interpreter, REPL, and runtime module system
that allows programs to be developed incrementally while they are
running.  This chapter covers Hoot's developer tools, including the
REPL.

@menu
* Using the REPL::          How to setup a REPL-driven workflow.
* Emacs integration::       Talk to the Hoot REPL from Emacs.
* REPL meta-commands::      Built-in REPL meta-commands.
* REPL limitations::        Things that don't work while live hacking.
* Invoking hoot repl::      Run or connect to a Hoot REPL.
* Invoking hoot server::    Hoot development web and REPL server.
@end menu

@node Using the REPL
@section Using the REPL

To use a local REPL within NodeJS, simply run @command{hoot repl} and
evaluate some code:

@example
$ hoot repl
(hoot user)> (+ 1 2 3)
=> 6
@end example

To load a module, use the @command{,use} meta-command:

@example
(hoot user)> ,use (srfi srfi-1)
@end example

Importing a module may or may not result in loading Scheme source code
from the file system.  If the module was a dependency of the compiled
program that is running the REPL then the module is already baked into
the Wasm binary.  Otherwise, the Hoot load path is searched for a file
corresponding to the given module name.

Modules loaded from the file system at runtime have a limitation: they
must be pure Scheme files that do not include raw Wasm fragments,
either directly or indirectly through macro expansion.  Notably, this
means that any module that uses @code{define-foreign} from the
@code{(hoot ffi)} module cannot be loaded from the file system at
runtime and instead must be compiled into the Wasm binary
(@pxref{REPL limitations}).

To switch modules, use the @command{,module} meta-command and the
prompt will change to reflect the new top-level environment:

@example
(hoot user)> ,module (srfi srfi-1)
(srfi srfi-1)> ,module (hoot user)
(hoot user)>
@end example

When evaluated code throws an exception, a new debugging sub-REPL is
opened:

@example
(hoot user)> (+ 1 "two")
Scheme error:

  1. #<&failed-type-check predicate: "number">
  2. #<&message message: "type check failed">
  3. #<&origin origin: "+">
  4. #<&irritants irritants: ("two")>
  5. #<&source file: "hoot/numbers.scm" line: 130 column: 2>

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
(hoot user) [1]>
@end example

Note the @code{[1]} in the prompt showing the current sub-REPL depth.

To exit a sub-REPL, use the @command{,quit} meta-command:

@example
(hoot user) [1]> ,q
(hoot user)>
@end example

When in the top REPL, @command{,quit} will exit the REPL entirely and
return control back to the shell:

@example
(hoot user)> ,q
$
@end example

Running a REPL within NodeJS is cool, but it would be even better to
connect to a REPL running withing a web browser.  This can be done
using Hoot's development web server and the @code{(hoot web-repl)}
module!

First, setup a web page to run a Hoot program (see @ref{Tutorial} for
instructions).

Below is a minimal program that runs a REPL and does nothing else:

@lisp
(use-modules (hoot web-repl))
(run-web-repl)
@end lisp

In order for this program to be usable it needs to be compiled with
the @code{-g1} (debugging level 1) flag to create a development build
that includes the runtime module system:

@example
guild compile-wasm -g1 -o web-repl.wasm web-repl.scm
@end example

To connect to the REPL running in the web browser, we require the
assistance of the Hoot development web server:

@example
hoot server
@end example

Browse to @url{http://localhost:8080} to start the REPL.

Finally, connect to the REPL:

@example
hoot repl --connect
@end example

If all went well, the REPL prompt should now be waiting for a Scheme
expression to evaluate.  Happy live hacking!

@node Emacs integration
@section Emacs integration

For a truly pleasant development experience, Emacs can connect to a
Hoot REPL using @url{https://geiser.nongnu.org,Geiser}.  To use it,
install the @code{geiser-hoot} extension.

To install using the Emacs package manager, first add
@url{https://melpa.org,MELPA} as a package repository in
@file{~/.emacs.d/init.el}:

@lisp
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
@end lisp

Then install @code{geiser-hoot} with @command{M-x package-install
geiser-hoot}.

To install using Guix, run:

@example
guix install emacs-geiser-hoot
@end example

Then restart Emacs.

Once installed, the extension can be loaded by evaluating
@code{(require 'geiser-hoot)}.

To start a REPL within NodeJS, use @command{M-x run-hoot}.

To connect to a REPL within a web browser, use @command{M-x
connect-to-hoot}.

Refer to the Geiser manual for further information.

@node REPL meta-commands
@section REPL meta-commands

The following REPL meta-commands are built-in to Hoot:

@table @code
@item  ,help
@itemx ,h
Display help information.

@item  ,quit
@itemx ,q
Quit current REPL.

@item  ,describe obj
@itemx ,d obj
Show description and/or documentation for @var{obj}.

@item  ,module [module]
@itemx ,m [module]
Change module to @var{module} when specified or show the current
module if no argument is given.

@item  ,import [module ...]
@itemx ,use [module ...]
Import the modules specified by @var{module} @dots{} or list all
modules imported in the current environment when no arguments are
given.

@item  ,backtrace
@itemx ,bt
Print backtrace.  Must be in a debugging REPL.

@end table

@node REPL limitations
@section REPL limitations

Making Hoot a fully live hackable environment is a work in progress.
Developers that are already used to the Guile development experience
will find some features missing.

Some notable limitations are:

@itemize

@item
Not all code that can be compiled to Wasm can be evaluated in the
Scheme interpreter at runtime.  For example, modules that include
@code{define-foreign} expressions (@pxref{Foreign function interface})
cannot be interpreted because they generate inline Wasm code that
requires the compiler.  To use such modules, they must be compiled
into the Wasm binary of the program being developed.  As a
consequence, adding new FFI bindings requires recompiling and
restarting the program.  To ensure that the desired module is compiled
into a development build, import it from one or more other modules or
import it in the top-level program.

@item
Re-evaluating a @code{define-module} form does not propagate new
exports into modules that have imported it like it does in Guile.  To
use the new exported symbols, the dependent module must have its
@code{define-module} form re-evaluated.  If the module is instead
being used from the REPL then it must be re-imported with the
@code{,use} meta-command (@pxref{REPL meta-commands}).

@item
Guile's module reflection API is not implemented.

@item
Many of Guile's meta-commands are missing, including most of the
debugging tools.

@item
There are no @code{$1}, @code{$2}, @dots{} history variables at the
REPL.

@end itemize

@node Invoking hoot repl
@section Invoking hoot repl

The @command{hoot repl} tool can be used to start an interactive REPL
session running within a NodeJs or connect to a REPL running with a
web browser.

The general syntax is:

@example
hoot repl [@var{option} ...]
@end example

To connect to a REPL in the web browser, run @command{hoot repl
--connect}.

The available options are documented below.

@table @code
@item  --load-path=@var{dir}
@itemx -L @var{dir}
Add @var{dir} to the front of Hoot's module load path.  The
directories are searched in the order given on the command line and
before any directories in the @env{HOOT_LOAD_PATH} environment
variable.

@item  --connect[=@var{port}]
@itemx -c [@var{port}]
Connect to REPL server listening on @var{port} or port 37146 if not
specified.

@end table

@node Invoking hoot server
@section Invoking hoot server

The @command{hoot server} tool can be used to start the development
web server.  The web server serves static files from the current
working directory and also acts as a proxy for REPLs running within
web browsers.

The general syntax is:

@example
hoot server [@var{option} ...]
@end example

The available options are documented below.

@table @code
@item  --port=@var{port}
@itemx -p @var{port}
Listen for HTTP requests on @var{port}.  If this flag isn't specified,
the web server listens on port 8080.

@item  --repl-port=@var{port}
Listen for REPL clients on @var{port}.  If this flag isn't specified,
the REPL server listens on port 37146 (the same as Guile).

@end table

@node Deployment
@chapter Deployment

Hoot's primary deployment targets are JavaScript runtimes, web
browsers in particular.  Hoot binaries are compatible with all major
web browsers:

@itemize
@item Mozilla Firefox as of version 121
@item Google Chrome as of version 119
@item Safari as of version 18.2
@end itemize

Additionally, Hoot binaries can also run in server-side JavaScript
runtimes that are derived from the JavaScript engines within web
browsers, such as NodeJS which is based on Google's V8 runtime.

At this time, it is @emph{not possible} to run Hoot binaries on
non-JavaScript Wasm runtimes such as Wasmtime.  If you're feeling
adventurous and manage to figure out how to deploy to Wasmtime or a
similar runtime, please let us know!

@menu
* Web deployment::                Deploy to web browsers.
* NodeJS deployment::             Deploy to NodeJS.
@end menu

@node Web deployment
@section Web deployment

On the client-side web, JavaScript is the host environment for Wasm
modules and the
@url{https://developer.mozilla.org/en-US/docs/WebAssembly,WebAssembly}
API is used to load and run them.  Hoot includes a JavaScript library,
@file{reflect.js} (@pxref{JavaScript reflection}) that wraps the
@code{WebAssembly} API and furthermore can inspect Scheme values and
call Scheme procedures.  This chapter documents deploying Hoot
artifacts and using the reflection API to run Scheme in the browser.

In order to run Hoot binaries in the browser, a web server needs to
host a copy of the Hoot JavaScript runtime.

The runtime files can be found in the @file{$prefix/share/guile-hoot/}
directory, where @code{$prefix} is the directory where Hoot was
installed on your system.  This is typically @file{/usr} or
@file{/usr/local} on Linux distributions such as Debian, Ubuntu,
Fedora, etc.

The runtime files can be copied to the current directory like this:

@example
cp $prefix/share/guile-hoot/$version/reflect-js/reflect.js .
cp $prefix/share/guile-hoot/$version/reflect-wasm/*.wasm .
@end example

Don't forget to upload the Wasm files for the Scheme programs, too!

A bit of JavaScript code is needed to bootstrap a Scheme program using
the @file{reflect-js/reflect.js} library (@pxref{JavaScript
reflection}).  For example, here's an example @file{boot.js} file that
runs the Scheme program @file{hello.wasm} and prints the return
values:

@example
@verbatim
window.addEventListener("load", async () => {
  const results = await Scheme.load_main("/hello.wasm");
  console.log(results);
});
@end verbatim
@end example

The @code{Scheme} namespace is defined in @file{reflect.js}.
@xref{JavaScript reflection} for more information.

To run @file{boot.js} on a web page, add @code{<script>} tags for it
and @file{reflect.js}:

@example
<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="/reflect.js"></script>
    <script type="text/javascript" src="/boot.js"></script>
  </head>
  <body>
    <h1>Hello, Hoot!</h1>
  </body>
</html>
@end example

@node NodeJS deployment
@section NodeJS deployment

Deploying to @url{https://nodejs.org,NodeJS} is similar to web
deployment but without all the web server setup.  A small boot script
is needed to import the @file{reflect.js} library (@pxref{JavaScript
reflection}) and then load the Wasm binary.

For example, here's a small boot script that imports
@file{reflect.js}, calls @code{Scheme.load_main} to load the Wasm
binary, imports the @code{document.findElementById} method, and prints
the program output:

@example
@verbatim
const hoot = await import("./reflect.js");
const results = await hoot.Scheme.load_main("example.wasm", {
  reflect_wasm_dir: ".",
  user_imports: {
    document: {
      findElementById: (id) => document.findElementById(id)
    }
  }
});
console.log(results);
@end verbatim
@end example

The necessary runtime files can be found in the
@file{$prefix/share/guile-hoot/} directory, where @code{$prefix} is
the directory where Hoot was installed on your system.  This is
typically @file{/usr} or @file{/usr/local} on Linux distributions such
as Debian, Ubuntu, Fedora, etc.

The runtime files can be copied to the current directory like this:

@example
cp $prefix/share/guile-hoot/$version/reflect-js/reflect.js .
cp $prefix/share/guile-hoot/$version/reflect-wasm/*.wasm .
@end example

Once the necessary files are in place, running the program is simple:

@example
node boot.js
@end example

@node Scheme reference
@chapter Scheme reference

In addition to supporting standard Scheme features, Hoot includes many
of its own extensions.  This chapter documents the APIs of these
extensions.

@menu
* Boxes::                         Mutable cells that store a single object.
* Atomics::                       Atomic boxes.
* Bitvectors::                    Sequences of bits.
* Bytevectors::                   Sequences of bytes.
* Control::                       Delimited continuations.
* Exceptions::                    Error handling.
* Fluids::                        Dynamic state.
* Parameters::                    Dynamic variables.
* Hashtables::                    Mutable key/value data structures.
* Records::                       Extensions to standard records.
* Pattern matching::              Object destructuring.
* Foreign function interface::    Call host functions from Scheme.
* Evaluation::                    Interpret Scheme programs at runtime.
* Fibers::                        Lightweight concurrency.
* Finalization::                  Finalization registries.
* Modules::                       The runtime module system.
* REPL::                          Read-eval-print loops.
@end menu

@node Boxes
@section Boxes

The @code{(hoot boxes)} module provides boxes, which are single-value,
mutable cells.

@deffn {Procedure} make-box init
Return a new box with an initial stored value of @var{init}.
@end deffn

@deffn {Procedure} box-ref box
Return the value stored within @var{box}.
@end deffn

@deffn {Procedure} box-set! box val
Set the stored value of @var{box} to @var{val}.
@end deffn

@node Atomics
@section Atomics

The @code{(hoot atomics)} module provides an API compatible with
Guile's @code{(ice-9 atomic)} module.  Atomic operations allow for
concurrent access to a resource form many threads without the need to
use thread synchronization constructs like mutexes.  Currently,
WebAssembly assumes single-threaded execution, making atomicity
trivial.  See @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Atomics.html,
the Guile manual}, @ref{Atomics,,,Guile Reference}} for more detailed
information.

@deffn {Procedure} make-atomic-box init
Return a new atomic box with an initial stored value of @var{init}.
@end deffn

@deffn {Procedure} atomic-box-ref box
Return the value stored within the atomic box @var{box}.
@end deffn

@deffn {Procedure} atomic-box-set! box val
Store @var{val} into the atomic box @var{box}.
@end deffn

@deffn {Procedure} atomic-box-swap! box val
Store @var{val} into the atomic box @var{box}, and return the value
that was previously stored in the box.
@end deffn

@deffn {Procedure} atomic-box-compare-and-swap! box expected desired
If the value of the atomic box @var{box} is the same as @var{expected}
(in the sense of @code{eq?}), replace the contents of the box with
@var{desired}.  Otherwise, the box is not updated.  Return the
previous value of the box in either case.  You can know if the swap
worked by checking if the return value is @code{eq?} to
@var{expected}.
@end deffn

@node Bitvectors
@section Bitvectors

The @code{(hoot bitvectors)} module provides bitvectors, which are
tightly packed arrays of booleans.

@deffn {Procedure} make-bitvector len [fill #f]
Return a new bitvector of @var{len} bits with all bits initialized to
@var{fill}.
@end deffn

@deffn {Procedure} bitvector? obj
Return @code{#t} if @var{obj} is a bitvector.
@end deffn

@deffn {Procedure} bitvector-length bv
Return the length of the bitvector @var{bv}.
@end deffn

@deffn {Procedure} bitvector-ref bv i
Return the boolean value of bit @var{i} in the bitvector @var{bv}.
@end deffn

@deffn {Procedure} bitvector-set-bit! bv i
Set the bit @var{i} in the bitvector @var{bv} to @code{#t}.
@end deffn

@node Bytevectors
@section Bytevectors

The @code{(hoot bytevectors)} module provides some of the R6RS
bytevectors API.  Bytevectors are sequences of bytes that are useful
for low-level manipulation of binary data.

@deffn {Procedure} make-bytevector len [init 0]
Return a new bytevector of @var{len} bytes with all bytes initialized
to @var{init}.
@end deffn

@deffn {Procedure} bytevector [byte ...]
Return a new bytevector containing the sequence @var{byte} @dots{}.
@end deffn

@deffn {Procedure} bytevector? obj
Return @code{#t} if @var{obj} is a bytevector.
@end deffn

@deffn {Procedure} bytevector-length bv
Return the length of @var{bv} in bytes.
@end deffn

@deffn {Procedure} bytevector-copy bv [start 0] [end (bytevector-length bv)]
Return a new bytevector that is a copy of the bytevector @var{bv} from
byte index @var{start} to @var{end}.  @var{start} must be less than or
equal to @var{end}.
@end deffn

@deffn {Procedure} bytevector-copy! to at from [start 0] [end (bytevector-length from)]
Copy the subsection of bytevector @var{from}, defined by the byte
range [@var{start}, @var{end}), into the bytevector @var{from}.
@end deffn

@deffn {Procedure} bytevector-append [bv ...]
Return a new bytevector that concatenates all the input bytevectors
@var{bv} @dots{} in the order given.
@end deffn

@deffn {Procedure} bytevector-concatenate bvs
Return a new bytevector that concatenates all of the bytevectors in
the list @var{bvs}.
@end deffn

@deffn {Procedure} bytevector-concatenate-reverse bvs
Return a new bytevector that concatenates all of the bytevectors in
the list @var{bvs} in reverse order.
@end deffn

@deffn {Procedure} bytevector-u8-ref bv index
@deffnx {Procedure} bytevector-s8-ref bv index
@deffnx {Procedure} bytevector-u16-native-ref bv index
@deffnx {Procedure} bytevector-s16-native-ref bv index
@deffnx {Procedure} bytevector-u32-native-ref bv index
@deffnx {Procedure} bytevector-s32-native-ref bv index
@deffnx {Procedure} bytevector-u64-native-ref bv index
@deffnx {Procedure} bytevector-s64-native-ref bv index
Return the N-bit signed or unsigned integer from the bytevector
@var{bv} at @var{index} using the host's native endianness.
@end deffn

@deffn {Procedure} bytevector-ieee-single-native-ref bv index
@deffnx {Procedure} bytevector-ieee-double-native-ref bv index
Return the single or double precision IEEE floating piont number from
the bytevector @var{bv} at @var{index} using the host's native
endianness.
@end deffn

@deffn {Procedure} bytevector-u8-set! bv index x
@deffnx {Procedure} bytevector-s8-set! bv index x
@deffnx {Procedure} bytevector-u16-native-set! bv index x
@deffnx {Procedure} bytevector-s16-native-set! bv index x
@deffnx {Procedure} bytevector-u32-native-set! bv index x
@deffnx {Procedure} bytevector-s32-native-set! bv index x
@deffnx {Procedure} bytevector-u64-native-set! bv index x
@deffnx {Procedure} bytevector-s64-native-set! bv index x
Store @var{x} as an N-bit signed or unsigned integer in the bytevector
@var{bv} at @var{index} using the host's native endianness.
@end deffn

@deffn {Procedure} bytevector-ieee-single-native-set! bv index x
@deffnx {Procedure} bytevector-ieee-double-native-set! bv index x
Store @var{x} as a single or double precision IEEE floating piont
number in the bytevector @var{bv} at @var{index} using the host's
native endianness.
@end deffn

@node Control
@section Control

The @code{(hoot control)} module provides an interface for Guile's
delimited continuation facility known as ``prompts'' and some of the
@code{(ice-9 control)} API.  See @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Prompts.html,
the Guile manual}, @ref{Prompts,,,Guile Reference}} for more detailed
information.

@deffn {Procedure} make-prompt-tag [stem ``prompt'']
Return a new prompt tag that incorporates the value of @var{stem}.  A
prompt tag is simply a unique object.
@end deffn

@deffn {Procedure} call-with-prompt tag body handler
Call the procedure @var{body}, a procedure of 0 arguments or
``thunk'', within the context of a prompt marked with @var{tag}.
Should this prompt be aborted via @code{abort-to-prompt}, the
procedure @var{handler} is called.  The @var{handler} procedure
receives as arguments a continuation object and any additional
arguments that were passed to @code{abort-to-prompt}.
@end deffn

@deffn {Procedure} abort-to-prompt tag [val ...]
Unwind the dynamic and control context to the nearest prompt named
@var{tag}, so passing the additional values @var{val} @dots{}
@end deffn

@deffn {Procedure} default-prompt-tag
Return the default prompt tag.
@end deffn

@deffn {Procedure} default-prompt-handler
Return the default prompt handler procedure.
@end deffn

Note that both @code{default-prompt-tag} and
@code{default-prompt-handler} are parameters, so their values may be
modified by using @code{parameterize}. @xref{Parameters} for more
information.

@deffn {Syntax} % expr
@deffnx {Syntax} % expr handler
@deffnx {Syntax} % tag expr handler
Syntactic sugar for @code{call-with-prompt}.  Evaluate @var{expr} in
the context of a prompt.  If @var{tag} is ommitted, the default prompt
tag will be used.  If @var{handler} is omitted, the default prompt
handler will be used.
@end deffn

@node Exceptions
@section Exceptions

@node Exception types
@subsection Exception types

The @code{(hoot exceptions)} module implements Guile's exception API.
See @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Exceptions.html,
the Guile manual}, @ref{Exceptions,,,Guile Reference}} for more
detailed information.

@deffn {Procedure} make-exception exceptions @dots{}
Return an exception object composed of @var{exceptions}.
@end deffn

@deffn {Procedure} exception? obj
Return @code{#t} if @var{obj} is an exception object.
@end deffn

Below are the built-in exception types and their respective
constructors, predicates, and accessors.

@deftp {Exception Type} &exception
@end deftp
@deffn {Procedure} simple-exception? obj
@end deffn

@deftp {Exception Type} &compound-exception
@end deftp
@deffn {Procedure} make-compound-exception components
@deffnx {Procedure} compound-exception? obj
@deffnx {Procedure} compound-exception-components compound-exception
@end deffn

@deftp {Exception Type} &message
@end deftp
@deffn {Procedure} make-exception-with-message message
@deffnx {Procedure} exception-with-message? obj
@deffnx {Procedure} exception-message exception
@end deffn

@deftp {Exception Type} &warning
@end deftp

@deffn {Procedure} make-warning
@deffnx {Procedure} warning? obj
@end deffn

@deftp {Exception Type} &serious
@end deftp

@deffn {Procedure} make-serious-exception
@deffnx {Procedure} serious-exception? obj
@end deffn

@deftp {Exception Type} &error
@end deftp

@deffn {Procedure} make-error
@deffnx {Procedure} error? obj
@end deffn

@deftp {Exception Type} &violation
@end deftp

@deffn {Procedure} make-violation
@deffnx {Procedure} violation? obj
@end deffn

@deftp {Exception Type} &assertion
@end deftp

@deffn {Procedure} make-assertion-violation
@deffnx {Procedure} assertion-violation? obj
@end deffn

@deftp {Exception Type} &arity-violation
@end deftp

@deffn {Procedure} make-arity-violation
@deffnx {Procedure} arity-violation? obj
@end deffn

@deftp {Exception Type} &implementation-restriction
@end deftp

@deffn {Procedure} make-implementation-restriction-violation
@deffnx {Procedure} implementation-restriction-violation? obj
@end deffn

@deftp {Exception Type} &failed-type-check
@end deftp

@deffn {Procedure} make-failed-type-check predicate
@deffnx {Procedure} failed-type-check? obj
@deffnx {Procedure} failed-type-check-predicate exception
@end deffn

@deftp {Exception Type} &non-continuable
@end deftp

@deffn {Procedure} make-non-continuable-violation
@deffnx {Procedure} non-continuable-violation? obj
@end deffn

@deftp {Exception Type} &irritants
@end deftp

@deffn {Procedure} make-exception-with-irritants irritants
@deffnx {Procedure} exception-with-irritants? obj
@deffnx {Procedure} exception-irritants exception
@end deffn

@deftp {Exception Type} &origin
@end deftp

@deffn {Procedure} make-exception-with-origin origin
@deffnx {Procedure} exception-with-origin? obj
@deffnx {Procedure} exception-origin exception
@end deffn

@deftp {Exception Type} &lexical
@end deftp

@deffn {Procedure} make-lexical-violation
@deffnx {Procedure} lexical-violation? obj
@end deffn

@deftp {Exception Type} &i/o
@end deftp

@deffn {Procedure} make-i/o-error
@deffnx {Procedure} i/o-error?
@end deffn

@deftp {Exception Type} &i/o-line-and-column
@end deftp

@deffn {Procedure} make-i/o-line-and-column-error line column
@deffnx {Procedure} i/o-line-and-column-error? obj
@deffnx {Procedure} i/o-error-line exception
@deffnx {Procedure} i/o-error-column exception
@end deffn

@deftp {Exception Type} &i/o-filename
@end deftp

@deffn {Procedure} make-i/o-filename-error filename
@deffnx {Procedure} i/o-filename-error? obj
@deffnx {Procedure} i/o-error-filename exception
@end deffn

@deftp {Exception Type} &i/o-not-seekable
@end deftp

@deffn {Procedure} make-i/o-not-seekable-error
@deffnx {Procedure} i/o-not-seekable-error? obj
@end deffn

@deftp {Exception Type} &i/o-port
@end deftp

@deffn {Procedure} make-i/o-port-error port
@deffnx {Procedure} i/o-port-error? obj
@deffnx {Procedure} i/o-error-port exception
@end deffn

@node Raising and handling exceptions
@subsection Raising and handling exceptions

The @code{(hoot errors)} module provides procedures for raising and
handling exceptions.

@deffn {Procedure} raise exception
Raise the non-continuable exception @var{exception} by invoking the
current exception handler.
@end deffn

@deffn {Procedure} raise-continuable exception
Raise the continuable exception @var{exception} by invoking the
current exception handler.
@end deffn

@deffn {Procedure} raise-exception exception [#:continuable? #f]
Raise the exception @var{exception} by invoking the current exception
handler.  When @var{continuable?} is @code{#t}, the raised exception
is continuable.
@end deffn

@deffn {Procedure} with-exception-handler handler thunk [#:unwind? #f]
Call @var{thunk}, a procedure of zero arguments, in a context where
@var{handler}, a procedure of one argument, is the current exception
handler.  If an exception is raised then @var{handler} will be called
with the exception obect.

When @var{unwind?} is @code{#t}, the stack will be unwound before
@var{handler} is called.  The default behavior is not to unwind.  When
the stack is not unwound, it is up to @var{handler} to properly manage
control flow.  Control is allowed to fallthrough @var{handler} and
resume from where the exception was raised only if the raised
exception is @emph{continuable}.  For non-continuable exceptions,
@var{handler} should abort to some prompt (@xref{Control}) to escape
the exception handling context.

@end deffn

@node Fluids
@section Fluids

A fluid is a variable whose value is associated with the dynamic
extent of a procedure call.  The @code{(hoot fluids)} module
implements Guile's fluid API.  See @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Fluids-and-Dynamic-States.html,
the Guile manual}, @ref{Fluids and Dynamic States,,,Guile Reference}}
for more detailed information.

@deffn {Procedure} make-fluid [default #f]
Return a new fluid whose initial value is @var{default}.
@end deffn

@deffn {Procedure} fluid? obj
Return @code{#t} if @var{obj} is a fluid.
@end deffn

@deffn {Procedure} fluid-ref fluid
Return the value currently stored within @var{fluid}.
@end deffn

@deffn {Procedure} fluid-set! fluid val
Set the contents of @var{fluid} to @var{val}.
@end deffn

@deffn {Procedure} with-fluid* fluid val thunk
Call @var{thunk}, a procedure of zero arguments, in a context where
the @var{fluid} is set to @var{val}.  When control leaves the dynamic
extent of @var{thunk}, @var{fluid} is set back to its previous value.
@end deffn

@deffn {Syntax} with-fluids ((fluid value) ...) body1 body2 ...
Evaluate @var{body1} @var{body2} @dots{} in a context where each
@var{fluid} is set to its respective @var{value}.
@end deffn

@node Parameters
@section Parameters

Parameters are Guile's facility for dynamically bound variables.
While parameters are part of the default Guile environment, in Hoot
they are provided by the @code{(hoot parameters)} module.  See
@inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Parameters.html,
the Guile manual}, @ref{Parameters,,,Guile Reference}} for more
detailed information.

A parameter is a procedure.  To retrieve the value of a parameter,
call it with zero arguments.  To set a new value, call it with one
argument.

@lisp
(define counter (make-parameter 0))
(counter)    ; => 0
(counter 1)
(counter)    ; => 1
(parameterize ((counter 2))
  (counter)) ; => 2
(counter)    ; => 1
@end lisp

@deffn {Procedure} make-parameter init [conv (lambda (x) x)]
Return a new parameter whose initial value is @var{(conv init)}.
@var{conv} is a procedure of one argument that transforms an incoming
value into the value that is actually stored within the parameter.
The default @var{conv} is an identity function that applies no
transformation at all.
@end deffn

@deffn {Syntax} parameterize ((parameter value) ...) body1 body2 ...
Evaluate @var{body1} @var{body2} @dots{} in a context where each
@var{parameter} is set to its respective @var{value}.  When control
leaves the dynamic extent of the body, each @var{parameter} is set
back to its previous value.
@end deffn

@node Hashtables
@section Hashtables

There are many mutable hashtable APIs amongst all the various Scheme
implementations, standards, and SRFIs.  From our point of view, there
is no clear ``best'' hashtable API that has emerged, but we think the
R6RS interface is OK.  Guile's own hashtable API has design issues
that are best left in the past.  So, the @code{(hoot hashtables)}
module is R6RS-like but with some notable differences.

@deffn {Procedure} make-hashtable [hash hash] [equiv equal?]
Return a new, empty hashtable that uses the hash procedure @var{hash}
and equivalence procedure @var{equiv}.
@end deffn

@deffn {Procedure} make-eq-hashtable
Return a new, empty hashtable that uses @code{eq?} as the equivalence
function and hashes keys accordingly.
@end deffn

@deffn {Procedure} make-eqv-hashtable
Return a new, empty hashtable that uses @code{eqv?} as the equivalence
function and hashes keys accordingly.
@end deffn

@deffn {Procedure} hashtable? obj
Return @code{#t} if @var{obj}
@end deffn

@deffn {Procedure} hashtable-hash table
Return the hash function for @var{table}.
@end deffn

@deffn {Procedure} hashtable-equiv table
Return the equivalence function for @var{table}.
@end deffn

@deffn {Procedure} hashtable-size table
Return the current number of key/value pairs in @var{table}.
@end deffn

@deffn {Procedure} hashtable-ref table key [default #f]
Return the value associated with @var{key} in @var{table}, or
@var{default} if there is no such association.
@end deffn

@deffn {Procedure} hashtable-set! table key value
Associate @var{val} with @var{key} in @var{table}, potentially
overwriting any previous association with @var{key}.
@end deffn

@deffn {Procedure} hashtable-delete! table key
Remove the association with @var{key} in @var{table}, if one exists.
@end deffn

@deffn {Procedure} hashtable-clear! table
Remove all of the key/value associations in @var{table}.
@end deffn

@deffn {Procedure} hashtable-contains? table key
Return @code{#t} if @var{key} has an associated value in @var{table}.
@end deffn

@deffn {Procedure} hashtable-copy table
Return a copy of @var{table}.
@end deffn

@deffn {Procedure} hashtable-keys table
Return a list of keys in @var{table}.
@end deffn

@deffn {Procedure} hashtable-values table
Return a list of values in @var{table}.
@end deffn

@deffn {Procedure} hashtable-for-each proc table
Apply @var{proc} to each key/value association in @var{table}.  Each
call is of the form @code{(proc key value)}.
@end deffn

@deffn {Procedure} hashtable-fold proc init table
Accumulate a result by applying @var{proc} with each key/value
association in @var{table} and the result of the previous @var{proc}
call.  Each call is of the form @code{(proc key value prev)}.  For the
first call, @code{prev} is the initial value @var{init}.
@end deffn

Hoot also includes weak key hash tables that wrap those of the Wasm
host platform, such as the @code{WeakMap} JavaScript class on the web.

@deffn {Procedure} make-weak-key-hashtable
Return a new weak key hashtable.
@end deffn

@deffn {Procedure} weak-key-hashtable? obj
Return @code{#t} if @var{obj} is a weak key hashtable.
@end deffn

@deffn {Procedure} weak-key-hashtable-ref hashtable key [default #f]
Return the value associated with @var{key} in @var{hashtable} or
@var{default} if there is no such association.
@end deffn

@deffn {Procedure} weak-key-hashtable-set! hashtable key value
Modify @var{hashtable} to associate @var{key} with @var{value},
overwriting any previous association that may have existed.
@end deffn

@deffn {Procedure} weak-key-hashtable-delete! hashtable key
Remove the association with @var{key} in @var{hashtable}, if one
exists.
@end deffn

The following hash functions are available:

@deffn  {Procedure} hash  key size
@deffnx {Procedure} hashq key size
@deffnx {Procedure} hashv key size
Return a hash value for @var{key} suitable for using in a table
containing @var{size} buckets.  The returned hash value will be in the
range [0, @var{size}).

@code{hashq} is the hash function used by @code{make-eq-hashtable},
and @code{hashv} is used by @code{make-eqv-hashtable}.
@end deffn

@node Records
@section Records

The @code{(hoot records)} module extends the R7RS
@code{define-record-type} form with additional features such as
inheritance and opaque types.

@deffn {Syntax} define-record-type name @
       [#:printer] [#:parent] [#:uid] [#:extensible? #t] [#:opaque? #f] @
       [#:allow-duplicate-field-names? #f] @
       constructor predicate @
       (field field-ref [field-set]) ...

Define a new record type descriptor bound to @var{name}.  Define a
constructor procedure bound to @var{constructor} and a predicate
procedure bound to @var{predicate}.  For each @var{field}, define an
accessor procedure @var{field-ref} and, optionally, a modifier
procedure @var{field-set}.

The record type will inherit from the record type descriptor bound to
@var{parent}, as long as @var{parent} is extensible.  By default,
record types are extensible.  A record type may be marked as ``final''
by passing an @var{extensible?} flag of @code{#f}.

When @var{opaque?} is @code{#t}, instances of this record type will be
compared for equality by identity @emph{only}.  This means that
@code{(equal? a b)} only returns @code{#t} when @code{a} and @code{b}
reference the same instance of the record type.  In other words, they
must be @code{eq?}.  The default behavior is to perform deep
structural equality checking by comparing record fields.

When @var{printer} is specified, that procedure will be used when
printing instances of this record type rather than the default
printer.

@var{uid} should be a unique identifier that will be associated with
the record type when specified.  Record types have no unique id by
default.

When @var{allow-duplicate-field-names?} is @code{#t}, field names may
appear more than once in the fields section.

@end deffn

@c @subsection Applicable records

@c Hoot's record type system can be used to create new types that can be
@c applied as if they were regular procedures.  These are known as
@c @emph{applicable records}.  The @code{<applicable-reord>} type defines
@c a single field that should contain a procedure.  Any record type that
@c descends from the @code{<applicable-record>} lineage (via
@c @code{#:parent}) becomes procedure-like.

@c As a contrived example, an incrementing counter could be implemented
@c like this:

@c @lisp
@c (use-modules (hoot records))

@c (define-record-type <counter>
@c   #:parent <applicable-record>
@c   (%make-counter procedure count)
@c   counter?
@c   (count counter-count set-counter-count!))

@c (define (make-counter)
@c   (define (next!)
@c     (let ((x (1+ (counter-count counter))))
@c       (set-counter-count! counter x)
@c       x))
@c   (define counter (%make-counter next! 0))
@c   counter)

@c (define c (make-counter))

@c (counter? c) ;; => #t

@c (procedure? c) ;; => #t

@c (c) ;; => 1
@c (c) ;; => 2
@c @end lisp

@c Note that @code{<counter>} objects are recognized as both counters
@c @emph{and} procedures!

@c @defvr {Variable} <applicable-record>
@c The record type descriptor for applicable records.
@c @end defvr

@c @deffn {Procedure} applicable-record? obj
@c Return @code{#t} if @var{obj} is an applicable record.
@c @end deffn

@c @deffn {Procedure} applicable-record-procedure obj
@c Return the procedure stored within the applicable record @var{obj}.
@c @end deffn

@c @deffn {Procedure} set-applicable-record-procedure! obj proc
@c Set the procedure stored within the applicable record @var{obj} to
@c @var{proc}.
@c @end deffn

@node Pattern matching
@section Pattern matching

Hoot provides a port of Guile's @code{(ice-9 match)} module for
pattern matching.  See @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Pattern-Matching.html,
Pattern Matching} in the Guile manual, @ref{Pattern Matching,,, guile,
GNU Guile Reference Manual}} for more information.

@node Foreign function interface
@section Foreign function interface

WebAssembly follows the capability security model, which means that
modules cannot do much on their own.  Wasm modules are guests within a
host.  They must be given capabilities by the host in order to
interact with the outside world.  Modules request capabilities by
declaring imports, which the host then fills out with concrete
implementations at instantiation time.  Hoot provides a foreign
function interface (FFI) in the @code{(hoot ffi)} module to embed
these import declarations within Scheme code.

The @code{define-foreign} form declares an import with a given type
signature (Wasm is statically typed) and defines a procedure for
calling it.  The FFI takes care of converting Scheme values to Wasm
values and vice versa.  For example, declaring an import for creating
text nodes in a web browser could look like this:

@lisp
(define-foreign make-text-node
  "document" "createTextNode"
  (ref string) -> (ref extern))
@end lisp

In the above example, the procedure is bound to the variable
@code{make-text-node}.  In the Wasm binary, this import is named
``createTextNode'' and resides in the ``document'' namespace of the
import table.  A Wasm host is expected to satisfy this import by
providing a function that accepts one argument, a string, and returns
an arbitary host value which may be null.

Note that declaring an import @emph{does not} do anything to bind that
import to an implementation on the host.  The Wasm guest cannot grant
capabilities unto itself.  Furthermore, the host could be any Wasm
runtime, so the actual implementation will vary.  In the context of a
web browser, the JavaScript code that instantiates a module with this
import could look like this:

@example
@verbatim
Scheme.load_main("hello.wasm", {
  user_imports: {
    document: {
      createTextNode: (text) => document.createTextNode(text)
    }
  }
});
@end verbatim
@end example

And here's what it might look like when using the Hoot interpreter:

@lisp
(use-modules (hoot reflect))
(hoot-instantiate (call-with-input-file "hello.wasm" parse-wasm)
                  `(("document" .
                     (("createTextNode" . ,(lambda (str) `(text ,str)))))))
@end lisp

Once defined, @code{make-text-node} can be called like any other
procedure:

@lisp
(define hello (make-text-node "Hello, world!"))
@end lisp

Since the return type of @code{make-text-node} is @code{(ref extern}),
the value of @code{hello} is an @emph{external reference}.  To check
if a value is an external reference, use the @code{external?}
predicate:

@lisp
(external? hello) ; => #t
@end lisp

External references may be null, which could indicate failure, a cache
miss, etc.  To check if an external value is null, use the
@code{external-null?} predicate:

@lisp
(external-null? hello) ; => #f
@end lisp

Note that we defined the return type of @code{make-text-node} to be
@code{(ref extern)}, not @code{(ref null extern)}, so @code{hello}
would never be null in this example.

A large application will likely need to manipulate many different
kinds of foreign values.  This introduces an opportunity for errors
because @code{external?} cannot distinguish between them.  The
solution is to wrap external values using disjoint types.  To define
such wrapper types, use @code{define-external-type}:

@lisp
(define-external-type <text-node>
  text-node? wrap-text-node unwrap-text-node)
@end lisp

@code{make-text-node} could then be reimplemented like this:

@lisp
(define-foreign %make-text-node
  "document" "createTextNode"
  (ref string) -> (ref extern))

(define (make-text-node str)
  (wrap-text-node (%make-text-node str)))

(define hello (make-text-node "Hello, world!"))

(external? hello)                    ; => #f
(text-node? hello)                   ; => #t
(external? (unwrap-text-node hello)) ; => #t
@end lisp

We've now explained the basics of using the FFI.  Read below for
detailed API documentation.

@deffn {Syntax} define-foreign scheme-name namespace import-name param-types ... -> result-type

Define @var{scheme-name}, a procedure wrapping the Wasm import
@var{import-name} in the namespace @var{namespace}.

The signature of the function is specified by @var{param-types} and
@var{result-type}, which are all Wasm types expressed in WAT form.

Valid parameter types are:

@itemize
@item i32: 32-bit integer
@item i64: 64-bit integer
@item f32: 32-bit float
@item f64: 64-bit float
@item (ref string): a string
@item (ref extern): a non-null external value
@item (ref null extern): a possibly null external value
@item (ref eq): any Scheme value
@end itemize

Valid result types are:

@itemize
@item none: no return value
@item i32: 32-bit integer
@item i64: 64-bit integer
@item f32: 32-bit float
@item f64: 64-bit float
@item (ref string): a string
@item (ref null string): a possibly null string
@item (ref extern): a non-null external value
@item (ref null extern): a possibly null external value
@item (ref eq): a Scheme value
@end itemize

@end deffn

@deffn {Procedure} external? obj
Return @code{#t} if @var{obj} is an external reference.
@end deffn

@deffn {Procedure} external-null? extern
Return @code{#t} if @var{extern} is null.
@end deffn

@deffn {Procedure} external-non-null? extern
Return @code{#t} if @var{extern} is not null.
@end deffn

@deffn {Procedure} procedure->external proc
Return an external reference that wraps @var{proc} as a function that
can be called on the host.

This procedure is particularly useful when registering event callbacks
on JavaScript hosts.
@end deffn

@deffn  {Syntax} define-external-type name predicate wrap unwrap
@deffnx {Syntax} define-external-type name predicate wrap unwrap print
Define a new record type named @var{name} for the purposes of wrapping
external values.  @var{predicate} is the name of the record type
predicate.  @var{wrap} is the name of the record type constructor.
@var{unwrap} is the name of the record field accessor that returns the
wrapped value.  Optionally, @var{print} is a procedure that accepts
two arguments (@code{obj} and @code{port}) and prints a textual
representation of the wrapped value.
@end deffn

@node Evaluation
@section Evaluation

Hoot is an ahead-of-time, whole-program compiler, but what if we want
to evaluate arbitrary Scheme code at runtime?  Fortunately, the
@code{(hoot eval}) module provides a Scheme interpreter for this
purpose!

Evaluation happens in the context of an environment.  Here's a simple
example:

@lisp
(use-modules (hoot eval) (hoot user))
(eval '(let ((x 1) (y 2)) (+ x y)) (interaction-environment))
@end lisp

@deffn {Procedure} eval exp toplevel-env
Evaluate @code{exp} in the context of the environment
@var{toplevel-env}.
@end deffn

The @code{(hoot user)} module provides a way to
capture the compile-time environment as an environment that can be
used by @code{eval}.

@deffn {Procedure} interaction-environment
Return an evaluation environment containing all of the bindings in the
current module.
@end deffn

@node Fibers
@section Fibers

Fibers is a facility for lightweight concurrency in Guile.  Hoot's
built-in fibers API is based on the third-party
@url{https://github.com/wingo/fibers,fibers library} available for the
Guile VM.

@menu
* Fibers example::              A simple example program.
* Operations::                  Asynchronous events.
* Channels::                    Communication between fibers.
* Timers::                      Sleepy fibers.
* Conditions::                  Send signals between fibers.
* Promises::                    Integrating fibers with the Wasm host.
* Streams::                     Stream-based I/O.
@end menu

@node Fibers example
@subsection Fibers example

Running a fibers program is a little different than running a regular
Scheme program.  Fibers programs need to be invoked in an asychronous
context from the host (usually JavaScript) and need to communicate the
overall success or failure of the program back to the host.

To demonstrate, let's make a @emph{very} simple program that sleeps
for one second before returning the value @code{42}.

@lisp
(use-modules (fibers promises)
             (fibers timers))

(lambda (resolved rejected)
  (call-with-async-result
   resolved rejected
   (lambda ()
     (display "Waiting... ")
     (force-output)
     (sleep 1)
     (display "done!\n")
     (force-output)
     42)))
@end lisp

Note that we've wrapped our program in a @code{lambda} that receives
@code{resolved} and @code{rejected} arguments.  When the Wasm host
calls this procedure in an asynchronous manner, these arguments will
be special host values that are used to resolve or reject the promise
(@pxref{Promises}) that represents the result of our program.  The
@code{call-with-async-result} procedure receives these host values and
takes care of all the promise plumbing for us.

To try this out, save the above code to @file{fibers-example.scm} and
run the following command:

@example
guild compile-wasm --run --async fibers-test.scm
@end example

The expected output is:

@example
Waiting... done!
(42)
@end example

There's just one value returned but since Scheme supports multiple
return values, the result of the program is a @emph{list} of values.

To invoke an asynchronous procedure from JavaScript, use the
@code{call_async} method on a @code{Procedure} object:

@example
const [proc] = await Scheme.load_main("fibers-test.wasm");
proc.call_async();
@end example

Read on for the detailed fibers API reference.

@node Operations
@subsection Operations

Operations are first-class abstractions for asynchronous events.
There are primitive operation types, such as waiting for a timer
(@pxref{Timers}) or waiting for a message on a channel
(@pxref{Channels}).  Operations can also be combined and transformed
using the @code{choice-operation} and @code{wrap-operation} from the
@code{(fibers operations)} module.

@deffn {Procedure} wrap-operation op f
Given the operation @var{op}, return a new operation that, if and when
it succeeds, will apply @var{f} to the values yielded by performing
@var{op}, and yield the result as the values of the wrapped operation.
@end deffn

@deffn {Procedure} choice-operation . ops
Given the operations @var{ops}, return a new operation that if it
succeeds, will succeed with one and only one of the sub-operations
@var{ops}.
@end deffn

Finally, once you have an operation, you can perform it using
@code{perform-operation}.

@deffn {Procedure} perform-operation op
Perform the operation @var{op} and return the resulting values.  If the
operation cannot complete directly, block until it can complete.
@end deffn

There is also a low-level constructor for other modules that implement
primitive operation types:

@deffn {Procedure} make-base-operation wrap-fn try-fn block-fn
Make a fresh base operation.
@end deffn

@node Channels
@subsection Channels

Channels are the way to communicate between fibers.  To use them, load
the @code{(fibers channels)} module.

@deffn {Procedure} make-channel
Make a fresh channel.
@end deffn

@deffn {Procedure} channel? obj
Return @code{#t} if @var{obj} is a channel, or @code{#f} otherwise.
@end deffn

@deffn {Procedure} put-operation channel message
Make an operation that if and when it completes will rendezvous with a
receiving operation to send @var{message} over @var{channel}.
@end deffn

@deffn {Procedure} get-operation channel
Make an operation that if and when it completes will rendezvous with a
sending operation to receive one value from @var{channel}.
@end deffn

@deffn {Procedure} put-message channel message
Send @var{message} on @var{channel}, and return zero values.  If there
is already a receiver waiting to receive a message on this channel,
give it our message and continue.  Otherwise, block until a receiver
becomes available.

Equivalent to:
@lisp
(perform-operation (put-operation channel message))
@end lisp
@end deffn

@deffn {Procedure} get-message channel
Receive a message from @var{channel} and return it.  If there is
already a sender waiting to send a message on this channel, take its
message directly.  Otherwise, block until a sender becomes available.

Equivalent to:
@lisp
(perform-operation (get-operation channel))
@end lisp
@end deffn

@node Timers
@subsection Timers

Timers are a kind of operation that, you guessed it, let you sleep
until a certain time.  The timer API can be found in the @code{(fibers
timers)} module.

@deffn {Procedure} sleep-operation seconds
Make an operation that will succeed with no values when @var{seconds}
have elapsed.
@end deffn

@deffn {Procedure} timer-operation expiry
Make an operation that will succeed when the current time is greater
than or equal to @var{expiry}, expressed in internal time units.  The
operation will succeed with no values.
@end deffn

@deffn {Procedure} sleep seconds
Block the calling fiber until @var{seconds} have elapsed.
@end deffn

@node Conditions
@subsection Conditions

Condition variables are a simple one-bit form of concurrent
communication.  A condition variable has two states: it starts in the
@dfn{unsignalled} state and later may transition to the
@dfn{signalled} state.  When a condition becomes signalled, any
associated waiting operations complete.  The following API can be
found in the @code{(fibers conditions)} module.

@deffn {Procedure} make-condition
Make a new condition variable.
@end deffn

@deffn {Procedure} condition? obj
Return @code{#t} if @var{obj} is a condition variable, or @code{#f}
otherwise.
@end deffn

@deffn {Procedure} signal-condition! cvar
Signal @var{cvar}, notifying all waiting fibers and preventing
blocking of future fibers waiting on this condition.
@end deffn

@deffn {Procedure} wait-operation cvar
Make an operation that will succeed with no values when @var{cvar}
becomes signalled.
@end deffn

@deffn {Procedure} wait cvar
Block the calling fiber until @var{cvar} becomes signalled.
Equivalent to @code{(perform-operation (wait-operation cvar))}.
@end deffn

@node Promises
@subsection Promises

Promises represent the result of a computation that may or may not
complete at some later point in time.  They are the primitive upon
which asynchronous concurrency is based in
@url{https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise,JavaScript},
whether using promises directly or through the
@url{https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function,async}/@url{https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await,await}
syntax.

Hoot fibers use these host promises under the hood and the
@code{(fibers promises)} module provides the API for doing so.  This
is @emph{mostly} transparent to the programmer, except at program
startup.  Programs that use fibers must be called in an async context
in which they receive special values used to resolve or reject the
promise representing the result of the entire program.  @xref{Fibers
example} for a walkthrough of this process.

@deffn {Procedure} await-promise-operation promise
Make an operation that will complete when @var{promise} is resolved.
Performing the operation produces one value: a thunk which when called
will either return the value or throw an exception.
@end deffn

@deffn {Procedure} await promise
Suspend the current fiber until @var{promise} is resolved.  If the
promise resolves successfully, one value is returned.  Otherwise, an
exception is thrown.
@end deffn

@deffn {Procedure} call-with-async-result resolved rejected thunk
Call @var{thunk} and resolve the promise with @var{resolved} and the
returned values.  If an exception is thrown, the promise is rejected
with @var{rejected} and the exception.

@var{resolved} and @var{rejected} are external host values that are
obtained by calling a Scheme procedure asynchronously from the host.
See the @code{Procedure.call_async} method in @ref{JavaScript
reflection} and the @code{hoot-apply-async} procedure in
@ref{Reflection} for more information on asynchronous procedure calls.
@end deffn

@node Streams
@subsection Streams

The @code{(fibers streams)} module provides an interface for wrapping
@url{https://developer.mozilla.org/en-US/docs/Web/API/Streams_API,web
stream} objects from the host with Scheme ports.

@deffn {Procedure} open-input-stream stream
Return an input port that reads from @var{stream}, an external
reference to a stream.
@end deffn

@deffn {Procedure} open-output-stream stream
Return an output port that writes to @var{stream}, an external
reference to a stream.
@end deffn

@defvr {Variable} standard-input-stream
An input port that reads from the host's standard input stream.
@end defvr

@defvr {Variable} standard-output-stream
An output port that writes to the host's standard output stream.
@end defvr

@defvr {Variable} standard-error-stream
An output port that writes to the host's standard error stream.
@end defvr

@node Finalization
@section Finalization

The @code{(hoot finalization)} module provides an interface for the
JavaScript
@url{https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry,FinalizationRegistry}
class, which notifies user code when a registered object has been
garbage collected.  Finalization registries are quite different from
Guile's @inlinefmtifelse{html,
@url{https://www.gnu.org/software/guile/manual/html_node/Guardians.html,
guardians}, @ref{Guardians,,,Guile Reference}}:

@itemize
@item
Guardians return references to the objects they have protected from
garbage collection.  Finalization registries @emph{do not} protect
objects from garbage collection at all.  Instead, when a registered
object is garbage collected, the finalization registry passes along a
user-specified ``held value''.  A held value @emph{cannot} be a
reference to the object being registered for finalization.

@item
Guardians are polled, whereas finalization registries use an
asynchronous callback function.

@item
Finalization registries allow objects to be unregistered, whereas
objects cannot be removed from a guardian once they have been added.

@end itemize

The following contrived example will print ``hey'' when the registered
object is garbage collected:

@lisp
(define (cleanup x)
  (display x)
  (newline))
(define registry (make-finalization-registry cleanup))
(finalization-registry-register! registry (list 'garbage) 'hey)
@end lisp

@deffn {Procedure} make-finalization-registry cleanup
Return a new finalization registry that will call @var{cleanup} (a
procedure of one argument) whenever a registered object is garbage
collected.
@end deffn

@deffn {Procedure} finalization-registry? obj
Return @var{#t} if @var{obj} is a finalization registry.
@end deffn

@deffn {Procedure} finalization-registry-register! registry target held-value [unregister-token]
Register @var{target} with @var{registry}.  When @var{target} is
garbage collected, the cleanup callback will receive @var{held-value}.
@var{held-value} @emph{cannot} be @code{eq?} to @var{target}.

If @var{unregister-token} is specified and not @code{#f} then this
token can be used to unregister @var{target} later.
@end deffn

@deffn {Procedure} finalization-registry-unregister! registry unregister-token
Unregister the objects associated with @var{unregister-token} from
@var{registry}.  Return @var{#t} if at least one object was
unregistered this way.
@end deffn

@node Modules
@section Modules

The @code{(hoot modules}) module provides a way to reflect and
interact with Hoot's runtime module system.  The runtime module system
is typically reserved for @emph{development builds only}, as its main
use case is for interactive development and their presence
significantly increases binary size.  To use the runtime module
system, ensure that programs are compiled with
@code{-gruntime-modules}.

@deffn {Parameter} the-root-module
Parameter containing the current root of the runtime module graph.
@end deffn

@deffn {Procedure} module? obj
Return @code{#t} if @var{obj} is a module.
@end deffn

@deffn {Procedure} make-empty-module [#:name '()] [#:root #f]
Return a fresh, empty module named @var{name} whose root module is
@var{root}.
@end deffn

@deffn {Procedure} module-name module
Return the name of @var{module}.
@end deffn

@deffn {Procedure} module-root module
Return the root module for @var{module}.
@end deffn

@deffn {Procedure} module-export! module name [src-name] [#:replace? #f]
Export @var{src-name} (@var{name} by default) as @var{name} in
@var{module}.  If @var{replace?} is @code{#t} then an existing export
may be overwritten.  Otherwise, an exception is raised in the event
that the export already exists.
@end deffn

@deffn {Procedure} module-import! dst src name [src-name]
Import the exported symbol @var{name} from module @var{src} into
module @var{dst} as @var{src-name} (@var{name} by default).
@end deffn

@deffn {Procedure} module-exported-names module
Return a list of names exported from @var{module}.
@end deffn

@deffn {Procedure} module-imported-modules module
Return a list of modules imported by @var{module}.
@end deffn

@deffn {Procedure} module-bound? module name [#:private? #f]
Return @code{#t} if @var{name} is bound in @var{module}.  By default,
@var{name} is looked up in the module's public namespace.  To perform
lookup in the private namespace instead, set @var{private?} to
@code{#t}.
@end deffn

@deffn {Procedure} module-ref module name [#:private? #f]
Return the top-level variable associated with @var{name} in
@var{module}.  By default, @var{name} is looked up in the module's
public namespace.  To perform lookup in the private namespace instead,
set @var{private?} to @code{#t}.
@end deffn

@deffn {Procedure} module-set! module name value [#:mutable-imports? #f] [#:private? #f]
Set the top-level variable associated with @var{name} in @var{module}
to @var{value}.  If @var{mutable-imports?} is @code{#t} then imported
variables are allowed to be modified, otherwise an exception is
raised.  By default, @var{name} is looked up in the module's public
namespace.  To perform lookup in the private namespace instead, set
@var{private?} to @code{#t}.
@end deffn

@deffn {Procedure} module-define! module name value [#:allow-redefinition? #f] [#:mutable? #t]
Define a top-level variable in @var{module} named @var{name} set to
@var{value}.  If @var{mutable?} is @code{#t} (the default) then the
variable will be mutable.  If @var{allow-redefinition?} is @code{#t}
then any previous definition of @var{name} will be clobbered.  By
default, redefinition is not allowed and an exception will be raised.
@end deffn

@deffn {Procedure} resolve-module module name [#:load? #f] [#:define? #f]
Return the module named @var{name} in @var{module}'s module graph.  If
no such module exists then one of a few things may happen.  If
@var{load?} is @code{#t} then try to load the module from source using
@var{current-module-loader}.  If @var{define?} is @code{#t} then
ensure that an empty module is created and return that.  If all of the
previous resolution strategies fail or are disabled then return
@code{#f}.
@end deffn

@deffn {Syntax} current-module
Return a runtime module for the module in which this form is expanded.
@end deffn

@deffn {Parameter} current-module-loader
Parameter containing the current procedure used for loading modules
from source code.
@end deffn

@node REPL
@section REPL

The @code{(hoot repl)} module provides a procedural API for
read-eval-print loops.  Additionally, it comes with a built-in driver
for a purely text-based REPL interface.  New drivers can be created by
integrating the procedural API with the desired interface, such as the
web's document object model.

REPLs contain a set of meta-commands and a stack of environments that
can be pushed and popped.

@deffn {Procedure} make-repl [#:environment] [#:meta-commands]
Return a fresh REPL for @var{environment} with @var{meta-commands}.
@end deffn

@deffn {Procedure} repl? obj
Return @code{#t} if @var{obj} is a REPL.
@end deffn

@deffn {Procedure} repl-environment repl
Return the current environment for @var{repl}.
@end deffn

@deffn {Procedure} repl-stack repl
Return the stack of previous environments for @var{repl}.
@end deffn

@deffn {Procedure} repl-depth
Return the current depth of @var{repl}.
@end deffn

@deffn {Procedure} repl-welcome repl
Return the welcome message for the current environment in @var{repl}.
@end deffn

@deffn {Procedure} repl-prompt repl
Return the current prompt message for @var{repl}.
@end deffn

@deffn {Procedure} repl-meta-commands repl
Return a list of meta-commands associated with @var{repl}.
@end deffn

@deffn {Procedure} repl-meta-command-ref repl
Return the meta-command in @var{repl} associated with @var{name}, or
@code{#f} if there is no such command.
@end deffn

@deffn {Procedure} repl-add-meta-command! repl cmd
Add meta-command @var{cmd} to @var{repl}.
@end deffn

@deffn {Procedure} repl-push! repl env
Enter a sub-REPL within @var{repl} using @var{env}, saving the
current environment on the environment stack to be restored later.
@end deffn

@deffn {Procedure} repl-pop! repl
Leave the current environment in @var{repl}, restoring the previous
environment if there is one.  Otherwise, raise an exception.
@end deffn

@deffn {Procedure} repl-read repl port
Read an expression from @var{port} using the current reader for
@var{repl}.  The returned expression may be a meta-command invocation.
@end deffn

@deffn {Procedure} repl-eval repl exp
Eval @var{exp} in the current environment of @var{repl}.
@end deffn

@deffn {Procedure} repl-eval-with-error-handling repl exp
Eval @var{exp}, either a language or meta-command
expression, in the current environment of @var{repl}.  If an exception
is thrown while evaluating a language expression, a debugging sub-REPL
will be entered.
@end deffn

@deffn {Procedure} repl-meta-eval repl cmd [args]
Invoke the meta-command @var{cmd} in @var{repl} with @var{args}.
@end deffn

@deffn {Parameter} current-repl
Parameter containing the current REPL being used for evaluation.  Can
be used in evaluated code to manipulate the host REPL.
@end deffn

The procedures below provide a classic textual REPL driver.

@deffn {Procedure} run-repl repl [#:reader]
Run @var{repl} using @var{reader} to prompt the user and read input.
A default reader is used if none is specified.

Reader procedures take a REPL object as their only argument.  Readers
should display the current prompt and parse an input expression with
the @var{repl-read} procedure.
@end deffn

@deffn {Procedure} spawn-repl [#:environment] [#:meta-commands] [#:reader]
Create and run a REPL for @var{environment} with @var{meta-commands}.
@end deffn

Environments are the context in which evaluation occurs.  They contain
a module (@pxref{Modules}) and a language for parsing and evaluating
REPL input.

@deffn {Procedure} make-repl-environment
Return a fresh REPL environment for evaluating @var{language} in
@var{module}.  @var{data} can be any arbitrary object to associate
with this environment, perhaps including debug information.
@var{welcome} is a procedure that displays a welcome message when the
enviroment is entered.  @var{prompt} is a procedure that returns an
input prompt to display to the user.  Both @var{welcome} and
@var{prompt} take just one argument: a REPL object.
@end deffn

@deffn {Procedure} repl-environment? obj
Return @code{#t} if @var{obj} is a REPL environment.
@end deffn

@deffn {Procedure} repl-environment-language env
Return the language for @var{env}.
@end deffn

@deffn {Procedure} repl-environment-module env
Return the module for @var{env}.
@end deffn

@deffn {Procedure} repl-environment-data env
Return the custom data for @var{env}.
@end deffn

@deffn {Procedure} repl-environment-welcome env
Return the welcome procedure for @var{env}.
@end deffn

@deffn {Procedure} repl-environment-prompt env
Return the prompt procedure for @var{env}.
@end deffn

Languages encapsulate a title string, a reader procedure, and an
evaluator procedure.  So, in theory, the Hoot interpreter could host
many languages, like the Guile VM does.  In practice, at least for
now, the language is always Scheme.

@deffn {Procedure} make-repl-language [#:title] [#:reader] [#:evaluator]
Return a new language named @var{title} that parses input text with
@var{reader} and evaluates expressions with @var{evaluator}.
@var{reader} is a procedure of one argument: an input port.
@var{evaluator} is a procedure of two arguments: an expression to
evaluate and a module in which to perform the evaluation.
@end deffn

@deffn {Procedure} repl-language? obj
Return @code{#t} if @var{obj} is a REPL language.
@end deffn

@deffn {Procedure} repl-language-title lang
Return the title of @var{lang}.
@end deffn

@deffn {Procedure} repl-language-reader lang
Return the read procedure for @var{lang}.
@end deffn

@deffn {Procedure} repl-language-evaluator lang
Return the evaluation procedure for @var{lang}.
@end deffn

Meta-commands are special REPL tools that can be invoked using a comma
at the beginning of the expression, such as @code{,help}.  New
meta-commands can be defined using @code{define-meta-command}.

@deffn {Syntax} define-meta-command (name repl args ...) kwargs ... body ...
Define a meta-command named @var{name} with an associated procedure
containing @var{body} that accepts @var{repl} and additionally any
other @var{args}.  The arguments list may include optional and keyword
arguments as in @code{define*}.

Additionally, there are several meta-command properties that may be
specified via @var{kwargs}:

@table @code
@item #:name
The symbol used to invoke this meta-command at the REPL prompt.

@item #:aliases
A list of symbols, each of which is an alternative name for this
meta-command.

@item #:group
The name of the meta-command group as a symbol.  Related meta-commands
should belong to the same group to ease user discovery.

@item #:usage
A string that describes how to invoke this meta-command.  A
meta-command with a required argument @code{foo} and an optional
argument @code{bar} might have the usage string @code{"FOO [BAR]"}.

@item #:summary
A brief documentation string.

@item #:documentation
A detailed documentation string.

@item #:reader
A procedure that reads meta-command arguments.  It takes two
arguments: a repl and a port.  This is an advanced configuration
option for meta-commands that need special argument parsing logic.
The default reader is usually sufficient.

@end table

This macro is best explained by example:

@lisp
(define-meta-command (meta:say repl #:optional message)
  ;; Keyword arguments:
  #:name 'say
  #:aliases '(s)
  #:group 'example
  #:usage "[MESSAGE]"
  #:summary "Say something."
  #:documentation "Say a few words, or maybe don't say anything at all."
  ;; Procedure body:
  (if message
      (format #t "You said: ~a\n" message)
      (display "You didn't say anything.")))
@end lisp

Once added to a REPL with @code{(repl-add-meta-command! repl
meta:say)}, it can be invoked with @code{,say} or its alias @code{,s}:

@example
(hoot user)> ,say "Hello!"
You said: Hello!
(hoot user)> ,s
You didn't say anything.
@end example

@end deffn

@deffn {Procedure} meta-command? obj
Return @code{#t} if @var{obj} is a meta-command.
@end deffn

@deffn {Procedure} meta-command-name cmd
Return the name of @var{cmd}.
@end deffn

@deffn {Procedure} meta-command-aliases cmd
Return the aliases of @var{cmd}.
@end deffn

@deffn {Procedure} meta-command-usage cmd
Return the documentation for @var{cmd}
@end deffn

@deffn {Procedure} meta-command-summary cmd
Return the documentation for @var{cmd}
@end deffn

@deffn {Procedure} meta-command-documentation cmd
Return the documentation for @var{cmd}
@end deffn

@deffn {Procedure} meta-command-reader cmd
Return the procedure used to read arguments for @var{cmd}.
@end deffn

@deffn {Procedure} meta-command-procedure cmd
Return the procedure used to perform @var{cmd}.
@end deffn

@node Toolchain reference
@chapter Toolchain reference

Hoot is not just a Scheme to Wasm compiler.  It's also a
self-contained and general purpose Wasm toolchain.  Hoot does not use
binaryen, wabt, emscripten, etc. in order to assemble and disassemble
Wasm.  The entire toolchain is implemented as a set of Scheme modules
that can be used to automate other Wasm targeted build workflows.
Since everything is implemented in one place, in a single language,
and because Guile encourages a REPL-driven development workflow, Hoot
makes a great platform for learning Wasm in a hands-on, interactive
way!

@menu
* Data types::                    Core Wasm module data types.
* Text format::                   Guile-flavored WebAssembly Text format.
* Resolver::                      Lower symbolic identifiers to integer identifiers.
* Symbolifier::                   Lift integer identifiers to symbolic identifiers.
* Linker::                        Add a standard library to a Wasm module.
* Assembler::                     Create Wasm binaries.
* Binary Parser::                 Parse Wasm binaries.
* Printer::                       Print the contents of a Wasm module.
* Interpreter::                   Execute Wasm within Guile.
* Wasm REPL commands::            Run and debug Wasm at the REPL.
@end menu

@node Data types
@section Data types

The @code{(wasm types)} module contains all the core data types that
comprise a Wasm module.

@subsection Modules

The Wasm module type is the top type, incorporating values of all the
types that are to follow.

@deffn {Procedure} wasm? obj
Return @code{#t} if @var{obj} is a Wasm module.
@end deffn

@deffn {Procedure} wasm-id wasm
Return the symbolic ID of @var{wasm}.
@end deffn

@deffn {Procedure} wasm-types wasm
Return the list of types in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-imports wasm
Return the list of imports in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-funcs wasm
Return the list of functions in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-tables wasm
Return the list of tables in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-memories wasm
Return the list of memories in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-globals wasm
Return the list of globals in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-exports wasm
Return the list of exports in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-elems wasm
Return the list of element segments in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-datas wasm
Return the list of data segments in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-tags wasm
Return the list of tags in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-strings wasm
Return the list of strings in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-custom wasm
Return the list of custom segments in @var{wasm}.
@end deffn

@deffn {Procedure} wasm-start wasm
Return the start function index for @var{wasm}.
@end deffn

@subsection Types

Wasm has four numeric types:

@enumerate
@item @code{i32}:
32-bit integer (signed or unsigned)
@item @code{i64}:
64-bit integer (signed or unsigned)
@item @code{f32}:
32-bit single precision IEEE floating point number.
@item @code{f64}:
64-bit double precision IEEE floating point number.
@end enumerate

There is also the @code{v128} vector type, but it is currently
unsupported.

Then there are a number of reference types that fall into 3
categories: function, external, and internal.

Function reference types:

@enumerate
@item @code{func}:
Function reference.
@item @code{nofunc}:
Bottom type for functions.  No function is of type @code{nofunc}.
@end enumerate

External reference types:

@enumerate
@item @code{extern}:
External reference introduced by the host.
@item @code{noextern}:
Bottom type for external references.  No external reference is of type
@code{noextern}.
@end enumerate

Internal reference types:

@enumerate
@item @code{any}:
The top type of all internal reference types.
@item @code{eq}:
Structural equivalence type.  Subtype of @code{all}.
@item @code{i31}:
Used for immediate references (such as the empty list or fixnums in
Scheme.)  Subtype of @code{eq}.
@item @code{array}:
Super type of all array types. Subtype of @code{eq}.
@item @code{struct}:
Super type of all struct types. Subtype of @code{eq}.
@item @code{none}:
The bottom type for internal references.  No internal reference is of
type @code{none}.
@end enumerate

Of course, modules may specify their own compound types assembled from
these primitives.

The type hierarchy looks like this:

@verbatim
              .-----.                         .-------.      .---------.
              | any |                         | func  |      | extern  |
              `-----'                         `-------'      `---------'
                 ↓                                ↓               ↓
              .-----.                        .-----------.  .-----------.
    .-------- | eq  | ------------.          | all funcs |  | noextern  |
    |         `-----'             |          `-----------'  `-----------'
    ↓            ↓                ↓               ↓
 .-----.  .-------------.    .---------.      .---------.
 | i31 |  | all arrays  |    | struct  |      | nofunc  |
 `-----'  `-------------'    `---------'      `---------'
                 ↓                ↓
              .-----.      .-------------.
              | any |      | all structs |
              `-----'      `-------------'
@end verbatim

A collection of type descriptor objects form a type table that
describes all non-primitive types used within a module.  Type objects
associate an identifier with a function signature or reference type
descriptor.

@deffn {Procedure} type? obj
Return @code{#t} if @var{obj} is a type.
@end deffn

@deffn {Procedure} type-id type
Return the symbolic ID of @var{type}.
@end deffn

@deffn {Procedure} type-val type
Return the type descriptor of @var{type}.
@end deffn

Types may also be nested within recursive type groups that allow for
circular and self references to the types within the group.  Types
@emph{not} within a group can be thought of as belonging to a group of
one.

@deffn {Procedure} rec-group? obj
Return @code{#t} if @var{obj} is a recursive type group.
@end deffn

@deffn {Procedure} rec-group-types rec-group
Return the types within @var{rec-group}.
@end deffn

Note that while each Wasm module contains a full inventory of its
types, structurally identical type groups across Wasm modules are
canonicalized at runtime and are considered to be identical
(@code{eq?} in Scheme terms.)  This allows for passing references
between modules.

Type uses refer to function signatures and are used for specifying the
type of a @code{block}, @code{loop}, or @code{if} expression.

@deffn {Procedure} type-use? obj
Return @code{#t} if @var{obj} is a type use.
@end deffn

@deffn {Procedure} type-use-idx type-use
Return the type index of @var{type-use}.
@end deffn

@deffn {Procedure} type-use-sig type-use
Return the function signature of @var{type-use}.
@end deffn


@deffn {Procedure} ref-type? obj
Return @code{#t} if @var{obj} is a reference type.
@end deffn

@deffn {Procedure} ref-type-nullable? ref-type
Return @var{#t} if @var{ref-type} is nullable.
@end deffn

@deffn {Procedure} ref-type-heap-type ref-type
Return the heap type of @var{ref-type}.
@end deffn

As mentioned above, reference types support structural subtyping.

@deffn {Procedure} sub-type? obj
Return @code{#t} if @var{obj} is a sub type.
@end deffn

@deffn {Procedure} sub-type-final? sub-type
Return @code{#t} if @var{sub-type} is marked as final.
@end deffn

@deffn {Procedure} sub-type-supers sub-type
Return super types of @var{sub-type}.
@end deffn

@deffn {Procedure} sub-type-type sub-type
Return the concrete type descriptor of @var{sub-type}.
@end deffn

Compound types take the form of arrays and structs.

@deffn {Procedure} array-type? obj
Return @code{#t} if @var{obj} is an array type.
@end deffn

@deffn {Procedure} array-type-mutable? array-type
Return @code{#t} if @var{array-type} is mutable.
@end deffn

@deffn {Procedure} array-type-type array-type
Retun the element type descriptor of @var{array-type}.
@end deffn

@deffn {Procedure} struct-type? obj
Return @code{#t} if @var{obj} is a struct type.
@end deffn

@deffn {Procedure} struct-type-fields struct-type
Return the field descriptors of @var{struct-type}.
@end deffn

Struct types are composed of several fields.

@deffn {Procedure} field? obj
Return @code{#t} if @var{obj} is a struct field.
@end deffn

@deffn {Procedure} field-id field
Return the symbolic ID of @var{field}.
@end deffn

@deffn {Procedure} field-mutable? field
Return @code{#t} if @var{field} is mutable.
@end deffn

@deffn {Procedure} field-type field
Return the type descriptor of @var{field}.
@end deffn

Both arrays and struct fields allow for packed data using the special
@code{i8} and @code{i16} data types.

@subsection Globals

Wasm supports both mutable and immutable global variables.

@deffn {Procedure} global? obj
Return @code{#t} if @var{obj} is a global.
@end deffn

@deffn {Procedure} global-id global
Return the symbloc ID of @var{global}.
@end deffn

@deffn {Procedure} global-type global
Return the type of @var{global}.
@end deffn

@deffn {Procedure} global-init global
Return the initialization instructions of @var{global}.  Only constant
instructions are allowed.
@end deffn

@deffn {Procedure} global-type? obj
Return @code{#t} if @var{obj} is a global type.
@end deffn

@deffn {Procedure} global-type-mutable? global-type
Return @code{#t} if @var{global-type} is mutable.
@end deffn

@deffn {Procedure} global-type-type global-type
Return the type descriptor of @var{global-type}.
@end deffn

@subsection Functions

@deffn {Procedure} func? obj
Return @code{#t} if @var{obj} is a function.
@end deffn

@deffn {Procedure} func-id func
Return the symbolic ID of @var{func}.
@end deffn

@deffn {Procedure} func-type func
Return the signature of @var{func}.
@end deffn

@deffn {Procedure} func-locals func
Return the locals of @var{func}.
@end deffn

@deffn {Procedure} func-body func
Return the body instructions of @var{func}.
@end deffn

The type of a function is its signature.  Notably, Wasm supports
multiple return values, just like Scheme.

@deffn {Procedure} func-sig? obj
Return @code{#t} if @var{obj} is a function signature.
@end deffn

@deffn {Procedure} func-sig-params func
Return the parameters of @var{func}.
@end deffn

@deffn {Procedure} func-sig-results func
Return the result types of @var{func}.
@end deffn

Function parameters pair a local identifier with its type.

@deffn {Procedure} param? obj
Return @code{#t} if @var{obj} is a param.
@end deffn

@deffn {Procedure} param-id param
Return the symbolic ID of @var{param}.
@end deffn

@deffn {Procedure} param-type param
Return the type descriptor of @var{param}.
@end deffn

Locals provide additional mutable variables scoped to the body of a
function.

@deffn {Procedure} local? obj
Return @code{#t} if @var{obj} is a function local.
@end deffn

@deffn {Procedure} local-id local
Return the symbolic ID of @var{local}.
@end deffn

@deffn {Procedure} local-type local
Return the type descriptor of @var{local}.
@end deffn

@subsection Imports/exports

Functions, globals, memories, and tables can be imported from the host
or another Wasm module.  They are organized into a two layer
hierarchy.  An import module groups many imports under an umbrella
name, and then the individual item names distinguish imported data
within a module.

@deffn {Procedure} import? obj
Return @code{#t} if @var{obj} is an import.
@end deffn

@deffn {Procedure} import-mod import
Return the module name string of @var{import}.
@end deffn

@deffn {Procedure} import-name import
Return the name string of @var{import}.
@end deffn

@deffn {Procedure} import-kind import
Return the kind of @var{import}.  Either @code{func}, @code{global},
@code{memory}, or @code{table}.
@end deffn

@deffn {Procedure} import-id import
Return the symbolic ID of @var{import}.
@end deffn

@deffn {Procedure} import-type import
Return the type descriptor of @var{import}.
@end deffn

Likewise, functions, globals, memories, and tables can be exported
from a module to be used by the host or by other modules.

@deffn {Procedure} export? obj
Return @code{#t} if @var{obj} is an export.
@end deffn

@deffn {Procedure} export-name export
Return the name string of @var{export}.
@end deffn

@deffn {Procedure} export-kind export
Return the kind of @var{export}.  Either @code{func}, @code{global},
@code{memory}, or @code{table}.
@end deffn

@deffn {Procedure} export-idx export
Return the index of @var{export}.
@end deffn

@subsection Linear memory

Memory objects specify linear chunks of bytes that a module can write
to/read from at runtime.  The size of a memory is specified in terms
of 64KiB pages.  While many memory objects coud be included in a
module, the Wasm specification currently only allows the use of a
single memory at index 0.

@deffn {Procedure} memory? obj
Return @code{#t} if @var{obj} is a memory.
@end deffn

@deffn {Procedure} memory-id memory
Return the symbolic ID of @var{memory}.
@end deffn

The type of a memory currently just specifies the size limitations.

@deffn {Procedure} memory-type memory
Return the type of @var{memory}.
@end deffn

@deffn {Procedure} mem-type? obj
Return @code{#t} if @var{obj} is a memory type.
@end deffn

@deffn {Procedure} mem-type-limits mem-type
Return the limits of @var{mem-type}.
@end deffn

Instructions that manipulate linear memory use the memory argument
type to point to a specific offset within a memory.

@deffn {Procedure} mem-arg? obj
Return @code{#t} if @var{obj} is a memory argument.
@end deffn

@deffn {Procedure} mem-arg-id mem-arg
Return the symbolic ID of @var{mem-arg}.
@end deffn

@deffn {Procedure} mem-arg-offset mem-arg
Return the offset of @var{mem-arg}.
@end deffn

@deffn {Procedure} mem-arg-align mem-arg
Return the alignment of @var{mem-arg}.
@end deffn

@subsection Data segments

Data segments are static chunks of data used to initialize regions of
memory.  They have two possible modes of use:

@enumerate
@item @strong{Active:}
The data segment is copied into memory during instantiation.
@item @strong{Passive:}
The data segment is copied into memory using the @code{memory.init}
instruction.
@end enumerate

@deffn {Procedure} data? obj
Return @code{#t} if @var{obj} is a data segment.
@end deffn

@deffn {Procedure} data-id data
Return the symbolic ID of @var{data}.
@end deffn

@deffn {Procedure} data-mode data
Return the mode of @var{data}.  Either @code{passive} or
@code{active}.
@end deffn

@deffn {Procedure} data-mem data
Return the memory associated with @var{data}.
@end deffn

@deffn {Procedure} data-offset data
Return the instructions that compute the offset of @var{data}.  Only
constant instructions are allowed.
@end deffn

@deffn {Procedure} data-init data
Return a bytevector containing the initialization data of @var{data}.
@end deffn

@subsection Tables

Tables specify a vector of heap object references of a particular
reference type.

@deffn {Procedure} table? obj
Return @code{#t} if @var{obj} is a reference table.
@end deffn

@deffn {Procedure} table-id table
Return the symbolic ID of @var{table}.
@end deffn

@deffn {Procedure} table-type table
Return the type of @var{table}.
@end deffn

Table types specify the reference type of the elements as well as the
size limitations.

@deffn {Procedure} table-type? obj
Return @code{#t} if @var{obj} is a table type.
@end deffn

@deffn {Procedure} table-type-limits table-type
Return the limts of @var{table-type}.
@end deffn

@deffn {Procedure} table-type-elem-type table-type
Return the element type of @var{table-type}.
@end deffn

@subsection Element segments

Element segments are static vectors of references used to initialize
regions of tables (well, mostly.)  They have three possible modes of
use:

@enumerate
@item @strong{Active:}
The element segment is copied into its associated table during
instantiation.
@item @strong{Passive:}
The element segment is copied into its associated table using the
@code{table.init} instruction.
@item @strong{Declarative:}
The element segment is unavailable at runtime and is instead used for
forward declarations of types that are used elsewhere in the code.
@end enumerate


@deffn {Procedure} elem? obj
Return @code{#t} if @var{obj} is an element segment.
@end deffn

@deffn {Procedure} elem-id elem
Return the symoblic ID of @var{elem}.
@end deffn

@deffn {Procedure} elem-mode elem
Return the mode of @var{elem}.
@end deffn

@deffn {Procedure} elem-table elem
Return the table associated with @var{elem}.
@end deffn

@deffn {Procedure} elem-type elem
Return the type of @var{elem}.
@end deffn

@deffn {Procedure} elem-offset elem
Return the instructions that compute the offset of @var{elem}.  Only
constant instructions are allowed.
@end deffn

@deffn {Procedure} elem-inits elem
Return a list of initializer instructions for the items of @var{elem}.
Only constant instructions are allowed.
@end deffn

@subsection Limits

Both memories and tables use limits to constrain their minimum and
maximum size.  A valid limit must have a minimum of at least 1, but
the maximum may be @code{#f} if unbounded growth is allowed.

@deffn {Procedure} limits? obj
Return @code{#t} if @var{obj} is a limits.
@end deffn

@deffn {Procedure} limits-min limits
Return the minimum value of @var{limits}.
@end deffn

@deffn {Procedure} limits-max limits
Return the maximum value of @var{limits} or @code{#f} if there is no
maximum.
@end deffn

@subsection Tags

Tag segments specify types of runtime errors that may be raised.

@deffn {Procedure} tag? obj
Return @code{#t} if @var{obj} is a tag.
@end deffn

@deffn {Procedure} tag-id tag
Return the symbolic ID of @var{tag}.
@end deffn

@deffn {Procedure} tag-type tag
Return the type of @var{tag}.
@end deffn

Tag types specify the function signature of the tags.  Since tags are
not truly functions, their signatures must only have parameters and no
results.

@deffn {Procedure} tag-type? obj
Return @code{#t} if @var{obj} is a tag type.
@end deffn

@deffn {Procedure} tag-type-attribute tag-type
Return the symbolic attribute of @var{tag-type}.  Currently, there is
only one valid attribute: @code{exception}.
@end deffn

@deffn {Procedure} tag-type-type tag-type
Return the type of @var{tag-type}.  This is expected to be a type use
object that refers to a function signature.
@end deffn

@subsection Custom sections

Custom sections specify arbitrary data that is not covered by the Wasm
specification.

@deffn {Procedure} custom? obj
Return @code{#t} if @var{obj} is a custom segment.
@end deffn

@deffn {Procedure} custom-name custom
Return the name of @var{custom}.
@end deffn

@deffn {Procedure} custom-bytes custom
Return the bytevector of @var{custom}.
@end deffn

There is, however, one custom section that @emph{is} specified: the
name section.  This section contains various ``name maps'' that can be
used to translate integer identifiers to (hopefully) human-readable
names for the purposes of debugging.

Hoot supports the name subsections described in the Wasm core
specification, the Wasm GC specification, and the extended names
proposal:

@enumerate
@item Module name
@item Function name map
@item Function local indirect name map
@item Block label indirect name map
@item Type name map
@item Table name map
@item Memory name map
@item Global name map
@item Element name map
@item Data name map
@item Struct field indirect name map
@item Tag name map
@end enumerate

Name maps are represented as association lists mapping integers to
strings.  Indirect name maps are represented as association lists
mapping integers to name maps.

@deffn {Procedure} names? obj
Return @code{#t} if @var{obj} is a name section object.
@end deffn

@deffn {Procedure} names-module names
Return the module name of @var{names}.
@end deffn

@deffn {Procedure} names-func names
Return the function name map of @var{names}.
@end deffn

@deffn {Procedure} names-local names
Return the function local indirect name map of @var{names}.
@end deffn

@deffn {Procedure} names-label names
Return the block label indirect name map of @var{names}.
@end deffn

@deffn {Procedure} names-type names
Return the type name map of @var{names}.
@end deffn

@deffn {Procedure} names-table names
Return the table name map of @var{names}.
@end deffn

@deffn {Procedure} names-memory names
Return the memory name map of @var{names}.
@end deffn

@deffn {Procedure} names-global names
Return the global name map of @var{names}.
@end deffn

@deffn {Procedure} names-elem names
Return the element name map of @var{names}.
@end deffn

@deffn {Procedure} names-data names
Return the data name map of @var{names}.
@end deffn

@deffn {Procedure} names-fields names
Return the struct field indirect name map of @var{names}.
@end deffn

@deffn {Procedure} names-tag names
Return the tag name map of @var{names}.
@end deffn

@node Text format
@section Text format

The @code{(wasm wat)} module provides a parser for a variant of
WebAssembly Text (WAT) format.  Since WAT uses an s-expression syntax
that resembles but is distinct from Scheme syntax, Hoot opts to
represent WAT code as Scheme expressions.  This allows for embedding
WAT directly into Scheme code and programmatically generating WAT code
via quasiquote templating or other means.  We call this variant GWAT
where the ``G'' stands for ``Guile'', of course.

Hoot's WAT variant has some additional expressive power such as
allowing string constants, bytevectors for data segments, and i32/i64
constants in either the signed or unsigned range.

WAT has two variants: unfolded and folded.  In the unfolded form,
instruction sequences are linear, as they would be in the resulting
binary:

@lisp
'(module
  (func (export "add") (param $a i32) (param $b i32) (result i32)
        (local.get $a)
        (local.get $b)
        (i32.add)))
@end lisp

The folded form allows instructions to be nested within each other:

@lisp
'(module
  (func (export "add") (param $a i32) (param $b i32) (result i32)
        (i32.add (local.get $a)
                 (local.get $b))))
@end lisp

This form looks more like Scheme procedure calls and is generally
easier to write and reason about.

@deffn {Procedure} wat->wasm expr
Parse @var{expr}, a Wasm module expressed as WAT code, and return a
Wasm module.

@lisp
(wat->wasm
 '(module
   (func (export "add") (param $a i32) (param $b i32) (result i32)
         (i32.add (local.get $a)
                  (local.get $b)))))
@end lisp

The returned Wasm module preserves named references, among other
things, and is thus unsuitable as input to the assembler or
interpreter.  To lower the module into a usable form, see
@code{resolve-wasm} in @ref{Resolver}.

@end deffn

@deffn {Procedure} wasm->wat wasm
Disassemble @var{wasm} and return its symbolic WAT form.  @var{wasm}
is assumed to be in @emph{symbolified} form (@pxref{Symbolifier}).
@end deffn

@node Resolver
@section Resolver

The @code{(wasm resolve)} module provides the @code{resolve-wasm}
procedure which lowers Wasm modules into a form that can be used by
the assembler or interpreter.  The resolver replaces named references
with their respective integer identifiers, fills out the type table,
and adjusts i32 and i64 constants into their canonical form.

@deffn {Procedure} resolve-wasm mod [#:emit-names? #f]
Lower the Wasm module @var{mod} into a form that can be assembled or
interpreted.  Returns a new Wasm module and does not modify @var{mod}.

When @var{emit-names?} is @code{#t}, the returned Wasm module will
include a name map that maps the original, human-readable names to the
resolved integer identifiers.
@end deffn

@node Symbolifier
@section Symbolifier

The @code{(wasm symbolify)} module does the opposite of @code{(wasm
resolve)} by giving symbolic names to all objects in a Wasm module.
Symbolified Wasm is useful for disassembling binaries (see
@code{wasm->wat} in @ref{Text format}).

@deffn {Procedure} symbolify-wasm wasm
Return a new Wasm module derived from @var{wasm} where all definitions
and uses have been given unique symbolic identifiers.
@end deffn

@node Linker
@section Linker

The @code{(wasm link)} module provides a means for extending a Wasm
module with the standard library that it needs at runtime.  Hoot uses
the linker to add the Scheme runtime to the compiled form of user
code.  The linker uses a form of tree-shaking to remove anything that
is not used by the base module.

@deffn {Procedure} add-stdlib wasm stdlib
Return a new Wasm module that is the combination of the Wasm module
@var{wasm} with the Wasm module @var{stdlib}.
@end deffn

@node Assembler
@section Assembler

The @code{(wasm assemble)} module is used to lower Wasm modules into
the Wasm binary format.

@deffn {Procedure} assemble-wasm wasm
Return a bytevector containing the assembled binary form of the Wasm
module @var{wasm}.
@end deffn

@node Binary Parser
@section Binary Parser

The @code{(wasm parse)} module parses the Wasm binary format.

@deffn {Procedure} parse-wasm port
Parse the Wasm binary data from @var{port} and return a Wasm module.
@end deffn

@deffn {Procedure} has-wasm-header? port
Return @code{#t} if the next 8 bytes read from @var{port} are the
magic bytes for a WebAssembly file.
@end deffn

@node Printer
@section Printer

The @code{(wasm dump)} module provides the @code{dump-wasm} procedure
for generating a detailed print-out of a Wasm module's contents.  See
also @ref{Wasm REPL commands} for the @code{wasm-dump} REPL
command.

@deffn {Procedure} dump-wasm mod [#:port] [#:dump-func-defs? #t]
Write a detailed inventory of the Wasm module @var{mod} to @var{port}
or the current output port if @var{port} is not specified.  If
@var{dump-func-defs?} is @code{#t}, which is the default, all function
definitions are printed, including the instructions in the body of
each.  Depending on the size of the module, this may be an
overwhelming amount of data, thus it is made optional.
@end deffn

@node Interpreter
@section Interpreter

The @code{(wasm vm)} module provides a virtual machine for
interpreting Wasm functions.  To use the interpreter, a Wasm module is
first validated for type safety (among other things) and then
instantiated, at which point exported functions become callable from
Scheme.

The interpreter only accepts validated Wasm.  The @code{validate-wasm}
procedure validates and wraps a Wasm module to indicate successful
validation:

@lisp
(use-modules (wasm vm) (wasm resolve))

(define validated-wasm
  (validate-wasm
   (wat->wasm
    '(module
      (func (export "main") (result i32)
            (i32.const 42))))))
@end lisp

When starting with a Wasm binary, the convenient
@code{load-and-validate-wasm} procedure parses the binary and then
performs validation:

@lisp
(call-with-input-file "hello.wasm" load-and-validate-wasm)
@end lisp

Once the Wasm module has been validated, the runtime data needed for
interpretation can be created by instantiating the module:

@lisp
(define instance (instantiate-wasm validated-wasm))
@end lisp

Exported Wasm functions then become usable as Scheme procedures:

@lisp
(define wasm-main (wasm-instance-export-ref instance "main"))
(wasm-main) ;; => 42
@end lisp

Wasm functions are statically typed, which means that calls from
Scheme to Wasm require runtime type checking for each call.

@subsection Validation

@deffn {Procedure} validate-wasm wasm
Validate the Wasm module @var{wasm} and return a validated Wasm
object.
@end deffn

@deffn {Procedure} load-and-validate-wasm obj
Load and validate the Wasm module within @var{obj} then return a
validated Wasm object.  @var{obj} may be a @code{<wasm>} record as
produced by @code{resolve-wasm} (@pxref{Resolver}), a bytevector
containing a Wasm binary, or an input port from which to read a Wasm
binary.
@end deffn

@deffn {Procedure} validated-wasm? obj
Return @code{#t} if @var{obj} is a validated Wasm object.
@end deffn

@deffn {Procedure} validated-wasm-ref validated-wasm
Unbox and return the Wasm module within @var{validated-wasm}.
@end deffn

@subsection Instantiation

@deffn {Procedure} instantiate-wasm wasm [#:imports '()]
Return a new Wasm instance for the validated Wasm module @var{wasm}.

@var{imports} is a nested association list of imported functions,
globals, memories, and tables.  Wasm imports are identified by a
module name and an object name.  Consider the following Wasm module
that computes 2D polar coordinates and prints them to a log:

@lisp
(use-modules (wasm resolve) (wasm vm) (wasm wat))

(define the-module
  (resolve-wasm
   (wat->wasm
    '(module
      (func $logf64 (import "debug" "logf64") (param f64))
      (func $cos (import "math" "cos") (param f64) (result f64))
      (func $sin (import "math" "sin") (param f64) (result f64))
      (func (export "polar") (param $r f64) (param $theta f64)
            (call $logf64 (f64.mul (local.get $r)
                                   (call $cos (local.get $theta))))
            (call $logf64 (f64.mul (local.get $r)
                                   (call $sin (local.get $theta)))))))))
@end lisp

This module requires three imported functions from two modules.  Thus
the module instantiation code would look like this:

@lisp
(define (logf64 x)
  (format #t "f64: ~a\n" x))

(define the-instance
  (instantiate-wasm (validate-wasm the-module)
                    #:imports `(("debug" . (("logf64" . ,logf64)))
                                ("math" . (("cos" . ,cos)
                                           ("sin" . ,sin))))))
@end lisp

@end deffn

@subsection Globals

@deffn {Procedure} make-wasm-global value mutable?
Return a new Wasm global containing @var{value}.  When @var{mutable?}
is @code{#f}, the value cannot be modified later.
@end deffn

@deffn {Procedure} wasm-global? obj
Return @code{#t} if @var{obj} is a Wasm global.
@end deffn

@deffn {Procedure} wasm-global-ref global
Return the current value within @var{global}.
@end deffn

@deffn {Procedure} wasm-global-set! global val
Set the value within @var{global} to @var{val}.  An exception is
raised if @var{global} is immutable.
@end deffn

@deffn {Procedure} wasm-global-mutable? global
Return @code{#t} if @var{global} is mutable.
@end deffn

@subsection Memories

@deffn {Procedure} make-wasm-memory size [#:limits (make-limits 1 #f)]
Return a new Wasm linear memory containing @var{size} 64KiB pages.
@var{limits} determines the lower and upper bounds of how many pages
this memory can store.  The default limits are a minimum of 1 page and
no maximum page limit.  @xref{Data types} for more information on
limit objects.
@end deffn

@deffn {Procedure} wasm-memory? obj
Return @code{#t} if @var{obj} is a Wasm memory.
@end deffn

@deffn {Procedure} wasm-memory-bytes memory
Return the current bytevector representing the pages of @var{memory}.
@end deffn

@deffn {Procedure} wasm-memory-size memory
Return the size of @var{memory} in 64KiB pages.
@end deffn

@deffn {Procedure} wasm-memory-limits memory
Return the limits of @var{memory}
@end deffn

@deffn {Procedure} wasm-memory-grow! memory n
Increase the size of @var{memory} by @var{n} pages.  An exception is
raised if growing by @var{n} exceeds the limits of @var{memory}.
@end deffn

@subsection Tables

@deffn {Procedure} make-wasm-table size [#:limits (make-limits 1 #f)]
Return a new Wasm reference table containing @var{size} element slots.
@var{limits} determines the lower and upper bounds of how many
elements this table can store.  The default limits are a minimum of 1
element and no maximum element limit.  @xref{Data types} for more
information on limit objects.
@end deffn

@deffn {Procedure} wasm-table?
Return @code{#t} if @var{obj} is a Wasm table.
@end deffn

@deffn {Procedure} wasm-table-size table
Return the size of @var{table}.
@end deffn

@deffn {Procedure} wasm-table-ref table i
Return the reference at the @var{i}th index in @var{table}.
@end deffn

@deffn {Procedure} wasm-table-set! table i x
Set the @var{i}th element of @var{table} to @var{x}, a Wasm reference
type.
@end deffn

@deffn {Procedure} wasm-table-fill! table start fill length
Fill the elements of @var{table} from @var{start} to @var{start} +
@var{length}, exclusive, with the value @var{fill}.
@end deffn

@deffn {Procedure} wasm-table-copy! table at elems start length
Copy the block of elements from vector @var{elems}, from @var{start}
to @var{start} + @var{length}, exclusive, to @var{table}, starting at
@var{at}.
@end deffn

@deffn {Procedure} wasm-table-grow! table n init
Increase the size of @var{table} by @var{n} elements.  An exception is
raised if growing by @var{n} exceeds the limits of @var{table}.
@end deffn

@subsection Observation

Every Wasm instruction evaluated by interpreter can be observed via
the @code{current-instruction-listener} parameter.  Use this hook to
instrument Wasm modules.

The following instruction listener would print every instruction's
name on a separate line:

@lisp
(define (log-instr instr path instance stack blocks locals)
  (display (car instr))
  (newline))

(parameterize ((current-instruction-listener log-instr))
  ...)
@end lisp

@defvar current-instruction-listener
The current instruction observation hook which is invoked
@emph{before} each instruction evaluation.  Must be a procedure that
accepts the following arguments:

@enumerate
@item @strong{Instruction:}
The symbolic Wasm instruction to be evaluated.
@item @strong{Path:}
The symbolic location of the instruction within the Wasm module.
@item @strong{Instance:}
The instance that is evaluating the instruction.
@item @strong{Stack:}
The Wasm value stack.
@item @strong{Blocks:}
The Wasm block stack, which is just a list of prompt tags.
@item @strong{Locals:}
The Wasm function locals.
@end enumerate

@end defvar

The Wasm value stack is a special data type with the following API:

@deffn {Procedure} wasm-stack? obj
Return @code{#t} if @var{obj} is a Wasm value stack.
@end deffn

@deffn {Procedure} wasm-stack-items stack
Return the values on @var{stack} as a list.
@end deffn

@node Wasm REPL commands
@section Wasm REPL commands

The @code{(hoot repl)} module provides a set of REPL commands to
assist with inspecting and debugging Wasm modules.  As a matter of
course, Hoot's Scheme compiler @emph{should not} cause low-level Wasm
runtime errors, but when it does, or when working with the Wasm
toolchain directly, these REPL tools may provide some assistance.

To install the REPL commands, simply import the module:

@lisp
scheme@@(guile-user)> ,use (hoot repl)
@end lisp

To see a list of all the Wasm commands, run:

@lisp
scheme@@(guile-user)> ,help wasm
@end lisp

To demonstrate the debugging features, let's create a trivial module
with a buggy function:

@lisp
@verbatim
scheme@(guile-user)> (define src
                       '(module
                         (func (export "main") (param $x i32) (result i32)
                               (i32.add (local.get $x)
                                        (unreachable)))))
@end verbatim
@end lisp

When called, this function will hit the @code{unreachable} instruction
and throw a runtime error.  Let's compile the WAT source, load it into
the VM, and get a reference to the @code{main} function:

@lisp
@verbatim
scheme@(guile-user)> ,use (wasm resolve) (wasm vm) (wasm wat)
scheme@(guile-user)> (define wasm (validate-wasm (resolve-wasm (wat->wasm src))))
scheme@(guile-user)> (define instance (instantiate-wasm wasm))
scheme@(guile-user)> (define main (wasm-instance-export-ref instance "main"))
@end verbatim
@end lisp

To trap the Wasm runtime error and open a Wasm debugging REPL, the
@command{wasm-catch} REPL command can be prefixed before an
expression:

@lisp
@verbatim
scheme@(guile-user)> ,wasm-catch (main 7)
ice-9/boot-9.scm:1674:22: In procedure raise-exception:
ERROR:
  1. &wasm-runtime-error:
      instruction: (unreachable)
      position: (func 0 1)
      instance: #<wasm-instance 140506559041920>
      stack: #<<wasm-stack> items: (7)>
      blocks: ((wasm-block))
      locals: #(7)
  2. &message: "Wasm runtime error: unreachable"
  3. &irritants: ()

Entering Wasm debug prompt. Type `,help wasm' for info or `,q' to continue.
scheme@(guile-user) [1]>
@end verbatim
@end lisp

Once in a Wasm debug context, many of the other REPL commands become
usable.  To highlight the instruction where execution has paused, use
@command{wasm-pos}:

@lisp
@verbatim
scheme@(guile-user) [1]> ,wasm-pos
(func 0 (param $x i32) (result i32)
  (local.get 0)
  <<< (unreachable) >>>
  (i32.add))
@end verbatim
@end lisp

To print the contents of the values stack, use @command{wasm-stack}:

@lisp
@verbatim
scheme@(guile-user) [1]> ,wasm-stack
Value stack:
  0:	7
@end verbatim
@end lisp

To print the contents of the function locals, use @command{wasm-locals}:

@lisp
@verbatim
scheme@(guile-user) [1]> ,wasm-locals
Locals:
  0:	7
@end verbatim
@end lisp

To evaluate arbitary Wasm instructions in the current context, either
in an attempt to repair interpreter state or just for fun, use
@command{wasm-eval}:

@lisp
@verbatim
scheme@(guile-user) [1]> ,wasm-eval '(local.get 0)
scheme@(guile-user) [1]> ,wasm-stack
Value stack:
  0:	7
  1:	7
@end verbatim
@end lisp

There are now two i32 values on the stack.  If we were to proceed with
execution, the next instruction, @code{i32.add}, should add them
together and return a result of 14.  To resume execution, use
@command{wasm-continue}:

@lisp
@verbatim
scheme@(guile-user) [1]> ,wasm-continue
$5 = 14
@end verbatim
@end lisp

Evaluating arbitrary Wasm commands in a debugging context is very
helpful when trying to understand the nature of a bug, but bear in
mind that cursed things may happen during the process as there is no
validation applied. This goes especially for when you try to resume
execution.

See @ref{Interpreter} for detailed information on running Wasm within
Guile and @ref{Toolchain reference} in general for working with Wasm
directly.

@deffn {REPL Command} wasm-trace exp
Evaluate @var{exp} with verbose Wasm tracing enabled.  This will print
out every instruction along with the state of the value stack and
function locals at the time of evaluation.
@end deffn

@deffn {REPL Command} wasm-freq exp
Evaluate @var{exp} and print out a table showing how many times each
kind of Wasm instruction was executed as well as a total instruction
count.
@end deffn

@deffn {REPL Command} wasm-catch exp
Catch and debug Wasm runtime errors that are raised by evaluating
@var{exp}.
@end deffn

The following commands are usable only in the context of a Wasm debug
REPL:

@deffn {REPL Command} wasm-stack
Print the state of the Wasm stack.
@end deffn

@deffn {REPL Command} wasm-locals
Print the state of the Wasm function locals.
@end deffn

@deffn {REPL Command} wasm-pos
Print the current function disassembly and highlight the instruction
where Wasm execution has paused.
@end deffn

@deffn {REPL Command} wasm-eval instr
Evaluate the Wasm instruction @var{instr} in the current debug
context.  Use this when attempting to fix the state of the Wasm stack
or locals before attempting to resume with @code{,wasm-continue}.
@end deffn

The following commands behave differently depending on if they are run
within a Wasm debug REPL or not.

@deffn {REPL Command} wasm-dump [wasm]
Display information about @var{wasm}, or the current Wasm instance
when debugging.
@end deffn

@deffn {REPL Command} wasm-continue
When in a debugger, exit and resume Wasm execution.  In the event that
this is run after trapping a runtime error, your warranty is void and
all bets are off!  While it may be dangerous, this does allow one to
manually fix the Wasm interpreter state manually with
@code{,wasm-eval} and attempt to proceed, which can come in handy
sometimes.

When not in a debugger, set the Wasm execution mode to continue
without interruption.  In other words, deactive the instruction
stepper if it is active.
@end deffn

@deffn {REPL Command} wasm-step
When in a debugger, resume Wasm execution but pause before the next
instruction is evaluated.

When not in a debugger, set Wasm execution to pause before each
instruction is evaluated.
@end deffn

@node Contributing
@chapter Contributing

Found a bug?  Let us know!  Made an improvement?  Show us!  Issues can
be filed and pull requests can be submitted on
@url{https://codeberg.org/spritely/hoot,Codeberg}.

@node License
@chapter License

@emph{(C) 2023-2025 David Thompson}

@emph{Both Guile Hoot and this manual are released under the terms of
the following license:}

@include apache-2.0.texi

@node Index
@unnumbered Index

@printindex fn

@bye
