IchorRuntime
The small runtime support library Ichor-generated
parsers call into, plus a handful of standalone toolkit modules useful to
any engine you build on top of one. Every parser mix ichor.gen writes
to disk, and every module use Ichor, grammar: ..., actions: ...
splices code into, resolves a handful of module names at runtime --
Ichor.Actions, Ichor.Error, the compiled Tokenizer/Parser
combinators, Grammar.VM.Token, and (for @engine lr/glr grammars)
the LR/GLR shift-reduce and GSS runtime. This package is exactly that
set, plus Ichor.Toolkit.Pratt, Ichor.Toolkit.TermWalk, and
Ichor.Backtrack -- three self-contained pieces a generated parser's
own @native(...) callbacks (or an engine built on top of one) commonly
need at every match/evaluation, not just once at grammar-generation
time.
Ichor itself -- the Aether grammar
language, its ABNF/BNF/EBNF/PEG importers, Grammar.Analysis, the
LR/GLR table builder, and both codegen backends -- never runs after a
grammar's been compiled. Splitting it out this way means a project that
only ever runs mix ichor.gen ahead of time can depend on
ichor_runtime as an ordinary dependency, and on ichor itself as
only: :dev, runtime: false -- the bulk of the library (grammar
parsing, analysis, and codegen) genuinely never ships to production,
including in a mix release build.
Installation
def deps do
[
{:ichor_runtime, "~> 0.1.0"},
{:ichor, "~> 0.2.0", only: :dev, runtime: false}
]
end
A project that instead loads/compiles grammars at runtime (via
Grammar.VM, Grammar.LR, or Grammar.GLR, rather than pregenerated
code) still needs the full ichor package as a normal dependency --
ichor_runtime is a piece Ichor's own interpreted backends depend on
too, not a replacement for it. In that case, just depend on ichor;
ichor_runtime comes along transitively.
What's in here
- Capture dispatch (
Ichor.Actions,Ichor.Capture,Ichor.Node,Ichor.Error) -- the mechanism a generatedrun/1,2uses to turn a raw parse into yourIchor.Actionsmodule's actual result. You implement anIchor.Actionsbehaviour; this is what calls it. Also whereIchor.Actions.evaluate_node/3lives -- the re-entry point a grammar with macro-like features (LISP's owndefmacro, most notably) needs to evaluate a capture tree that didn't come from the original parse (a macro's own expansion). - The compiled Tokenizer/Parser runtime
(
Grammar.Native.Runtime.Parser/Tokenizer,Grammar.VM.Token,Grammar.Source,Grammar.Lexer) -- the shared combinators everymix ichor.gen-generated module's own tokenizer/parser functions call into. Not meant to be called directly; generated code is the only caller. - The LR/GLR runtime (
Grammar.LRTable,Grammar.LRTable.Production/.Captures,Grammar.LR.Stack,Grammar.GLR.GSS/.Runtime) -- same idea, for a grammar tagged@engine lr/@engine glr: the shift-reduce stack and graph-structured-stack machinery a compiled LR/GLR parser's generated dispatch functions call into. Also not meant to be called directly. Ichor.CustomLexeme/Ichor.CustomRule-- the behaviours a grammar's own@native("Module", "function", ...)escape hatch dispatches to. You implement these; nothing here calls them for you.Ichor.Toolkit.Pratt-- precedence-climbing (Pratt) expression parsing over a runtime-mutable operator table (prefix/infix/postfix). Genuinely standalone -- useful for any expression grammar with operator precedence, whether or not it was ever generated by Ichor.Ichor.Toolkit.TermWalk-- genericfold/rewriterecursion over any term type implementingIchor.Backtrack.Term. Standalone.Ichor.Backtrack(+.Bindings/.Term/.Tree) -- a generic lazy-search-plus-unification substrate for logic-language evaluation models (SLD-resolution and friends). Standalone -- nothing else in this package calls it.Ichor.Toolkit.Result--reduce_ok/map_ok, anEnum.reduce-with-early-exit-on-failure pair. Standalone, tiny, useful anywhere you're threading a fallible step over a collection.
See the cheatsheet for worked examples of every
standalone piece (Pratt, TermWalk, Backtrack, Result), and for
what an Ichor.Actions module actually receives at runtime. For the
grammar-authoring side of things -- writing .aether grammars,
mix ichor.gen, use Ichor -- see
Ichor's own docs.
Development
mix deps.get
mix precommit
mix precommit chains format -> compile --warnings-as-errors ->
credo --strict -> sobelow -> test -> dialyzer.
License
MIT -- see LICENSE.