Gumbo.Error (gumbo v0.3.0)

Copy Markdown View Source

A parse error gumbo recovered from.

An error is only meaningful together with the Gumbo.Output handle it came from: the handle owns the error vector and validates the index. A hand-built struct can carry an out-of-range index; that is a programmer error, so the scalar accessors raise ArgumentError on one and details/1 returns {:error, :invalid_node}. Nothing dereferences a bad index, and nil keeps exactly one meaning: this error type carries no such data.

Accessors by error type

Every error has a type/1, position/1, original_text/1, message/1 and caret/1. The type-specific accessors return nil off their types:

AccessorError types
codepoint/1:utf8_invalid, :utf8_truncated, :control_character_in_input_stream, :noncharacter_in_input_stream, :numeric_char_ref_without_semicolon, :numeric_char_ref_invalid
tokenizer/1the tokenizer-state errors (e.g. :tag_eof, :attr_name_invalid, :comment_eof, :doctype_invalid)
text/1:named_char_ref_without_semicolon, :named_char_ref_invalid
duplicate_attr/1:duplicate_attr
parser_error/1:parser, :unacknowledged_self_closing_tag

original_text/1 is the source bytes from the error location to the end of the input; message/1 is gumbo_error_to_string and caret/1 is gumbo_caret_diagnostic_to_string, both rendered by gumbo itself against the retained copy of the source.

Summary

Functions

Gumbo's caret diagnostic: the message, the offending source line, and a caret pointing at the column (gumbo_caret_diagnostic_to_string).

The offending code point for the UTF-8 and numeric character-reference errors; nil off those types.

Every field at once.

The duplicated attribute's name and both of its indices in the attribute vector; nil off :duplicate_attr.

Gumbo's own one-line description (gumbo_error_to_string).

The source bytes from the error location to the end of the input.

The parser state at the error for :parser and :unacknowledged_self_closing_tag; nil off those types.

The source position where the error occurred.

The named character reference as written for the named character-reference errors; nil off those types.

The tokenizer state and code point under the cursor for the tokenizer- state errors; nil off those types.

Types

t()

@opaque t()

Functions

caret(error)

@spec caret(t()) :: binary()

Gumbo's caret diagnostic: the message, the offending source line, and a caret pointing at the column (gumbo_caret_diagnostic_to_string).

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.caret()
"@1:16: Attribute class occurs multiple times, at positions 0 and 1.\n<div class=\"a\" class=\"b\">\n               ^\n"

codepoint(error)

@spec codepoint(t()) :: non_neg_integer() | nil

The offending code point for the UTF-8 and numeric character-reference errors; nil off those types.

Examples

iex> {:ok, output} = Gumbo.parse("<p>" <> <<0xFF>> <> "</p>")
iex> error = Enum.find(Gumbo.Output.errors(output), &(Gumbo.Error.type(&1) == :utf8_invalid))
iex> Gumbo.Error.codepoint(error)
255

details(error)

@spec details(t()) :: {:ok, map()} | {:error, :invalid_node}

Every field at once.

The eight fields that read the error in place plus the two that render it, message and caret, so a caller wanting one field can ask for it without paying for the other nine.

The map keys are the accessor names above, with nil for fields the error type does not carry, so details(error)[:type] == type(error) for every key. Gumbo.materialize/2's error maps are this map minus :caret: it builds one map per error and a caret renders the whole source line, so see caret/1 for that field on a single error. The deliberate exception to the ArgumentError contract, matching Gumbo.Node.details/1: a caller asking for a whole error branches on {:error, :invalid_node} rather than rescues.

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> {:ok, details} = output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.details()
iex> details[:type]
:duplicate_attr

duplicate_attr(error)

@spec duplicate_attr(t()) ::
  %{
    name: binary(),
    original_index: non_neg_integer(),
    new_index: non_neg_integer()
  }
  | nil

The duplicated attribute's name and both of its indices in the attribute vector; nil off :duplicate_attr.

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.duplicate_attr()
%{name: "class", new_index: 1, original_index: 0}

message(error)

@spec message(t()) :: binary()

Gumbo's own one-line description (gumbo_error_to_string).

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.message()
"@1:16: Attribute class occurs multiple times, at positions 0 and 1."

original_text(error)

@spec original_text(t()) :: binary()

The source bytes from the error location to the end of the input.

gumbo stores a pointer to the offending byte, not a length, so the remainder of the retained input is what this accessor can report; for an error at end of input it is the empty binary.

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.original_text()
"class=\"b\">"

parser_error(error)

@spec parser_error(t()) ::
  %{
    input_type: Gumbo.Types.token_type(),
    input_tag: Gumbo.Tag.t(),
    insertion_mode: Gumbo.Types.insertion_mode(),
    tag_stack: [Gumbo.Tag.t()]
  }
  | nil

The parser state at the error for :parser and :unacknowledged_self_closing_tag; nil off those types.

tag_stack is the stack of open elements at the error, bottom first, as Gumbo.Tag.t/0 values.

Examples

iex> {:ok, output} = Gumbo.parse("</p>")
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.parser_error()
%{input_type: :end_tag, input_tag: :p, insertion_mode: :initial, tag_stack: []}

position(error)

@spec position(t()) :: Gumbo.Position.t()

The source position where the error occurred.

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.position()
%Gumbo.Position{line: 1, column: 16, offset: 15}

text(error)

@spec text(t()) :: binary() | nil

The named character reference as written for the named character-reference errors; nil off those types.

Examples

iex> {:ok, output} = Gumbo.parse("&notit;")
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.text()
"not"

tokenizer(error)

@spec tokenizer(t()) ::
  %{state: Gumbo.Types.tokenizer_state(), codepoint: integer()} | nil

The tokenizer state and code point under the cursor for the tokenizer- state errors; nil off those types.

codepoint is the raw value the tokenizer saw, so it can be -1 at end of input.

Examples

iex> {:ok, output} = Gumbo.parse("<p a")
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.tokenizer()
%{state: :data, codepoint: -1}

type(error)

@spec type(t()) :: Gumbo.Types.error_type()

The error's Gumbo.Types.error_type/0.

Examples

iex> {:ok, output} = Gumbo.parse(~s(<div class="a" class="b">))
iex> output |> Gumbo.Output.errors() |> Enum.at(0) |> Gumbo.Error.type()
:duplicate_attr