watgo – en WebAssembly Toolkit för Go
Jag är glad att kunna meddela den allmänna tillgängligheten av watgo – den WebAsammansättning Toolkit för Go. Detta projekt liknar wabt (C++) eller wasm-tools (Rust), men i ren, noll-beroende Go.
watgo kommer med en CLI och en Go API för att analysera WAT (WebAssembly Text), validera den och koda den till WASM-binärer; den stöder också avkodning av WASM från dess binära format.
I centrum för allt är wasmir – en semantisk representation av en WebAssembly-modul som användare kan granska (och manipulera). Detta diagram visar funktionerna som tillhandahålls av watgo:

- Parse: en parser från WAT till wasmir
- Validera: använder den officiella WebAssembly-valideringssemantiken för att kontrollera att modulen är välformad och säker
- Koda: avger wasmir in i WASM binär representation
- Avkoda: läs in WASM binär representation wasmir
Användningsfall för CLI
watgo kommer med en CLI, som du kan installera genom att utfärda detta kommando:
go install github.com/eliben/watgo/cmd/watgo@latest
CLI syftar till att vara kompatibel med wasm-tools , och jag har redan bytt ut mina wasm-wat-samples-projekt för att använda den; t.ex. ett kommando för att analysera en WAT-fil, validera den och koda den till binärt format:
watgo parse stack.wat -o stack.wasm
API-användningsfall
wasmir representerar semantiskt en WASM-modul med ett API som är lätt att arbeta med. Här är ett exempel på hur man använder watgo för att analysera ett enkelt WAT-program och göra lite analys:
package main
import (
"fmt"
"github.com/eliben/watgo"
"github.com/eliben/watgo/wasmir"
)
const wasmText = `
(module
(func (export "add") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add
)
(func (param f32 i32) (result i32)
local.get 1
i32.const 1
i32.add
drop
i32.const 0
)
)`
func main() {
m, err := watgo.ParseWAT(()byte(wasmText))
if err != nil {
panic(err)
}
i32Params := 0
localGets := 0
i32Adds := 0
// Module-defined functions carry a type index into m.Types. The function
// body itself is a flat sequence of wasmir.Instruction values.
for _, fn := range m.Funcs {
sig := m.Types(fn.TypeIdx)
for _, param := range sig.Params {
if param.Kind == wasmir.ValueKindI32 {
i32Params++
}
}
for _, instr := range fn.Body {
switch instr.Kind {
case wasmir.InstrLocalGet:
localGets++
case wasmir.InstrI32Add:
i32Adds++
}
}
}
fmt.Printf("module-defined funcs: %d\n", len(m.Funcs))
fmt.Printf("i32 params: %d\n", i32Params)
fmt.Printf("local.get instructions: %d\n", localGets)
fmt.Printf("i32.add instructions: %d\n", i32Adds)
}
En viktig anmärkning: WAT-formatet stöder flera syntaktiska finesser som plattas ut/kanoniseras när de sänks till wasmir. Till exempel sänks alla vikta instruktioner till ovikta (linjär form), funktions- och typnamn löses till numeriska index, etc. Detta matchar validerings- och exekveringssemantiken för WASM och dess binära representation.
Dessa syntaktiska detaljer finns i watgo i textformat paket (som analyserar WAT till en AST) och tas bort när detta sänks till wasmir. De textformat Paketet hålls internt för närvarande, men i framtiden kan jag överväga att exponera det offentligt – om det finns intresse.
Testa strategi
Även om det fortfarande är tidiga dagar för watgo, är jag ganska säker på dess riktighet på grund av en strategi med mycket tunga tester redan från början.
WebAssembly kommer med en stor officiell testsvit, som är perfekt för end-to-end-testning av nya implementeringar. Kärntestsviten innehåller nästan 200 000 rader WAT-filer som innehåller flera moduler med förväntad exekveringssemantik och en mängd olika felscenarier. Dessa lever i specialdesignade .wast-filer och använder en anpassad spec-tolk.
watgo kapar detta tillvägagångssätt genom att använda den officiella testsviten för sina egna tester. En anpassad sele analyserar .wast-filer och använder watgo för att konvertera WAT i dem till binär WASM, som sedan exekveras av Node.js ; denna sele är en betydande ansträngning i sig, men det är mycket värt det – resultatet är utmärkt testtäckning. watgo klarar hela WASM spec core test suite.
På samma sätt utnyttjar vi wabts interp-testsvit som också inkluderar end-to-end-tester, med en enklare nodbaserad sele för att testa dem mot watgo.
Slutligen upprätthåller jag en samling realistiska programexempel skrivna i WAT i wasm-wat-samples repository; dessa används också av watgo för att testa sig själv.
