formawasm compiles a formalang Intermediate Representation (IR) module into a WebAssembly component — a .wasm binary that any standards-compliant runtime can execute.
formalang frontend ──► IrModule ──► formawasm ──► .wasm component ──► host runtime
formawasm is a backend: it doesn't parse .fv source files itself, and it doesn't run the resulting wasm. Both jobs belong to other libraries (formalang for parsing, wasmtime / wasmi / a browser engine for execution). formawasm only emits bytes.
The boundary between a component and its host is described in WIT — the small Interface Definition Language of the Component Model. formawasm generates the WIT file automatically from the public surface of each IR module; the host never hand-writes WIT.
Install the CLI:
cargo install formawasmOr pin to a specific version:
cargo install formawasm --version 0.0.1-betaCompile a .fv source file:
echo 'pub fn id(x: I32) -> I32 { x }' > id.fv
formawasm id.fv
# wrote id.wasm (… bytes) from id.fvInspect the generated WIT interface:
wasm-tools component wit id.wasmpackage formawasm:generated;
world component {
export id: func(x: s32) -> s32;
}Run it directly with the wasmtime CLI — no host code required:
wasmtime run --invoke 'id(42)' id.wasm
# 42Or wire it into your Rust application:
use wasmtime::{Config, Engine, Store};
use wasmtime::component::{Component, Linker};
let mut config = Config::new();
config.wasm_component_model(true);
let engine = Engine::new(&config)?;
let bytes = std::fs::read("id.wasm")?;
let component = Component::from_binary(&engine, &bytes)?;
let linker = Linker::<()>::new(&engine);
let mut store = Store::new(&engine, ());
let instance = linker.instantiate(&mut store, &component)?;
let id = instance.get_typed_func::<(i32,), (i32,)>(&mut store, "id")?;
let (got,) = id.call(&mut store, (42,))?;
assert_eq!(got, 42);The full book lives at docs/ and is built with mdBook:
mdbook serve # local dev server with live reloadHighlights:
For users (embedding formawasm in a Rust application):
- Quickstart —
.fv→.wasmin 30 seconds - Using the Library —
WasmBackendfrom your own crate - Hosting a Component — running components under wasmtime
- Boundary Policy — what can cross the WIT boundary
- Type Mapping — formalang ↔ WIT
- Feature Coverage — what's supported, per IR variant
- Cargo Features —
wasm-opt,dwarf, validation - Troubleshooting — common errors
For contributors (extending the backend):
- Architecture — the seven-stage pipeline
- Crate Layout — what's in
src/ - Lowering — memory model, runtime helpers, per-IrExpr lowering
- Extending the Backend — adding IR variants, runtime helpers, layouts
- Testing — test conventions and milestone tests
- Contributing — code style, quality gates, microcommit cadence
Phases 1 through 5 are closed. The backend produces a Component-Model artifact for every milestone — recursive functions (fib), structs + enums + methods (Counter / Action), arrays + ranges + for-loops (sieve of Eratosthenes), strings + optionals + dictionaries (greet), virtual dispatch (Greet trait across two impls), and host-provided externs (call_host(21) → 42 via host_double).
See CHANGELOG.md for the phase-by-phase history; the "Roadmap" section at the top captures what's left.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
