defmodule Irc.Parser.Prefix do @moduledoc """ Parser for prefixes. Supports multi-prefix. """ @spec parse(String.t, Irc.Connection.t) :: {modes :: [String.t], rest :: nil | String.t} @doc """ If `lax` is set to true, the parser will ignore chars until it meets a known prefix. """ def parse(string, conn, lax \\ false) do map = Map.get(conn.isupport, "PREFIX") || %{} {prefixes, rest} = parse_prefix(string, Map.keys(map), lax) modes = Enum.map(prefixes, fn(p) -> Map.get(map, p) end) |> Enum.filter(fn(p) -> p end) {Enum.reverse(modes), to_string(Enum.reverse(rest))} end defp parse_prefix(string, all_prefixes, lax) do parse_prefix(to_charlist(string), to_charlist(all_prefixes), [], [], lax) end defp parse_prefix(all = [prefix | rest], all_prefixes, acc, ign, lax) do prefix_str = to_string([prefix]) cond do Enum.member?(all_prefixes, prefix_str) -> parse_prefix(rest, all_prefixes, [prefix_str | acc], ign, lax) lax && acc == [] -> parse_prefix(rest, all_prefixes, acc, [prefix | ign], lax) true -> parse_lax(all, acc, []) end end defp parse_prefix([], _, acc, ign, _) do {acc, ign} end defp parse_lax([a | rest], prefixes, acc) do parse_lax(rest, prefixes, [a | acc]) end defp parse_lax([], prefixes, acc) do {prefixes, acc} end end