GoForge — Build | Test | Ship | Collaborate GoForge — Build | Test | Ship | Collaborate
v1.0.0

Brigadier

The command tree, as the GADT it is

$ go get goforge.dev/gbrigadier@v1.0.0

Released — v1.0.0. goforge.dev/gbrigadier is a Go+ reimplementation of Mojang/brigadier — the command parser and dispatcher behind Minecraft — at feature parity across all 44 classes, consuming std/parsec for its scanning core. Install with go get goforge.dev/gbrigadier@v1.0.0.

GoForge Brigadier targets Mojang/brigadier (majorMinor 1.3, pinned at commit 9ba4f13). It registers, parses, executes, and suggests completions for tree- structured commands, generic over a caller-defined source type S.

Parity

Verified against brigadier’s own JUnit suite, ported to Go: 170 test functions pass — reader, all six argument types, the command tree, builders, context, the full dispatcher (execute / parse / redirect / fork / usage / ambiguities), and suggestions — race-, vet-, and goplus gen -check clean.

One documented ledger (a formatting divergence, not a semantic gap): legacy Java’s non-shortest Float.toString spells the Integer.MIN_VALUE float bound -2.14748365E9 where Go/Ryū emits the shortest round-tripping decimal -2.1474836E9; both parse back to the identical float32. Every other toString is byte-identical.

The command tree is a GADT

brigadier’s command tree is a genuine GADT, and this rewrite models it as one — the reason it was chosen to exercise Go+’s GADT and dependent machinery. ArgumentType[T] indexes the value a node parses; ArgumentCommandNode[S, T] keeps T yet satisfies the non-generic CommandNode[S] interface, so T erases exactly at brigadier’s ArgumentCommandNode<S, ?> boundary — no manual boxing. The context holds a heterogeneous, string-keyed bag of parsed arguments, and GetArgument[T](ctx, name) recovers the value type-safely — the dependent retrieval Java performs with an unchecked cast.

Go+’s existing GADT/dependent machinery carried the whole design — the generic-over-S tree, the T-erasure, and the typed retrieval all generate and type-check with no compiler extension required. brigadier is thus a validation that the machinery holds up on a real, industrial GADT, not a toy.

std/parsec, load-bearing

StringReader’s character-run scans — numbers, unquoted strings, whitespace — run through parsec.TakeWhile, turning brigadier’s imperative while canRead && pred loops into single combinator applications. The parser core does real work rather than standing in as decoration.

Faithful adaptations

Everything is generic over S, as upstream. Java checked CommandSyntaxException becomes Go (T, error) with pointer-identity exception singletons so error-type comparison matches. CompletableFuture<Suggestions> becomes a synchronous *Suggestions (all upstream providers are synchronous). And Suggestions.create’s sort reproduces the JDK’s TimSort binary-insertion path so brigadier’s inconsistent-comparator ordering of mixed integer/string suggestions is byte-identical.

Provenance

Upstream: Mojang/brigadier, MIT (© Microsoft). Independent Go+ implementation, not vendored source; .upstream/COMMIT pins the exact upstream commit parity was verified against.