Tptp.Bnf.Oracle (Tptp v0.1.0)

Copy Markdown View Source

Renders Tptp.Bnf.OracleTable, the regex transcription of the BNF's token layer.

mix tptp.gen invokes this; nothing calls it at runtime. The output is written to test/support/, its purpose being to provide an independent check on the lexer.

Rationale

Tptp.Lexer is the only hand-written stage in this library. Every other stage is derived from the BNF, so an error appears as a compilation failure or a coverage gap. A lexer accepting 1. as a real, or terminating a <sq_char> one byte early, instead produces a plausible token stream and an incorrect parse.

The BNF's ::- and ::: rules are already regular expressions, with <name> references in place of sub-patterns, so transcribing them mechanically is inexpensive and gives a property test an independent basis for comparison.

It is an oracle, not an implementation. It anchors and matches one token at a time; it does not scan, has no notion of maximal munch, and is far too slow for the hot path. Where the two disagree the BNF is right and the lexer is wrong — unless the disagreement is one of the deliberate deviations Tptp.Lexer documents, in which case the test names it.

The transcription

Each rule's right-hand side is regex syntax already. Every <name> is replaced by that rule's pattern wrapped in a non-capturing group, recursively; the references form a DAG with no cycles, so the substitution terminates. Octal escapes such as \40 mean the same thing to PCRE as they do to the BNF, and are passed through untouched rather than reinterpreted.

Summary

Functions

The resolved pattern for every ::- and ::: rule, keyed by nonterminal name.

Render the oracle module, and say how many patterns it holds.

Functions

patterns(bnf_path)

@spec patterns(Path.t()) :: %{required(binary()) => binary()}

The resolved pattern for every ::- and ::: rule, keyed by nonterminal name.

iex> patterns = Tptp.Bnf.Oracle.patterns(Tptp.Bnf.vendored_path!())
iex> patterns["lower_alpha"]
"[a-z]"
iex> patterns["lower_word"]
"(?:[a-z])(?:((?:[a-z])|(?:[A-Z])|(?:[0-9])|(?:[_])))*"

table(bnf_path)

@spec table(Path.t()) :: {binary(), non_neg_integer()}

Render the oracle module, and say how many patterns it holds.