Packages

Run WebAssembly from Elixir. Load WASM modules in Rust, Go, C — call them like native functions.

Current section

Files

Jump to
firebird lib firebird sigils.ex
Raw

lib/firebird/sigils.ex

defmodule Firebird.Sigils do
@moduledoc """
Macros for inline WebAssembly in Elixir.
Import this module to use `wat!/1` for compile-time WAT compilation,
or `wat/1` for runtime compilation.
## Usage
import Firebird.Sigils
# Compile WAT to WASM bytes at compile time
wasm_bytes = wat!(\"""
(module
(func (export "add") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
\""")
{:ok, instance} = Firebird.load(wasm_bytes)
{:ok, [8]} = Firebird.call(instance, :add, [5, 3])
The `wat!/1` macro compiles WAT source to WASM binary bytes at compile
time. It requires `wat2wasm` to be installed (part of the WABT toolkit).
Install WABT:
- macOS: `brew install wabt`
- Ubuntu: `apt install wabt`
- Or download from: https://github.com/WebAssembly/wabt/releases
"""
@doc """
Compile WAT source to WASM bytes at compile time.
This macro runs `wat2wasm` during compilation and embeds the resulting
WASM binary directly in your module's bytecode. Zero runtime overhead.
## Examples
import Firebird.Sigils
bytes = wat!(\"""
(module
(func (export "double") (param i32) (result i32)
local.get 0
i32.const 2
i32.mul))
\""")
{:ok, wasm} = Firebird.load(bytes)
{:ok, [10]} = Firebird.call(wasm, :double, [5])
"""
defmacro wat!(wat_source) do
wat_string =
case Macro.expand(wat_source, __CALLER__) do
s when is_binary(s) ->
s
_ ->
{result, _} = Code.eval_quoted(wat_source, [], __CALLER__)
result
end
case compile_wat_to_bytes(wat_string) do
{:ok, bytes} ->
Macro.escape(bytes)
{:error, {:wat2wasm_not_found, _}} ->
raise CompileError,
description: """
wat2wasm not found. Install WABT:
• macOS: brew install wabt
• Ubuntu: apt install wabt
• https://github.com/WebAssembly/wabt/releases
"""
{:error, {:wat_compile_error, msg}} ->
raise CompileError,
description: "WAT compilation failed:\n#{msg}"
end
end
@doc """
Compile WAT source to WASM bytes at runtime.
Unlike `wat!/1`, this compiles at runtime. Useful for dynamic WAT generation.
## Examples
import Firebird.Sigils
{:ok, bytes} = wat("(module)")
{:ok, instance} = Firebird.load(bytes)
"""
def wat(source) do
Firebird.compile_wat(source)
end
@doc false
def compile_wat_to_bytes(wat_source) do
Firebird.compile_wat(wat_source)
end
end