Goeteia: A Self-Hosting Scheme Compiler That Lives in Your Browser via Wasm GC
Goeteia is a self-hosting Scheme compiler that compiles itself to WebAssembly GC in the browser — no server needed, just a 70 KB gzipped wasm blob and a reactive web stack.
Goeteia is a Scheme compiler that runs entirely in your browser. The page you're reading is compiled live from Scheme source to WebAssembly GC, with no server-side compilation. The entire compiler is a single goeteia.wasm file (~70 KB gzipped, cached after first load), and recompilation takes about 15 ms.
Self-hosting to the byte
The compiler is written in the subset of Scheme it compiles. The self-hosted build recompiles itself, and the output is byte-identical — a fixpoint checked in CI on every change. Every test runs through both stages to ensure correctness.
Native Wasm GC objects
Fixnums are unboxed i31refs, pairs and records are GC structs, and eq? is a single ref.eq. There's no shadow heap in JavaScript: the host supplies only two byte-stream imports.
Hygienic macros and real closures
Goeteia supports syntax-rules and procedural syntax-case with fenders, nested ellipses, and datum->syntax. Closures use typed function references with fast per-arity entry and a generic entry for variadic procedures. Every tail call is a return_call, so a 100M-iteration loop runs in constant stack in ~150 ms.
call/cc and dynamic-wind
Escape continuations use the Wasm exception-handling proposal: capture is O(1), the normal path costs one try block, and winders unwind inner-to-outer on exit.
Reactive web stack and 3D
The (web sx) module provides reactive templates over fine-grained signals, an HTML renderer, and a JavaScript FFI. The (web three) module builds reactive Three.js scenes, while (web gl) drives raw WebGL through a command buffer — one bridge call per frame — with shaders written as s-expressions in (web glsl).
Scheme-to-Scheme RPC
When the backend is also Scheme (Igropyr), requests and replies are s-expressions. (rpc "/rpc" '(add 1 2 1/2)) returns (ok 7/2) with exact rationals. The (web fetch) module uses direct-style Wasm JSPI; (web ws) and (web sse) push datum streams; (web json) handles everyone else.
Quick start
$ git clone https://github.com/guenchi/Goeteia
$ cd Goeteia
$ ./run-tests.sh
$ ./build-self.sh
$ echo '(define (fact n) (if (zero? n) 1 (* n (fact (- n 1)))))
(fact 20)' > fact.ss
$ node rt/compile.mjs goeteia.wasm fact.ss fact.wasm
$ node rt/run.mjs fact.wasm
2432902008176640000Compiled modules run on any engine with Wasm GC and tail calls: Node 22+, current Chrome/Firefox/Safari, and wasmtime. Bootstrapping from source needs Chez Scheme; the checked-in compiler wasm works without it.
Discussion
0 Comments
Be the first to start the discussion.