mwa

A Wasm macro assembler implemented in WAT.

Reads a WAT-like S-expression source with macros, reader macros, splices, and gensyms; emits a Wasm module. The compiler itself is written in WAT and compiled to Wasm.

example

The prelude registers reader macros so &x reads as (local.get $x) and #42 as (i32.const 42). Operator atoms like +, >>u, and, @8u, ! are aliases for the matching i32.* ops and work in both prefix and postfix position. (fun NAME (sig) body) desugars to (func ...) with name type ... -> rtype in sig. User macros compose with all of it.

(module
  (memory (export "memory") 1)
  (const $W 64)

  ;; pack 0x00BBGGRR into 0xAABBGGRR with full alpha
  (fun $pk ($c i32 -> i32)
    &c #16 >>u
    &c #0xff00 and  or
    &c #16 <<       or
    #0xff000000     or)

  ;; saturating byte add: mem[a] = clamp(mem[a] + d, 0, 255)
  (fun $b+ ($d i32 $a i32)
    (local $v i32)
    &a &a @8u &d + local.set $v
    #255 &v &v #255 > select local.set $v
    #0   &v &v #0   < select !8)

  ;; user macro: only call $b+ when cond is true
  (macro $dist (cond addr)
    `($when ,cond (call $b+ &err ,addr)))

  ;; fill row $y with packed color $c
  (fun $row ($y i32 $c i32)
    (local $x i32)
    ($for $x #0 #$W 1
      &y #$W * &x + #2 <<
      &c call $pk
      !)))

build

make           # build dist/mwa
make test      # run the test suite
make install   # install to $PREFIX (default /usr/local)

Then:

mwa < in.mwa > out.wasm