Language basics
28 steps in 9 sets of WebAssembly.
WebAssembly is the fourth language of the web and the portable compile target everyone else agreed on: a stack machine with linear memory, four number types, and a sandbox that trusts nothing. Rust, C, Go, and Kotlin all compile to it; browsers, serverless edges, and plugin systems all run it. The text format — WAT — is its honest face: every s-expression here is exactly one instruction the engine executes, which makes it the rare assembly language you can read like Lisp.
This tour types the whole core: modules and exports, stack style against folded style, integer and float instructions with their signedness suffixes, locals and tee, typed if and the block/loop/br trio that builds every control structure, calls direct and indirect through tables, linear memory with data segments and bulk operations, globals and the start function, imports, and the width-crossing conversions. The Encore is three complete modules — a prime sieve, a Collatz record hunt, and a vowel tally over a data segment — each one runnable with nothing but wasmtime.
Modules
- The module shapeThe smallest WebAssembly text: one module, one exported function.
- Parameters and resultsSignatures declare everything; $names alias the argument indices.
- Stack style and folded styleThe same function twice: raw stack pushes, then nested s-expressions.
Numbers
- Integer arithmeticNo operators, only instructions — and division declares its sign.
- ComparisonsTests return an i32 — one for true, zero for false.
- Float mathf64 instructions, plus the explicit crossing from integers.
Locals & the stack
- LocalsDeclared up front, zero to start, moved with get and set.
- local.teeStore a value and keep using it, in one instruction.
- drop and selectThrow a value away, or pick between two without branching.
Control flow
- if and elseBranches are typed: a result-carrying if must fill both arms.
- block and br_ifLabels are exits: br on a block jumps past its end.
- loop and brOn a loop, br jumps to the top: that is the whole while story.
Calls
- callPrivate helpers by $name; only exports face the host.
- RecursionA function calls itself by its own $name.
- Tables and call_indirectFunction pointers: a table of funcrefs picked by runtime index.
Memory
- Linear memoryOne flat run of bytes, addressed by arithmetic you write yourself.
- Data segmentsBytes baked into memory before anything runs.
- memory.size and memory.growMemory is counted in 64 KiB pages, growable at run time.
- Bulk memoryCopy or fill whole byte runs in a single instruction.
Globals & startup
- GlobalsModule-level state; only (mut ...) globals accept writes.
- The start functionInitialization that runs before any export can be called.
- ImportsThe module states its needs; the host supplies them or no deal.
Wider types
- i64 and width changesDoubling the width is explicit in both directions.
- Conversionsdestination.op_source, signedness included — nothing is implicit.
- Multiple resultsA function may leave several values; the caller uses them in order.
Encore
- prime_sieve.watThe Sieve of Eratosthenes in linear memory: 25 primes at or below 100.
- collatz_record.watRace every Collatz chain below 100 and return the record start: 97.
- vowel_count.watWalk a passage in a data segment byte by byte and tally its vowels.