Macro breakdown · August 1, 2026
Registration by Declaration
One small macro turns annotated member functions into a construct-owned command set.
macro commandGroup(): Construct { #environment { extension #environment.target.Declaration.identity { enum Command { case invalid case #commandDeclaration.identity } } function runCommandLine(): Int { return 64 } } }}1. Mark the registrable members
command targets a Function. Its empty body is
intentional: it supplies typed annotation identity, rather than a runtime
registry or a wrapper around the function.
2. Discover the registrations
The group macro targets the enclosing Construct. Its Declaration.members query is local to that target, and filter(all: @command) retains only functions carrying the
marker. The result is a typed, ordered collection of command declarations.
3. Validate the contract
A command group with no registrations is not meaningful. Before generating
anything, the macro reports a targeted diagnostic: @commandGroup
requires at least one @command function.
4. Generate the closed command set
#environment emits an extension on the target construct.
Within it, #commands.map runs at macro time and splices one case per registered declaration into Command.
Adding @command function help() therefore adds case help; no second list can drift out of sync.
5. Dispatch is the next boundary
The generated runCommandLine() deliberately returns 64 today. It proves that the macro can generate and attach a
callable entry point, but it does not yet parse argv or invoke a registered
function. That later dispatch work builds on this registration slice rather
than changing what registration means.