Current section

Files

Jump to
minipeg lib minipeg input.ex
Raw

lib/minipeg/input.ex

defmodule Minipeg.Input do
use Minipeg.Types
@moduledoc ~S"""
An input wrapper
"""
defstruct col: 1, context: %{}, input: "", lnb: 1
@type t :: %__MODULE__{col: pos_integer(), context: map(), input: binary(), lnb: pos_integer()}
@type take_and_rest_t :: {binary(), t()}
@spec new(input_t(), pos_integer(), pos_integer()) :: t()
def new(source, col \\ 1, lnb \\ 1, context \\ %{})
def new(%__MODULE__{} = src, col, lnb, ctxt), do: %{src | col: col, lnb: lnb, context: ctxt}
def new(source, col, lnb, ctxt) when is_binary(source),
do: %__MODULE__{input: source, col: col, lnb: lnb, context: ctxt}
@spec drop(t(), str_or_count_t()) :: t()
def drop(inp, str_or_count \\ 1)
def drop(%__MODULE__{} = inp, str) when is_binary(str) do
_drop(inp, String.length(str))
end
def drop(%__MODULE__{} = inp, count) do
_drop(inp, count)
end
@spec position(t()) :: position_t()
def position(%__MODULE__{col: col, lnb: lnb}), do: {col, lnb}
@spec report_position(t(), binary?()) :: binary()
def report_position(input, name \\ nil)
def report_position(%__MODULE__{col: col, lnb: lnb}, nil) do
"#{lnb},#{col}"
end
def report_position(%__MODULE__{col: col, lnb: lnb}, name) do
"#{lnb},#{col} in #{name}"
end
@spec _drop(t(), non_neg_integer()) :: t()
defp _drop(inp, count)
defp _drop(%__MODULE__{} = inp, 0), do: inp
defp _drop(%__MODULE__{input: ""} = inp, _), do: inp
defp _drop(%__MODULE__{input: input, col: col, lnb: lnb} = inp, 1) do
<<first::utf8, rest::binary>> = input
graph = List.to_string([first])
{col1, lnb1} = if graph == "\n", do: {1, lnb + 1}, else: {col + 1, lnb}
%{inp | input: rest, col: col1, lnb: lnb1}
end
defp _drop(%__MODULE__{input: input, col: col, lnb: lnb} = inp, count) do
<<first::utf8, rest::binary>> = input
graph = List.to_string([first])
{col1, lnb1} = if graph == "\n", do: {1, lnb + 1}, else: {col + 1, lnb}
_drop(%{inp | input: rest, col: col1, lnb: lnb1}, count - 1)
end
@spec take(t(), str_or_count_t()) :: take_and_rest_t()
def take(input, str_or_count \\ 1)
def take(%__MODULE__{} = inp, str) when is_binary(str) do
take(inp, String.length(str))
end
def take(%__MODULE__{input: input} = inp, count) do
{
input |> String.slice(0, count),
drop(inp, count)
}
end
end
# SPDX-License-Identifier: Apache-2.0