Expand description
ABNF grammars as a testing oracle.
Parses ABNF grammars (RFC 5234 as amended by RFC 7405 and Errata 2968 and 3076), decides whether an input string is in the language of a rule, and generates strings that are.
The emphasis is on being right, not fast. Alternation is unordered, backtracking is full,
ambiguity is tolerated, and the recognizer computes the set of all end positions an element
can reach rather than committing to the first branch that matches. What this crate is
deliberately not is listed in SCOPE.md 3: no parse trees, no ambiguity detection, no
PEG or regex semantics, no byte-oriented matching, and no performance promises.
§Shape of the API
Three types, used in order:
Grammar— the syntactic layer. What the parser produces: definitions as written.CheckedGrammar— the semantic layer, produced byGrammar::check. Incremental alternatives are merged, names are resolved, and the analyses the recognizer and generator rely on have been run. It is the only route to either of them, so there is no way to recognize against a grammar whose structure was never validated.Recognizer/Generator— bound to a checked grammar and a start rule.
§Example
use abnf_oracle::{Generator, Grammar, Recognizer};
// A grammar, as it would appear in an RFC.
let source = concat!(
"full-date = date-fullyear \"-\" date-month \"-\" date-mday\r\n",
"date-fullyear = 4DIGIT\r\n",
"date-month = 2DIGIT\r\n",
"date-mday = 2DIGIT\r\n",
);
// Parse, then check. `check` merges incremental definitions, resolves every name and runs
// the analyses; it is the only way to reach a recognizer or a generator.
let grammar = Grammar::parse(source)
.expect("valid ABNF")
.check()
.expect("no structural errors");
// Recognize.
assert!(Recognizer::new(&grammar, "2026-09-20").accepts("full-date").unwrap());
assert!(!Recognizer::new(&grammar, "20260920").accepts("full-date").unwrap());
// Generate. The same seed always gives the same string.
let mut generator = Generator::new(&grammar, 42);
let produced = generator.generate("full-date").expect("generates");
// What the generator produces, the recognizer accepts.
assert!(Recognizer::new(&grammar, &produced).accepts("full-date").unwrap());§Errors are not rejections
A limit, a prose value or an unrepresentable terminal makes a question unanswerable, which
is different from answering “no”. Every such case is an Err, never Ok(false), so a
caller can never mistake “could not decide” for “does not match”.
Structs§
- CharVal
- A quoted string terminal:
char-valin RFC 5234 4. - Check
Errors - Every structural problem found by
crate::Grammar::check, in the order found. - Checked
Grammar - A grammar that passed structural validation.
- Definition
- One
name = elementsorname =/ elementsdefinition, as written. - GenOptions
- How to generate.
- Generator
- Generates strings that a rule accepts.
- Grammar
- A parsed grammar: the ordered definitions as written, after local rewrites only.
- Ignored
- A value that is carried but never compared: every
Ignored<T>equals every other. - Match
Options - Resource limits for recognition.
- NodeId
- An index into a checked grammar’s node arena.
- Parse
Options - Syntactic options for parsing. Never semantic (SCOPE.md 4, D30).
- Recognizer
- Decides whether an input is in the language of a rule.
- Repeat
- Repetition bounds, inclusive on both ends.
- Rule
- A rule in the merged table:
=/folded into its base, body lowered into the arena. - Rule
Name - A rule name.
- Span
- A byte range in the grammar source text.
Enums§
- Check
Error - A structural problem: the grammar cannot be used at all.
- Defined
As - Which definition operator introduced a
Definition:defined-asin RFC 5234 4. - Element
- An element of a rule body, in the syntactic layer.
- GenError
- Generation could not be attempted, or could not be finished.
- Lint
Warning - An advisory warning. Never fails
check(D5). - Match
Error - Recognition could not be attempted, or could not be finished.
- MinLen
- The length of the shortest string a node can match (SCOPE.md 6.4, D27).
- Node
- A node in the merged-grammar arena.
- NumVal
- A numeric terminal, in any of the three radices. The radix is not retained:
%d65,%b1000001and%x41all parse to the same node and print as%x41(SCOPE.md 6.7, D37). - Parse
Error - The grammar text could not be parsed.
- RuleId
- Identifies a rule in the merged table, distinguishing user rules from the implicit core-rule environment.
- Witness
- The choice a node’s shortest derivation makes (SCOPE.md 6.4, D28).
Constants§
- DEFAULT_
GEN_ DEPTH - How deep the walk may recurse before it starts following witnesses.
- DEFAULT_
MAX_ DEPTH - How deep the recognizer may recurse before giving up:
MatchOptions::max_depth’s default. - DEFAULT_
MAX_ OUTPUT_ LEN - How long a generated string may get before generation gives up.
- DEFAULT_
MAX_ STEPS - How many nodes the walk may visit before it gives up.
- DEFAULT_
SPREAD - How many extra repetitions a repetition may take beyond its minimum.