Ergo.Context (Ergo v1.0.4)

Ergo.Context defines the Context struct that is used to maintain parser state as the various parsers work, and various functions for creating & manipulating contexts.

Fields

  • status

When a parser returns it either sets status to :ok to indicate that it was successful or to a tuple {:error, reasons} where reasons is a list of tuples representing a sequence of errors. Each tuple is of the form {code, message} where code is an atom indiciting the specific type of error and the message contains additional human-focused information that may be helpful in diagnosing the problem.

  • input

The binary input being parsed.

  • consumed

The binary input that has already been consumed by parsing.

  • index

Represents the position in the input which has been read so far. Initially 0 it increments for each character processed.

  • line

Represents the current line of the input. Initially 1 it increments whenever a is read from the input.

  • col

Represents the current column of the input. Initially 1 it is incremented every time a character is read from the input and automatically resets whenever a is read.

  • entry_points

A list of Parser entry points

  • data

Map containing user-data that the parsers can use to pass information between them.

  • ast

Represents the current data structure being built from the input.

  • parser

The current parser.

  • tracks

Parsers will add themselves to the Context tracks in the form of {ref, index}. If the same parser attempts to add itself a second time at the same index an error is thrown because a cycle has been detected.

  • depth

As nested parsers are called the depth field will be updated to reflect the number of levels of nesting for the current parser.

  • captures

A map of data that can be captured from ASTs using the capture parser.

  • partial_ast

A list containing AST elements that were successfully parsed before a sequence parser failed. This allows error functions to access partially parsed data to provide better error messages.

Summary

Functions

Examples

iex> alias Ergo.Context
iex> context =
...>  Context.new("Hello World")
...>  |> Context.add_error(:unexpected_char, "Expected: |e| Actual: |.|")
iex> assert is_nil(context.ast)
iex> assert {:error, [{:unexpected_char, {1, 1}, "Expected: |e| Actual: |.|"}]} = context.status

iex> alias Ergo.Context
iex> context =
...>  Context.new("Hello World")
...>  |> Context.add_error(:unexpected_char, "Expected: |e| Actual: |.|")
...>  |> Context.add_error(:literal_failed, "Expected 'end'")
iex> assert is_nil(context.ast)
iex> assert {:error, [{:literal_failed, {1, 1}, "Expected 'end'"}, {:unexpected_char, {1, 1}, "Expected: |e| Actual: |.|"}]} = context.status

Because we build ASTs using lists they end up in reverse order. This method reverses the AST back to in-parse-order

Where an AST has been built from individual characters and needs to be converted to a string

Called to perform an arbitrary transformation on the AST value of a Context.

The ignore parser matches but returns a nil for the AST. Parsers like sequence accumulate these nil values. Call this function to remove them

Clears the partial AST by setting it to an empty list.

new returns a newly initialised Context with input set to the string passed in.

Reads the next character from the input of the passed in Context.

Returns truthy value if the parser referred to by ref has already been called for the index index.

Examples

iex> context = Context.new("Hello")
iex> assert %Context{status: :ok, ast: ?H, input: "ello", index: 1, line: 1, col: 2} = Context.peek(context)

iex> context = Context.new("")
iex> assert %Context{status: {:error, [{:unexpected_eoi, {1, 1}, "Unexpected end of input"}]}, index: 0, line: 1, col: 1} = Context.peek(context)

Pushes an AST element to the front of the partial AST list.

Clears the value of the status and ast fields to ensure that the wrong status information cannot be returned from a child parser.

Sets the partial AST for the context. This is used to track successfully parsed elements during sequence parsing failures.

Updates the Context to track that the parser referred to by ref has been called for the index index.

Functions

add_error(ctx, error_id, message \\ "")

Examples

iex> alias Ergo.Context
iex> context =
...>  Context.new("Hello World")
...>  |> Context.add_error(:unexpected_char, "Expected: |e| Actual: |.|")
iex> assert is_nil(context.ast)
iex> assert {:error, [{:unexpected_char, {1, 1}, "Expected: |e| Actual: |.|"}]} = context.status

iex> alias Ergo.Context
iex> context =
...>  Context.new("Hello World")
...>  |> Context.add_error(:unexpected_char, "Expected: |e| Actual: |.|")
...>  |> Context.add_error(:literal_failed, "Expected 'end'")
iex> assert is_nil(context.ast)
iex> assert {:error, [{:literal_failed, {1, 1}, "Expected 'end'"}, {:unexpected_char, {1, 1}, "Expected: |e| Actual: |.|"}]} = context.status

ast_in_parsed_order(ctx)

Because we build ASTs using lists they end up in reverse order. This method reverses the AST back to in-parse-order

Examples

iex> context = Ergo.Context.new("", ast: [4, 3, 2, 1])
iex> assert %Context{ast: [1, 2, 3, 4]} = Context.ast_in_parsed_order(context)

ast_to_string(ctx)

Where an AST has been built from individual characters and needs to be converted to a string

Examples

iex> context = Ergo.Context.new("", ast: [?H, ?e, ?l, ?l, ?o])
iex> assert %Context{ast: "Hello"} = Context.ast_to_string(context)

ast_transform(ctx, fun)

Called to perform an arbitrary transformation on the AST value of a Context.

Examples

iex> alias Ergo.Context
iex> context = Context.new("", ast: "Hello World")
iex> assert %Context{ast: "Hello World"} = Context.ast_transform(context, &Function.identity/1)

iex> alias Ergo.Context
iex> context = Context.new("", ast: "Hello World")
iex> assert %Context{ast: 11} = Context.ast_transform(context, &String.length/1)

iex> alias Ergo.Context
iex> context = Context.new("", ast: "Hello World")
iex> assert %Context{ast: "Hello World"} = Context.ast_transform(context, nil)

ast_without_ignored(ctx)

The ignore parser matches but returns a nil for the AST. Parsers like sequence accumulate these nil values. Call this function to remove them

Examples

iex> context = Ergo.Context.new("", ast: ["Hello", nil, "World", nil])
iex> assert %Context{ast: ["Hello", "World"]} = Context.ast_without_ignored(context)

clear_partial_ast(ctx)

Clears the partial AST by setting it to an empty list.

Examples

iex> alias Ergo.Context
iex> ctx = Context.new("test")
iex> ctx = Context.set_partial_ast(ctx, ["attr_name", ":"])
iex> ctx = Context.clear_partial_ast(ctx)
iex> assert %Context{partial_ast: []} = ctx

clip(context, length \\ 40)

commit(ctx)

dec_depth(ctx)

inc_depth(ctx)

make_error_fatal(ctx)

new(input \\ "", options \\ [])

new returns a newly initialised Context with input set to the string passed in.

Examples:

iex> alias Ergo.Context iex> assert %Context{status: :ok, input: "Hello World", line: 1, col: 1, index: 0, tracks: %{}} = Context.new("Hello World")

next_char(context)

Reads the next character from the input of the passed in Context.

If the input is empty returns status: {:error, :unexpected_eoi}.

Otherwise returns a new Context setting ast to the character read and incrementing positional variables such as index, line, and column appropriately.

Examples

iex> context = Context.next_char(Context.new("")) iex> assert %Context{status: {:error, [{:unexpected_eoi, {1, 1}, "Unexpected end of input"}] }} = context

iex> context = Context.next_char(Context.new("Hello World")) iex> assert %Context{status: :ok, input: "ello World", ast: ?H, index: 1, line: 1, col: 2} = context

parent_parser(context)

parser_tracked?(context, ref)

Returns truthy value if the parser referred to by ref has already been called for the index index.

Examples

iex> alias Ergo.Context iex> parser_ref = 123 iex> context = Context.new("Hello World") |> Context.track_parser(parser_ref, :foo) iex> assert Context.parser_tracked?(context, parser_ref)

peek(ctx)

Examples

iex> context = Context.new("Hello")
iex> assert %Context{status: :ok, ast: ?H, input: "ello", index: 1, line: 1, col: 2} = Context.peek(context)

iex> context = Context.new("")
iex> assert %Context{status: {:error, [{:unexpected_eoi, {1, 1}, "Unexpected end of input"}]}, index: 0, line: 1, col: 1} = Context.peek(context)

pop_parser(ctx)

push_parser(ctx, next_parser)

push_partial_ast(ctx, ast_element)

Pushes an AST element to the front of the partial AST list.

Examples

iex> alias Ergo.Context
iex> ctx = Context.new("test")
iex> ctx = Context.push_partial_ast(ctx, "attr_name")
iex> ctx = Context.push_partial_ast(ctx, ":")
iex> assert %Context{partial_ast: [":", "attr_name"]} = ctx

reset_status(ctx)

Clears the value of the status and ast fields to ensure that the wrong status information cannot be returned from a child parser.

Examples

iex> context = Context.new("Hello World")
iex> context = %{context | status: {:error, [{:inexplicable_error, "What the…"}]}, ast: true}
iex> context = Context.reset_status(context)
iex> assert %Context{status: :ok, ast: nil} = context

set_ast(ctx, new_ast)

set_partial_ast(ctx, partial_ast)

Sets the partial AST for the context. This is used to track successfully parsed elements during sequence parsing failures.

Examples

iex> alias Ergo.Context
iex> ctx = Context.new("test")
iex> ctx = Context.set_partial_ast(ctx, ["attr_name", ":"])
iex> assert %Context{partial_ast: ["attr_name", ":"]} = ctx

track_parser(ctx, ref, data)

Updates the Context to track that the parser referred to by ref has been called for the index index.

Examples:

iex> alias Ergo.Context
iex> import Ergo.Terminals
iex> context = Context.new("Hello World")
iex> parser = literal("Hello")
iex> context2 = Context.track_parser(context, parser.ref, :foo)
iex> assert Map.has_key?(context2.tracks, {0, parser.ref})

uncommit(ctx)