Become a Spritely supporter today!

We're building the next generation of distributed web technology for secure collaboration and we need your help to fill up our health bar

$51,333 of $80,000 raised so far! Please support Spritely!

Guile Hoot v0.4.0 released!

Dave Thompson —

Hoot version 0.4.0

We are excited to announce the release of Guile Hoot v0.4.0! Hoot is a Scheme to WebAssembly compiler backend for Guile, as well as a general purpose WebAssembly toolchain. In other words, Scheme in the browser!

Highlights

  • Hoot now supports user-defined modules. Users no longer have to stuff their entire program into one file! Currently, the R6RS library syntax is supported, with R7RS define-library and Guile define-module syntax to come in a future release.

  • The standard library is now available as a collection of importable modules. Hoot supports the standard (scheme ...) namespace as specified by R7RS-small. Non-standard interfaces are available under the (hoot ...) namespace. The see manual for more information about available non-standard interfaces.

  • An example project was added to the source tree in Git, examples/project-template, to serve as an easy starting point for new Hoot projects. This example project also ships with our official release tarballs. See the template's README for more information.

  • More of R7RS-small has been implemented and Hoot can now run 54 out of 57 Scheme benchmarks!

Read on for the full change log.

R7RS-small

  • Improved support for call-with-current-continuation.

  • Added support for complex number arithmetic.

  • Added support for cyclic data structures to equal?.

  • Added support for file ports (call-with-input-file, call-with-output-file) with the caveat that they only work in non-browser runtimes such as NodeJS 22+ or Hoot's own Wasm interpreter.

  • Fixed bignum/fraction division.

  • Fixed missing fraction/flonum arithmetic cases.

  • Fixed get-output-bytevector when total output size is greater than buffer size.

  • Fixed close-port to call the port object's close hook.

Non-standard interfaces

  • Added support for Guile's keyword argument dispatch syntax define*, and lambda*. To use them, add (only (hoot syntax) define* lambda*) to your program/module's import form.

Compiler

  • Added #:load-library and #:extend-load-library keyword arguments to compile, compile-file, and read-and-compile.

  • Improved error messages for unbound variables.

  • Added new --load-path flag to guild compile-wasm that allows loading user modules from the file system.

  • Added new --emit-names flag to guild-compile-wasm that emits debug names in the resulting Wasm binary.

  • Fixed guild compile-wasm passing an invalid keyword argument to compile.

Runtime

  • Errors that occur in standard library functions implemented in Wasm now throw Scheme exceptions rather than crashing. For example, it is now possible to catch the type error thrown by (+ 1 "two").

  • Entry to the Hoot ABI via reflect.wasm now pushes the default prompt. Used for call-with-current-contination.

  • Fixed issue where sending large strings from Wasm to JS caused a stack overflow.

Toolchain

  • Added support for the Wasm exceptions proposal (tag objects and try, try_delegate, throw, rethrow instructions) as currently shipped in major browsers.

  • The disassembler wasm->wat now expects symbolified input (via symbolify-wasm) and produces much better output that more closely resembles Wasm disassembly in Chrome dev tools.

  • Fixed multi-value block type handling in push-block in (wasm stack).

Notable issues

  • A special combination of branching code involving continuations with known return arity can lead to miscompilations that express themselves as Wasm runtime errors in the form of table.get instructions with a negative index or an invalid type cast. GitLab issue

  • Usage of define-record-type within the top-level of the main program (not in a module) leads to a compilation error. The workaround for now is to wrap the program body in a (let () ...) form. GitLab issue

  • Some uses of dynamic-wind cause compilation errors due to an unhandled thunk? primitive. Hoot expects such primitives to be removed. This seems to be caused by Guile's partial evaluator terminating earlier than desired and likely requires a fix to upstream Guile. GitLab issue

Browser compatibility

  • Compatible with Firefox 121 or later.

  • Compatible with Google Chrome 119 or later.

  • Safari/WebKit is unsupported, unfortunately, as Wasm GC and tail calls are still not available.

Get Hoot 0.4.0!

Hoot is already available in GNU Guix:

$ guix pull
$ guix install guile-next guile-hoot

(Hoot currently requires a bleeding-edge version of Guile, hence guile-next above.)

Otherwise, Hoot can be built from source via our release tarball. See the Hoot homepage for a download link and GPG signature.

Documentation for Hoot 0.4.0, including build instructions, can be found here.

Get in touch!

For bug reports, pull requests, or just to follow along with development, check out the Hoot project on GitLab.

If you build something cool with Hoot, let us know on our community forum!

The code in this release was brought to you by Andy Wingo and David Thompson. The lovely Hoot art is by tessa. Special thanks to the MetaMask folks for funding this work!

Until next time, happy hooting! 🦉