Diagnostic reporting for an input the generated parser has no clause for.
Md.Engine compiles the syntax map into a do_parse/2 clause set. Every
clause is emitted from a syntax declaration, so the set is closed: an input
that reaches the catch-all clause has found a gap in the syntax definition
(or a bug in the engine), not merely an unusual document.
This module turns the parser state at that moment into something a maintainer
can act on. It reports, via Logger.error/1:
- the offending continuation, with its byte size and a
byte_size-aware preview (so a multi-byte character is never split); - the full mode stack, top first -- the mode is what selects the clause, so it is the single most useful piece of context;
- the open path (the elements currently being built) and the pending
bagcontents; - a hint derived from the top mode and the leading bytes, naming the construct whose clause is missing.
It then raises Md.Parser.Error with the same information in the message, so
the failure is visible to the consumer and not only in the log.
Summary
Functions
Builds the exception without raising it. Exposed for testing.
Reports the failure and raises Md.Parser.Error.
Types
@type t() :: %Md.Parser.Error{ __exception__: term(), bag: map(), continuation: binary(), hint: String.t() | nil, message: String.t(), mode: [Md.Listener.parse_mode()], parser: module(), path: [Md.Listener.trace()] }
Everything captured at the point the parser got stuck
Functions
@spec build(term(), Md.Parser.State.t(), module()) :: t()
Builds the exception without raising it. Exposed for testing.
@spec raise!(binary(), Md.Parser.State.t(), module()) :: no_return()
Reports the failure and raises Md.Parser.Error.
Called by the generated catch-all do_parse/2 clause; not part of the
public API.