Status: Superseded by ADR-296 — its D1-D3 are D32-D34 there
Date: September 16, 2026
Target Version: Nikaia 0.0.8
Related: ADR-007 (grammars), ADR-082 (a
grammar is entered by a call), ADR-009 (frames), Part II 10.1,
10.6, 10.7 and the new 10.8, language-review.md
§3.6
The grammar is the most original part of the language and the best-designed: scannerless, so a foreign language can be embedded; typed actions in the rule, where Ohm and pest keep them outside; commit points, so a corrupt line is an error and not a silent skip; frames, so a file can be cut blindly and parsed in parallel, which no other grammar language offers; build-time execution and a trust floor per format. None of that is in question.
What was missing is a page. The specification showed five built-in elements
and the examples used fourteen; the sentences that say how whitespace is
skipped, what WS is, what => does and what # "…" names lived in
example comments, one per file. And two of the built-ins were the engine’s
spelling for something the grammar can already say: tag("x") is "x", and
digit1 is digit+. A third thing is a wart rather than a gap: the arrow
that introduces a rule’s result type introduced its action too, on the same
line.
The conventions themselves have precedent and stay: uppercase names are
lexical as in ANTLR, WS steers skipping as pest’s WHITESPACE does, =>
is the cut, and # "…" names a rule for its failure.
An element that is not on the page is not in the language. The page is the
reference the examples’ comments were standing in for; it is normative, and
a built-in the engine offers that the page does not name is not reachable
from a .nika grammar.
rule NAME -> &str = s:until(";" | frame_end) { s }
rule pair -> Pair = key:string ":" => val:value { Pair { key, val } }
The one -> a rule writes is its result type, as a function’s is. A bare
{ after a pattern can only begin the action, because a brace delimiter
in the input is written { … } around a pattern and a brace bound starts
with an integer; the three are told apart where they stand, as 10.8 says.
Every alternative carries its own block, as before.
tag and digit1 are not spelled.A literal is "x"; one or more digits is digit+, which yields the text
it matched as every character-class repetition does. The engine’s names are
not names in a .nika grammar, and a grammar that writes one is refused
with the spelling to use.
digit1 and tag appear in none of them.dec[i64].examples/ and the specification’s
own grammar blocks.token NAME), a skip
declaration in place of the WS rule, or any change to => and # "…".
Each has precedent and stays.hex_digit1, oct_digit1,
binary_digit1, space0, space1, count, peek, lex, spaced):
reachable the day a program needs one and a line is added to the page.Nothing. Grammars write -> { … } for the action, and the vocabulary is the
engine’s. The order of work:
tag and digit1 refused with theirs;examples/.#202 carries it.