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 <> = 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 <> = 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