Skip to content

Add Morphir interpreter as WebAssembly Component Model component#1272

Closed
DamianReeves wants to merge 13 commits intoremixedfrom
feature/wasm-interpreter
Closed

Add Morphir interpreter as WebAssembly Component Model component#1272
DamianReeves wants to merge 13 commits intoremixedfrom
feature/wasm-interpreter

Conversation

@DamianReeves
Copy link
Copy Markdown
Member

Summary

Exposes the Morphir interpreter as a WebAssembly Component Model component using ComponentizeJS. This enables embedding Morphir evaluation in any runtime that supports the Component Model standard — Rust, Go, Python, .NET, and browsers — without rewriting the interpreter.

New package: @morphir/interpreter-wasm (packages/morphir-interpreter-wasm/)

WIT Interface

Defines morphir:interpreter with:

  • eval.evaluate — stateless one-shot evaluation (IR JSON + typed FQName + typed args)
  • types.ir-store — stateful resource: load IR once, evaluate many times, reload to replace IR
  • morphir-value — index-based flat tree representation (workaround for WIT's lack of recursive types). Covers all Morphir value types: bool, int, float, string, decimal, char, list, tuple, record, constructor, unit
  • eval-error — structured error variants: invalid-ir, reference-not-found, argument-error, pattern-mismatch, type-error, variable-not-found, other
  • fq-name — fully qualified name with package-path, module-path, local-name

Architecture

  1. Elm interpreter compiled to JS (reuses 100% of existing code)
  2. JS glue layer converts between WIT typed values and Morphir IR JSON
  3. jco componentize wraps JS+SpiderMonkey into a WASM component
  4. jco transpile produces browser-compatible ESM output

Files

  • packages/morphir-interpreter-wasm/wit/interpreter.wit — WIT interface definition
  • packages/morphir-interpreter-wasm/src/Morphir/Interpreter/Worker.elm — Elm port module entry point
  • packages/morphir-interpreter-wasm/src/interpreter.js — JS glue with value conversion
  • .mise/tasks/build/interpreter-{elm,wasm,browser}.ts — build tasks
  • .mise/tasks/test/interpreter-wasm.ts — test task
  • docs/plans/2026-02-25-wasm-interpreter-{design,plan}.md — design & implementation docs

Test plan

  • 11 integration tests passing (one-shot eval, stateful store, reload, error cases)
  • 864 existing Elm unit tests passing (no regression)
  • WASM component builds and exports correct interfaces
  • Browser transpilation produces valid ESM
  • CI passes

Design for exposing the Morphir interpreter as a WebAssembly Component
Model component using ComponentizeJS. Defines WIT interface with
stateless evaluation and stateful ir-store resource.
10 bite-sized tasks covering package scaffolding, WIT definition,
Elm entry point, JS glue, mise build tasks, test fixture, integration
tests, and validation.
Replace JSON string args/returns with index-based flat morphir-value
tree (workaround for WIT's lack of recursive types). Add fq-name
record, eval-error variant. Update implementation plan with conversion
layer in JS glue and typed integration tests.
Implements the bridge between WIT component exports and the Elm Worker:
- morphirValueToJson/jsonToMorphirValue: convert between WIT flat indexed
  tree and nested Elm IR Value codec JSON format
- fqName conversion between WIT record and Elm codec/Worker formats
- Elm app management with synchronous port communication
- WIT eval_.evaluate for stateless evaluation
- WIT types.IrStore resource class with constructor, uri, evaluate, reload
- Result/error mapping between Elm Worker JSON and WIT eval-error variant
Fix three issues preventing jco componentize from building the WASM component:

1. Fix jco CLI flag: --output -> -o (jco uses short flag)
2. Fix eval export: jco expects `export { eval_ as eval }` since "eval" is
   a JS reserved word but the WIT interface name
3. Bundle Elm IIFE output into single ESM file: Elm compiles to an IIFE
   wrapping `(function(scope){...}(this))` which isn't ESM. The build task
   now reads the Elm output, replaces `this` with a scope object, and
   concatenates it with the JS glue into a single ESM bundle.
4. Break up deeply nested && chains: Elm's compiler generates pattern match
   conditions with 100+ levels of parenthesis nesting. SpiderMonkey's JS
   engine (used by ComponentizeJS) has a ~50-frame recursion limit for
   expression parsing. The build task post-processes the Elm output to
   flatten these into sequential `var _c = a; _c = _c && b; ...` checks.
Test the interpreter bundle's eval.evaluate (stateless) and types.IrStore
(stateful) interfaces with 11 test cases covering addInts, isPositive,
error handling for unknown functions and invalid IR, store URI management,
reload, and repeated evaluation.

Also patch _Process_sleep(0) in the build script to be synchronous, which
is needed to test the Elm port communication outside the WASM runtime
(where setTimeout is inherently sync in StarlingMonkey).
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@DamianReeves DamianReeves changed the base branch from main to remixed February 25, 2026 11:18
@DamianReeves DamianReeves deleted the branch remixed February 25, 2026 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant