Expand description
Emitting Go parse tables from a spec.
The Go side of usage has no derive macro to emit its tables, because Go has no
macros: what a Rust CLI gets from #[derive(Cli)] at compile time, a Go CLI
gets from this, at build time, through go:generate. The output is a plain Go
file an author checks in and a reviewer can read.
§What it emits, and what it does not
Two tables, kept apart on purpose. The hot one is what binding reads: which
token becomes which flag or argument, and nothing else. The cold one — Meta —
carries what the rules decided after the last token need: required,
choices, default, env, the var bounds, and the four that compare one
entry against another. A parse never touches the second.
Help text is in neither. mise’s runs to several hundred kilobytes, and a table carrying it would put all of that in front of the parser; rendering help is its own cold table and its own piece of work.
§Why package-level var and not const
Go has no const for composite data. What it does have is a linker that
statically initializes package-level variables holding plain data, which is
the property the whole design rests on: go tool nm reports these symbols as
type D, and the generated package has no init function. So a 211-command
table costs bytes in the binary and no instructions at startup — the thing
cobra and kong each pay a million or more for.
Commands are emitted as separate variables rather than one nested literal
because default_subcommand has to point at a node inside the tree, and a
composite literal cannot refer to its own interior.
Structs§
- GoOptions
- How to emit.
Functions§
- generate
- Turn a spec into a Go source file declaring its parse tables.
- is_
valid_ package - Whether a string can be written after
packageand then imported.