zf

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

nimble_parsec.compile.ex (2667B)


      1 defmodule Mix.Tasks.NimbleParsec.Compile do
      2   @shortdoc "Compiles a parser and injects its content into the parser file"
      3 
      4   @moduledoc ~S"""
      5   Compiles a parser from a template.
      6 
      7       mix nimble_parsec.compile template.ex.exs
      8 
      9   This task is useful to generate parsers that have no runtime dependency
     10   on NimbleParsec.
     11 
     12   ## Examples
     13 
     14   Let's define a template file:
     15 
     16       # lib/my_parser.ex.exs
     17       defmodule MyParser do
     18         @moduledoc false
     19 
     20         # parsec:MyParser
     21         import NimbleParsec
     22 
     23         date =
     24           integer(4)
     25           |> ignore(string("-"))
     26           |> integer(2)
     27           |> ignore(string("-"))
     28           |> integer(2)
     29 
     30         time =
     31           integer(2)
     32           |> ignore(string(":"))
     33           |> integer(2)
     34           |> ignore(string(":"))
     35           |> integer(2)
     36           |> optional(string("Z"))
     37 
     38         defparsec :datetime, date |> ignore(string("T")) |> concat(time)
     39 
     40         # parsec:MyParser
     41       end
     42 
     43   After running:
     44 
     45       mix nimble_parsec.compile lib/my_parser.ex.exs
     46 
     47   The following file will be generated:
     48 
     49       # lib/my_parser.ex
     50       defmodule MyParser do
     51         @moduledoc false
     52 
     53         def datetime(binary, opts \\ []) do
     54           ...
     55         end
     56 
     57         defp datetime__0(...) do
     58           ...
     59         end
     60 
     61         ...
     62       end
     63 
     64   The file will be automatically formatted if using Elixir v1.6+.
     65 
     66   ## Options
     67 
     68     * `-o` - configures the output location. Defaults to the input
     69       file without its last extension
     70 
     71   """
     72 
     73   use Mix.Task
     74 
     75   @impl true
     76   def run(args) do
     77     Mix.Task.reenable("nimble_parsec.compile")
     78     {opts, files} = OptionParser.parse!(args, strict: [output: :string], aliases: [o: :output])
     79     Mix.Task.run("compile")
     80 
     81     case files do
     82       [file] -> compile(file, opts)
     83       _ -> Mix.raise("Expected a single file to be given to nimble_parsec.compile")
     84     end
     85   end
     86 
     87   defp compile(input, opts) do
     88     output = opts[:output] || Path.rootname(input)
     89     Mix.shell().info("Generating #{output}")
     90 
     91     {:ok, _} = NimbleParsec.Recorder.start_link([])
     92 
     93     try do
     94       Code.compiler_options(ignore_module_conflict: true)
     95       Code.require_file(input)
     96 
     97       input
     98       |> File.read!()
     99       |> NimbleParsec.Recorder.replay(input)
    100       |> write_to_disk(input, output)
    101     after
    102       Code.compiler_options(ignore_module_conflict: false)
    103       NimbleParsec.Recorder.stop()
    104     end
    105   end
    106 
    107   defp write_to_disk(contents, input, output) do
    108     now = DateTime.utc_now() |> Map.put(:microsecond, {0, 0}) |> to_string
    109 
    110     prelude = """
    111     # Generated from #{input}, do not edit.
    112     # Generated at #{now}.
    113 
    114     """
    115 
    116     File.write!(output, [prelude | contents])
    117   end
    118 end