Lamb lets you inspect how a small OCaml expression is typed, lowered and represented at runtime. It prints models of Typedtree, Lambda, Clambda, Cmm and x86-64 assembly, evaluates expressions, and shows tagged values and closure environments.
There are two implementations: a JavaScript CLI with no runtime dependencies, and an OCaml CLI that also has an optimiser and a tagged bytecode machine. Both use their own parser and type inference. The printed compiler stages are educational sketches; the assembly output is not an executable binary.
Requires Node.js 20 or newer.
git clone https://github.com/rackquiem/lamb.git
cd lamb
node bin/lamb sample.mlUse npm link if you want lamb on your path. Otherwise, run node bin/lamb from the checkout.
node bin/lamb sample.ml --stage clambda
node bin/lamb examples/list.ml --run
node bin/lamb examples/option.ml --repr
printf 'let x = 20 in x + 22\n' | node bin/lamb --stage cmmRequires OCaml 5.1 or newer and Dune 3.12 or newer.
dune build
dune exec lambnative -- sample.ml --stage clambda
dune exec lambnative -- examples/list.ml --runIf your tools are installed through opam, run these commands in your switch environment, or prefix them with opam exec --.
The OCaml CLI also exposes the alpha-renamed Lambda IR, reduction passes and bytecode execution:
dune exec lambnative -- sample.ml --ir
dune exec lambnative -- sample.ml --optimize
dune exec lambnative -- examples/list.ml --bytecode
dune exec lambnative -- examples/list.ml --machineThe optimiser folds constants, simplifies branches, removes unused pure bindings, inlines small expressions and performs beta reduction. The bytecode machine executes the optimised IR after a stack verification pass. --run evaluates the source syntax; --machine executes the bytecode.
Both CLIs accept a file or standard input. With no mode selected, they print all six stages.
| Option | Output |
|---|---|
--stage source |
Source expression |
--stage typedtree |
Typed expression nodes |
--stage lambda |
Functional intermediate form |
--stage clambda |
Closures and captured environments |
--stage cmm |
Tagged arithmetic and allocation |
--stage assembly |
An x86-64 instruction sketch |
--run |
Inferred type and evaluated result |
--analyze |
Structural metrics and diagnostics |
--repr |
Result value, tagged word and allocated blocks |
--tokens |
Token stream and source offsets |
--word 42 |
Tagged integer encoding |
--list |
Available compiler stages |
Add --json for structured output from the shared inspection modes. The OCaml-only IR, optimisation and bytecode modes print text. The Node CLI supports --no-color and NO_COLOR to disable ANSI colour; the OCaml CLI prints plain text.
node bin/lamb sample.ml --stage lambda --json
node bin/lamb --word -42 --jsonInteger tagging uses (n << 1) | 1, so 42 becomes 85. The Node word inspector uses BigInt and displays the low 64 bits in hexadecimal and binary. The OCaml implementation uses Int64.
The parsers cover literals, let and let rec, anonymous functions, application, conditionals, tuples, lists, option constructors and pattern matching. Type inference supports polymorphic let bindings. The examples directory contains small programs for each of the collection and pattern forms.
let rec length values =
match values with
| [] -> 0
| value :: rest -> 1 + length rest
in
length [3; 5; 8; 13; 21]This evaluates to 5. Lamb accepts an expression subset, so it cannot compile arbitrary OCaml projects. Compilation also evaluates the expression to obtain its runtime value, even when you request only a printed stage.
npm run check
npm run program
dune runtestThe JavaScript checks cover syntax, inference, evaluation, runtime representation, analysis and the CLI. The OCaml suite also checks optimisation, bytecode execution and stack verification. CI runs JavaScript checks on Node.js 20, 22 and 24, and the native suite on OCaml 5.2.
The implementation lives in src/ and ocaml/; the CLI entry points are src/cli/index.js and ocaml/main.ml.


