Skip to content

mtc-wasm: expose the compiler IR and its Mermaid graph so the browser demo can draw the TM-1 state graph and the PM-1 CFG #116

Description

@mellonis

Follow-up to #6 / #115, surfaced while sizing a state-graph panel for the demo's TM-1 and PM-1 pages (the graph panel was left hidden for the toolchain engines in machines-demo#136; the demo-side issue is linked below).

Both compilers already have what a graph panel needs: --emit-ir writes a versioned JSON document (docs/formats.md, "IR JSON"), and IrProgram::to_mermaid() behind tmt ir graph / pmt ir graph renders it. Neither reaches the browser: Toolchain exposes build / check / format / stdlibSource and the tape-block codec, and nothing returns the IR or a diagram.

Ask

  1. Toolchain.ir(lang, source, opts): string — the same document --emit-ir writes (IR_VERSION = 4 for .pmc, TM_IR_VERSION = 3 for .tmc), for the source languages only; pma / tma have no IR and should throw the same way an unknown lang does. opts carries the optLevel of BuildOptions plus a stage: 'lowered' | 'final' matching --emit-ir=STAGE (after:<pass> can stay CLI-only). The distinction matters: lowered is the graph straight from the source — one state per state block, one row per rule — and is what a panel should show by default; final is what codegen received, which at -O1 carries tail_call / branch shapes the source never had. At -O0 the two are byte-identical (the optimizer contract in docs/tmt/optimizer.md), and the demo builds at -O0 today, so the default can be lowered without a visible difference until the demo exposes optimization levels.
  2. Toolchain.irGraph(lang, source, opts): { name: string; mermaid: string }[] — one entry per world / function, the text ir graph prints, split at the %% name headers; same opts as ir. This is the cheap first step for a consumer; the JSON form is what a consumer needs once it wants to draw its own labels (see below).

Optional, if it is cheap: the glyph tables. The IR is index-only by design; the demo can substitute glyphs itself from Program.tapes() (it already has them for the tape view), so this is not a blocker, and the pow2 rendering linked below was produced exactly that way.

What the IR documents look like at demo scale

Measured on v0.5.0 with the demo's bundled pow2.tmc: one world, 10 states, 19 rows — the raw ir graph output is readable as is, and with glyphs substituted every arrow label is the source rule verbatim (copyExp reads [1,*,*] w[␣,1,-] m[>,>,.]). Rendered: https://claude.ai/code/artifact/b6b863e2-cf9a-41d4-be4a-9109cd27453f

At docs/examples/rpnwide scale the raw form is not drawable (4,711 arrows over 14 tapes); that is a renderer question, tracked separately as the row-merging issue linked below.

Later, for a live highlight

The demo highlights the paused state on the JS pages. For TM-1 the IR's per-state and per-rule line fields plus Program.lineOf(addr) give a line-ownership mapping that is good enough for a first version. A precise mapping would be the map sidecar carrying the IR state id per address; worth a separate issue once the panel exists and the approximation shows its gaps.

Links

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions