Ichor.Conformance (Ichor v0.7.2)

Copy Markdown View Source

This implementation's answers to the Ichor Conformance Suite, through either backend.

The suite runs every Ichor implementation against the same grammars and inputs, reaching each one through an adapter (mix ichor.conformance here) with a JSON request, and reading a JSON answer back:

%{"cases" => [%{"id" => "trees: one number", "operation" => "parse",
                "grammar" => "/abs/calculator.aether", "text" => "2"}]}
#=> %{"results" => [%{"id" => "trees: one number", "tree" => ...}]}

A grammar may be written in any notation Ichor reads -- Aether, ABNF, BNF, ISO EBNF, PEG -- told by its extension or an @style line, exactly as mix ichor.gen tells it (Ichor.GrammarImport.styled/2). What the suite compares is the parse, so the same language written twice must come to the same tree.

It lives here, not in ichor_runtime, because the runtime is only ever called by generated code: to answer a case, a parser has to be made from the case's grammar first, and making one is Ichor's.

The backend is the implementation. :interpreted runs the grammar through Grammar.VM, Grammar.LR or Grammar.GLR, by its engine; :compiled generates a module with Ichor.generate_from_grammar/2 and runs that. The suite configures each as an implementation of its own, which is what checks that the two agree.

A "render" answers "rendered", the first error exactly as Ichor.Error.format/1 writes it for a person -- location, message, the source line and a caret -- or "tree" when the text parses. Word for word: what a person reading an error is given is output, and every implementation gives the same.

"pratt", "unify", "solve" and "walk" hold the toolkits to their cases, through the same standard callbacks every adapter supplies (Ichor.Conformance.Toolkits).

A "tokens" answers "tokens", the grammar's token stream for the text -- every token in order, trivia included, @keywords applied, as {name, text, line, column}, an inline literal's token named nil -- or "error", the lexer error's stage, line and column.

A "lossless" answers "tree", the lossless tree of the text (Ichor.Syntax) -- a node as {:rule, name, offset, size, line, column, children}, a token as {:token, name, text, trivia, offset, line, column}, an inline literal's token named nil -- or "error", as a "parse" does. Every field is one an implementation computes, so the offsets are held to the cases as the structure is.

A "parse" answers one of:

  • "tree" -- the default tree, what the parse comes to with no actions of its own: a token is its text, a rule with exactly one capture matched once is that capture's value, and any other rule is {:node, rule, captures}, its captures a map from name to value;
  • "error" -- %{stage: ..., line: ..., column: ...} of the first error, from reading the grammar, analysing it, or parsing the text.

Both travel as the suite's typed JSON ({"keyword": "node"}, {"integer": "1"}, {"tuple": [...]}, {"map": [[k, v], ...]}), so nothing tells two values apart differently here than in Praxis.

Summary

Types

Which of this implementation's two backends answers.

Functions

The answer to request through backend, one result per case, in order.

Types

backend()

@type backend() :: :interpreted | :compiled

Which of this implementation's two backends answers.

Functions

answer(map, backend)

@spec answer(map(), backend()) :: map()

The answer to request through backend, one result per case, in order.