lib/pegasus/class.ex

defmodule Pegasus.Class do
  @moduledoc """
  Produces a "class" parser.

  Note that the output of a "class" parser leaves a NimbleParsec parser in the
  arguments list.

  ```peg
  Class           <- '[' < ( !']' Range )* > ']' Spacing
  ```
  """

  alias Pegasus.Components

  import NimbleParsec

  def parser(previous \\ empty()) do
    previous
    |> tag(
      ignore(string("["))
      |> optional(string("^"))
      |> repeat(
        lookahead_not(string("]"))
        |> Components.range()
      )
      |> ignore(string("]")),
      :class
    )
    |> post_traverse({__MODULE__, :to_parser, []})
    |> Components.spacing()
  end

  def to_parser(rest, [{:class, args} | args_rest], context, _, _) do
    classes =
      case args do
        ["^" | rest] ->
          Enum.map(rest, &{:not, &1})

        args ->
          args
      end

    {rest, [{:char, classes} | args_rest], context}
  end
end