Hoot 0.8.0 released!

Dave Thompson —

We are excited to announce the release of Hoot 0.8.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!

This release contains new features and bug fixes and since the 0.7.0 release back in October.

New features

  • New (hoot repl) module. At long last, there is now a built-in read-eval-print loop implementation! Previous releases added a macroexpander, a Scheme interpreter, and a runtime module system, but now it's possible to do live hacking from a Hoot program inside a WebAssembly runtime!

    • To use the REPL, compile your Wasm binary with the necessary debug flag during development: guild compile-wasm -g runtime-modules. This will include the runtime module system in the resulting binary. Expect compilation time and binary size to increase significantly. The trade-off is that a live hacking workflow should make recompilations fewer and farther between.

  • While not shipping in Hoot directly, initial support for using the Hoot REPL from Emacs has been added in the new geiser-hoot library. We expect to release this more formally and package it for easy installation with Guix or Emacs' built-in package manager in the near future.

  • Enhanced (hoot web-server) module. To support the use of REPLs running within a web browser tab, the most common development use case, the web server doubles as a REPL server, proxying TCP traffic from REPL clients (more about that below) over a WebSocket to the connected browser tab.

    • These enhancements introduce two new, optional depedencies to Hoot: Fibers and guile-websocket. If either of these dependencies are not present at build time, the (hoot web-server) module will not be built.

  • New (hoot web-repl) module. This module can be imported and compiled into the Wasm binary so that it can act as a REPL "server". "Server" is quoted because a browser tab cannot act as a server, it is strictly a client. Instead, it connects to the aforementioned (hoot web-server) which as a proxy for all connected REPL clients.

  • New hoot command-line tool. This tool will be used as a place to collect handy Hoot development tools. This initial version has two subcommands:

    • hoot repl: Open a REPL running in Node. Useful for quickly trying out basic Scheme expressions in Hoot without having to compile a standalone WebAssembly program.

    • hoot server: Conveniently launch the development web server in (hoot web-server).

  • New (web request) and (web response) modules that export a sliver of the API defined in Guile's modules of the same names.

  • New (web socket) module that provides a input/output interface to WebSocket client connections. Mimicks the module of the same name in guile-websocket.

  • Added customizable module loader interface via new current-module-loader parameter. Two concrete loaders are provided: By default, modules are loaded from the file system by searching a load path. This is useful when running in a non-browser runtime such as NodeJS. When run-web-repl in (web repl) is used, connected REPLs are configured to use an HTTP-based loader. This loader makes HTTP requests to a special endpoint on the development web server to fetch source code.

    • Note that modules loaded at runtime are loaded from source and then interpreted. Unlike Guile, where modules are automatically compiled to bytecode, Hoot cannot compile individual modules to Wasm (which would require compiling the Wasm compiler to Wasm which is an interesting and overwhelming future possibility).

Documentation changes

  • Updated Installation chapter to mention new optional dependencies.

  • Added Modules and REPL sections to the Scheme reference chapter.

  • Added Development chapter.

  • Update Status section to remove mention of missing R7RS support that we have now.

  • Removed docs for obsolete --emit-names flag

  • Add documentation for -g flag to guild compile-wasm.

Toolchain changes

  • Split Wasm validation out of (wasm vm) module and into new (wasm validation) module.

  • Keep data computed within the validation pass in <validated-wasm> records so that data can be used during instantiation rather than redundantly recomputing it.

  • Added explicit support for representing a "canonicalization": a world in which structurally equal types are equal.

  • (wasm vm) types <wasm-func>, <wasm-struct>, <wasm-array> now refer to their types by index into a canonicalized set.

  • Added untagged <wasm-array> backing stores to (wasm vm) for all simple scalar numeric types, including i8 and i16 packed types.

  • Modified (wasm vm) to look up named heap type references in the instance's canonicalization.

  • Added bytevector->wasm-array, wasm-array->bytevector to (wasm vm).

  • Added support for some of the "none" bottom types.

  • Packed data is stored signed, wrapped from i32 when set, and only unwrapped to unsigned in get_u functions.

Miscelanneous changes

  • Made schedule-task, which is implemented using inline Wasm, a no-op when called at expansion time on the host machine.

  • Added support for vector and call-with-values primitives to (hoot primitives) module so they can be used in interpreted code.

  • truncate is now exported from (guile).

  • Allow exports to clobber each other in module-declare! to support live hacking of modules where define-module forms are often re-evaluated many times.

  • Extracted JS Uint8Array bindings from internals of (fibers streams) to new (hoot typed-arrays) module.

  • Implement subset of Guile's procedural module API for hackable programs (i.e. programs that are built with runtime module support).

  • Added (hoot config) target-side module for accessing certain build-time constants (currently just the Hoot version string).

  • Extracted (hoot library) module from (hoot library-group) so that the library parser can be used on the target for live hacking purposes.

  • Added define-module implementation to (guile) that simply throws an error if used during compilation. A separate implementation is installed for use by the interpreter in hackable programs.

  • Added #:replace? argument to module-export! to allow replacement of exports for live hacking purposes.

  • Exported module-root from (hoot modules).

  • Added module-imported-modules procedure to (hoot modules).

  • Changed file I/O host functions to return null when a file cannot be opened so a Scheme exception that can be handled by user code rather than a host exception that cannot.

  • Extracted contents of (scheme file) to new (hoot file) module for use in internal code such as the implementation of the file system module loader in (hoot hackable).

  • Moved implementation of string-join, string-concatenate, string-prefix?, and string-prefix-ci? from (guile) to (hoot strings).

  • Moved case-insensitive string procedures from (scheme char) to (hoot strings).

  • Added string-drop to (hoot strings).

  • Added every and fold-right procedures to (hoot lists).

  • Moved implementation of and-map and or-map from (guile) to (hoot lists).

  • Added symbol-append to (hoot symbols).

  • Added less verbose custom printer for <module> record type.

  • Switched from positional to keyword arguments for make-soft-port in (hoot ports).

Bug fixes

  • Fixed format-exception not writing all of its output to the current error port.

  • Fix eof-object export in (ice-9 binary-ports).

  • Fixed off-by-one error for procedures with rest args in (hoot eval).

  • Fixed min/max to only accept real numbers, handle NaNs, and normalize exact zeroes.

  • Fixed continuation composition leaving an unwind continuation on the stack.

  • Fixed prompt unwinding in certain join continuation situations.

  • Fixed compilation of unwind primcalls at join points.

Browser compatibility

  • Compatible with Safari 26 or later.

  • Compatible with Firefox 121 or later.

  • Compatible with Chrome 119 or later.

Get Hoot 0.8.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.8.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 Codeberg.

If you build something cool with Hoot (for the upcoming game jam or otherwise), let us know on our community forum!

Thanks to our supporters

TODO

Until next time, happy hooting! 🦉