Write WebAssembly Code Directly by Hand Using WAT

Yes, you can write WebAssembly (Wasm) code directly by hand using its official textual representation, known as WebAssembly Text Format (WAT). This article provides a practical introduction to writing WAT by hand, understanding its S-expression-based syntax, and compiling it into the binary .wasm format that browsers and runtimes can execute.

What is WebAssembly Text Format (WAT)?

While WebAssembly is binary-based for fast loading and execution, the creators of Wasm designed a 1:1 text representation called WAT. WAT uses S-expressions (symbolic expressions, characterized by nested parentheses) to represent the abstract syntax tree of the WebAssembly module. This format is fully human-readable and can be written in any standard text editor.

Writing Your First WAT File

To write Wasm by hand, you define a module, functions, parameters, and operations. Below is a simple WAT example that takes two integers, adds them together, and returns the result.

(module
  (func $add (param $p1 i32) (param $p2 i32) (result i32)
    local.get $p1
    local.get $p2
    i32.add
  )
  (export "add" (func $add))
)

Breaking Down the Syntax

Compiling WAT to WASM

Computers cannot run WAT directly; it must be compiled into binary Wasm. The industry-standard tool for this conversion is wat2wasm, which is part of the WebAssembly Binary Toolkit (WABT).

To compile your WAT file via the command line:

wat2wasm math.wat -o math.wasm

This command generates a highly optimized math.wasm binary file.

Running Your Hand-Written Wasm in JavaScript

Once compiled, you can load and run your hand-written WebAssembly module inside a web browser or Node.js environment using the native WebAssembly API.

// Fetch and instantiate the compiled .wasm file
WebAssembly.instantiateStreaming(fetch('math.wasm'))
  .then(obj => {
    // Call the exported 'add' function
    const result = obj.instance.exports.add(15, 27);
    console.log(result); // Outputs: 42
  });

Writing WebAssembly by hand using WAT is an excellent way to understand how the stack-based architecture of Wasm works, optimize performance-critical algorithms at the lowest level, or build custom compilers.