Current section
Files
Jump to
Current section
Files
lib/minipeg/input.ex
defmodule Minipeg.Input do
use Minipeg.Types
@moduledoc ~S"""
An input wrapper
"""
defstruct chars: [], col: 1, lnb: 1
@type t :: %__MODULE__{chars: list(binary()), col: pos_integer(), lnb: pos_integer()}
@type position_t :: {pos_integer(), 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)
def new(%__MODULE__{} = src, col, lnb), do: %{src|col: col, lnb: lnb}
def new(source, col, lnb) when is_list(source),
do: %__MODULE__{chars: source, col: col, lnb: lnb}
def new(source, col, lnb) when is_binary(source),
do: %__MODULE__{chars: String.graphemes(source), col: col, lnb: lnb}
@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 _drop(t(), non_neg_integer()) :: t()
defp _drop(inp, count)
defp _drop(%__MODULE__{}=inp, 0), do: inp
defp _drop(%__MODULE__{chars: []}=inp, _), do: inp
defp _drop(%__MODULE__{chars: ["\n"|rest], lnb: lnb}=inp, count) do
_drop(%{inp|chars: rest, col: 1, lnb: lnb + 1}, count - 1)
end
defp _drop(%__MODULE__{chars: [_|rest], col: col}=inp, count) do
_drop(%{inp|chars: rest, col: col + 1}, count - 1)
end
@spec take(t(), str_or_count_t()) :: take_and_rest_t()
def take(input, str_or_count)
def take(%__MODULE__{}=inp, str) when is_binary(str) do
take(inp, String.length(str))
end
def take(%__MODULE__{chars: chars}=inp, count) do
{
chars |> Enum.take(count) |> Enum.join,
drop(inp, count)
}
end
end
# SPDX-License-Identifier: Apache-2.0