One error struct, reused across every stage -- Lexer, Parser, analysis
pass, and Ichor.Actions -- so errors look the same regardless of
origin.
context_lines is pre-rendered at construction time, not lazily
computed on access: cheap to do once, and keeps every stage's error
output visually consistent.
Summary
Functions
Renders the full human-readable error: location, message, and the caret-annotated snippet, in that order.
Builds a Ichor.Error, pre-rendering context_lines immediately.
Types
@type stage() :: :lexer | :parser | :analysis | :action
@type t() :: %Ichor.Error{ column: pos_integer() | nil, context_lines: String.t() | nil, expected: term(), file: String.t() | nil, found: term(), line: pos_integer() | nil, message: String.t(), stage: stage() | nil }
Functions
Renders the full human-readable error: location, message, and the caret-annotated snippet, in that order.
Examples
iex> error = Ichor.Error.new(
...> message: "expected ')'",
...> stage: :parser,
...> file: "calc.aether",
...> line: 1,
...> column: 8,
...> source: "(2 + 3"
...> )
iex> Ichor.Error.format(error)
"calc.aether:1:8: expected ')'\n1 | (2 + 3\n | ^"
Builds a Ichor.Error, pre-rendering context_lines immediately.
Accepts :message (required), :stage, :line, :column, :file,
:expected, :found, and either :source (the full source text, used
to render a caret-annotated snippet at :line/:column) or a
pre-rendered :context_lines directly, for callers that already have
one (e.g. re-wrapping an error from another stage).
Examples
iex> error = Ichor.Error.new(
...> message: "expected ')'",
...> stage: :parser,
...> line: 1,
...> column: 8,
...> expected: ")",
...> found: :eof,
...> source: "(2 + 3"
...> )
iex> error.context_lines
"1 | (2 + 3\n | ^"
iex> Ichor.Error.new(message: "boom", source: nil, line: nil).context_lines
nil