Fork channel

Create a new channel as a copy of main.

Rename channel

Rename main to:

Delete channel

Delete main? This cannot be undone.

mode name
drwxr-xr-x src/
drwxr-xr-x test_data/
drwxr-xr-x wa_embedder_ex/
-rw-r--r-- .ignore
-rw-r--r-- Makefile
-rw-r--r-- README.md
-rw-r--r-- UNLICENSE
-rw-r--r-- flake.lock
-rw-r--r-- flake.nix
-rw-r--r-- rebar.config
-rw-r--r-- rebar.lock
README

wa_embedder

A WebAssembly-to-BEAM compiler for the Erlang ecosystem, written in Erlang. It parses a .wasm binary (via wa_parser), translates each function to Erlang abstract format, and compiles and loads the result as a native BEAM module that you can call directly.

This is the Erlang package. Elixir projects can depend on it directly, or use the companion wa_embedder_ex package for an idiomatic Elixir API (WaEmbedder.compile/1..4 + WaEmbedder.ImportError).

Repository layout (monorepo)

Two hex packages live in this repository:

PathPackageToolRole
repo rootwa_embedderrebar3The compiler core (pure Erlang)
wa_embedder_ex/wa_embedder_exmixThin Elixir wrapper + the test suite
test_data/cmakeShared WAT/C .wasm fixtures

The dependency direction is one-way: wa_embedder_ex (Elixir) → wa_embedder (Erlang) → wa_parser (Erlang). The core has no Elixir dependency.

Installation (rebar3)

%% rebar.config
{deps, [{wa_embedder, "~> 0.1"}]}.

Usage

{module, Mod} = wa_embedder:compile("module.wasm"),
Result = Mod:some_exported_fun(Arg).

compile/1,2,3,4 compiles and loads the module and returns the code:load_binary/3 result ({module, ModuleName} on success). Modules with imports take an imports map resolving each WASM import to an Erlang target (MFA tuple, external fun, or closure); unsatisfiable imports raise erlang:error({import_error, Map}).

Development

A nix develop shell provides erlang, elixir, rebar3, and the fixture toolchain (cmake, ninja, wabt, binaryen). Dependencies default to their published hex releases:

  • Core → parser (side repo): the core depends on the published {wa_parser, "~> 0.1"} hex package; rebar3 fetches it from hex. To develop against a sibling ../wa_parser checkout instead, opt in manually with a rebar3 checkout (mkdir -p _checkouts && ln -sfn ../../wa_parser _checkouts/wa_parser); a checkout takes precedence over the hex dep. Nothing wires it for you (remove it before packaging).
  • Wrapper → core (in-repo): the wrapper depends on the published {:wa_embedder, "~> 0.1"} hex package by default. To build against the Erlang core at the repo root instead, opt in manually by exporting WA_EMBEDDER_PATH=.. before mix (e.g. WA_EMBEDDER_PATH=.. mix test).

Build and test

# Erlang core (repo root) — uses the published wa_parser hex dep
rebar3 compile

# Elixir wrapper + full fixture suite (in wa_embedder_ex/).
# The core is not on hex yet, so build the wrapper against the in-repo core:
cd wa_embedder_ex && WA_EMBEDDER_PATH=.. mix test

The test suite lives in wa_embedder_ex/test/ and compiles the WAT/C fixtures under the repo-root test_data/ (built by CMake/Ninja before the suite runs). Once wa_embedder is published, mix test works without WA_EMBEDDER_PATH.

Building the fixtures manually

cd test_data
cmake -B build -G Ninja
ninja -C build            # WAT fixtures (default); `ninja -C build c_fixtures` for the C chain

Packaging

# Core: uses the published {wa_parser, "~> 0.1"} dep. (If you added a manual
# _checkouts override for parser dev, remove it first: rm -rf _checkouts.)
rebar3 hex build            # or: make package

# Wrapper: unset WA_EMBEDDER_PATH so the {:wa_embedder, "~> 0.1"} hex dep is used
cd wa_embedder_ex && env -u WA_EMBEDDER_PATH mix hex.build   # or: make package

Publish order: publish wa_embedder (core) first, then wa_embedder_ex (the wrapper’s hex dep on the core cannot resolve until the core is on hex).

License

Released into the public domain under the Unlicense.