# shen $ ./zincvm globals.csexp --meta-repl

A language that evaluates itself.

self-hosted Shen — a C11 VM · custom moving generational GC · ~295 bundled closures · no host runtime

The self-hosting thesis

// Shen evaluates Shen, compiles itself to native bytecode, runs on a C VM

The full eval-kl chain is working: (+ 1 2) marshalled to tagged form, compiled through the metacircular pipeline, executed by the metacircular interpreter, demarshalled back to native — it returns 3. Pure self-hosting, no C bypass.

The meta-circular evaluator is the core — the ZINC abstract machine implemented in ~100 lines of Shen pattern-matching rules, serialized to ~0.33 MB of bytecode, and loaded by a ~2600-line C VM with a custom moving generational garbage collector. The VM is self-contained: a working Shen runtime that depends only on a C compiler and its own GC — no Boehm, no host runtime.

Run it in your browser — the real C VM, compiled to WebAssembly, in an xterm.js terminal. No setup, no server.
Open the Playground →
  • Evaluates itself — the metacircular interpreter is written in Shen and runs on the C VM.
  • Compiles itself — the reduced bundle is compiled by our own shen->kl compiler, no Shen OS code.
  • Own garbage collector — a custom moving generational collector (nursery + old-gen, precise roots, write barrier).

The pipeline

// Shen source → KLambda → ZINC bytecode → C VM
Shen source → shen->kl (own compiler) → KLambda → kmacros → normalize → debruijn
            → zinc-c → csexp → C VM
                                        ↑
             interp.shen (meta-circular ZINC VM on Shen/Chez)
                    ↓
  serialize-reduced → globals.csexp → C VM (self-hosting)

Every stage — the Shen→KLambda front-end, the normalizer, the ZINC compiler, the metacircular interpreter, the serializer — is part of this repo. The full architecture walk-through →

Feature summary

// the stack in one table
LayerWhat it does
shen->klOwn full-arity Shen→KLambda compiler (safe subset, no partial application).
normalizeKLambda expansion, A-normal form, debruijn indices.
zinc-cKLambda → ZINC bytecode, incl. %% primitive dispatch.
interpThe ZINC interpreter in Shen — loads, compiles, and runs.
zincvm.cThe native C parser + VM — all primitives, closures, tail calls, custom GC.
zincdecStandalone bytecode decompiler — 4 output formats + --curried scan.

Proven self-hosting

// the eval-kl chain, end to end
1

Marshal

Native values are marshalled to tagged Shen forms through the marshal_to_tagged layer.

2

Compile

The tagged form goes extract-kl → kl→zinc → toplevel-interp — compiled entirely by our own compiler.

3

Execute

The metacircular interp (97 pattern-match rules in shen/interp.shen) runs the bytecode on the C VM.

4

Demarshal

The result demarshals back to a native value. (+ 1 2)3. Shen compiles Shen, which runs on Shen, on the C VM.

Reference pages

// architecture · build · primitives · playground
  • Architecture — the pipeline, the two global namespaces, and the design intent.
  • Build — make targets, the decompiler, tracing, and the self-hosting test matrix.
  • Primitives — the type-checked safe wrappers and ZINC argument convention.
  • Playground — the C VM compiled to WebAssembly, in an xterm.js terminal.