zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

recorder.ex (3037B)


      1 defmodule NimbleParsec.Recorder do
      2   @moduledoc false
      3 
      4   @name __MODULE__
      5 
      6   @doc """
      7   Starts the recorder server.
      8   """
      9   def start_link(_opts) do
     10     Agent.start_link(fn -> %{} end, name: @name)
     11   end
     12 
     13   @doc """
     14   Stops the recorder server.
     15   """
     16   def stop() do
     17     Agent.stop(@name)
     18   end
     19 
     20   @doc """
     21   Records the given call and potentially debugs it.
     22   """
     23   def record(module, parser_kind, combinator_kind, name, combinators, inline, opts) do
     24     inline? = Keyword.get(opts, :inline, false)
     25 
     26     if Keyword.get(opts, :debug, false) do
     27       IO.puts(format_defs(combinator_kind, combinators, inline, inline?))
     28     end
     29 
     30     if Process.whereis(@name) do
     31       Agent.update(@name, fn state ->
     32         update_in(
     33           state[module],
     34           &[{parser_kind, combinator_kind, name, combinators, inline, inline?} | &1 || []]
     35         )
     36       end)
     37     end
     38 
     39     :ok
     40   end
     41 
     42   defp format_parser_kind(nil, _name) do
     43     []
     44   end
     45 
     46   defp format_parser_kind(:def, name) do
     47     {doc, spec, def} = NimbleParsec.Compiler.entry_point(name)
     48 
     49     """
     50     @doc "\""
     51     #{doc}
     52     "\""
     53     @spec #{Macro.to_string(spec)}
     54     #{format_def(:def, def)}
     55     """
     56   end
     57 
     58   defp format_parser_kind(:defp, name) do
     59     {_doc, spec, def} = NimbleParsec.Compiler.entry_point(name)
     60 
     61     """
     62     @spec #{Macro.to_string(spec)}
     63     #{format_def(:defp, def)}
     64     """
     65   end
     66 
     67   defp format_defs(kind, defs, inline, inline?) do
     68     functions = Enum.map(defs, &format_def(kind, &1))
     69     inline = if inline?, do: "@compile {:inline, #{inspect(inline)}}\n\n", else: ""
     70     [inline | functions]
     71   end
     72 
     73   defp format_def(kind, {name, args, guards, body}) do
     74     signature = Macro.to_string(quote(do: unquote(name)(unquote_splicing(args))))
     75 
     76     if guards == true do
     77       """
     78       #{kind} #{signature} do
     79         #{Macro.to_string(body)}
     80       end
     81 
     82       """
     83     else
     84       """
     85       #{kind} #{signature} when #{Macro.to_string(guards)} do
     86         #{Macro.to_string(body)}
     87       end
     88 
     89       """
     90     end
     91   end
     92 
     93   @doc """
     94   Replays recorded parsers on the given content.
     95   """
     96   def replay(contents, id) when is_binary(contents) do
     97     code = inject_recorded(contents, id, Agent.get(@name, & &1))
     98     [Code.format_string!(code) | "\n"]
     99   end
    100 
    101   defp inject_recorded(contents, id, recorded) do
    102     Enum.reduce(recorded, contents, fn {module, entries}, acc ->
    103       marker = "# parsec:#{inspect(module)}"
    104 
    105       case String.split(acc, marker) do
    106         [pre, _middle, pos] ->
    107           replacement = Enum.map(entries, &format_recorded/1)
    108           IO.iodata_to_binary([pre, replacement, pos])
    109 
    110         [_, _] ->
    111           raise ArgumentError, "expected 2 markers #{inspect(marker)} on #{inspect(id)}, got 1"
    112 
    113         _ ->
    114           raise ArgumentError, "could not find marker #{inspect(marker)} on #{inspect(id)}"
    115       end
    116     end)
    117   end
    118 
    119   defp format_recorded({parser_kind, combinator_kind, name, combinators, inline, inline?}) do
    120     [
    121       format_parser_kind(parser_kind, name)
    122       | format_defs(combinator_kind, combinators, inline, inline?)
    123     ]
    124   end
    125 end