zf

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

parse.ex (3855B)


      1 defmodule Absinthe.Phase.Parse do
      2   @moduledoc false
      3 
      4   use Absinthe.Phase
      5 
      6   alias Absinthe.{Blueprint, Language, Phase}
      7 
      8   # This is because Dialyzer is telling us tokenizing can never fail,
      9   # but we know it's possible.
     10   @dialyzer {:no_match, run: 2}
     11   @spec run(Language.Source.t() | %Blueprint{}, Keyword.t()) :: Phase.result_t()
     12   def run(input, options \\ [])
     13 
     14   def run(%Absinthe.Blueprint{} = blueprint, options) do
     15     options = Map.new(options)
     16 
     17     case parse(blueprint.input) do
     18       {:ok, value} ->
     19         {:ok, %{blueprint | input: value}}
     20 
     21       {:error, error} ->
     22         blueprint
     23         |> add_validation_error(error)
     24         |> handle_error(options)
     25     end
     26   end
     27 
     28   def run(input, options) do
     29     run(%Absinthe.Blueprint{input: input}, options)
     30   end
     31 
     32   # This is because Dialyzer is telling us tokenizing can never fail,
     33   # but we know it's possible.
     34   @dialyzer {:no_unused, add_validation_error: 2}
     35   defp add_validation_error(bp, error) do
     36     put_in(bp.execution.validation_errors, [error])
     37   end
     38 
     39   def handle_error(blueprint, %{jump_phases: true, result_phase: abort_phase}) do
     40     {:jump, blueprint, abort_phase}
     41   end
     42 
     43   def handle_error(blueprint, _) do
     44     {:error, blueprint}
     45   end
     46 
     47   @spec tokenize(binary) :: {:ok, [tuple]} | {:error, String.t()}
     48   def tokenize(input) do
     49     case Absinthe.Lexer.tokenize(input) do
     50       {:error, rest, loc} ->
     51         {:error, format_raw_parse_error({:lexer, rest, loc})}
     52 
     53       other ->
     54         other
     55     end
     56   end
     57 
     58   # This is because Dialyzer is telling us tokenizing can never fail,
     59   # but we know it's possible.
     60   @dialyzer {:no_match, parse: 1}
     61   @spec parse(binary | Language.Source.t()) :: {:ok, Language.Document.t()} | {:error, tuple}
     62   defp parse(input) when is_binary(input) do
     63     parse(%Language.Source{body: input})
     64   end
     65 
     66   defp parse(input) do
     67     try do
     68       case tokenize(input.body) do
     69         {:ok, []} ->
     70           {:ok, %Language.Document{}}
     71 
     72         {:ok, tokens} ->
     73           case :absinthe_parser.parse(tokens) do
     74             {:ok, _doc} = result ->
     75               result
     76 
     77             {:error, raw_error} ->
     78               {:error, format_raw_parse_error(raw_error)}
     79           end
     80 
     81         other ->
     82           other
     83       end
     84     rescue
     85       error ->
     86         {:error, format_raw_parse_error(error)}
     87     end
     88   end
     89 
     90   @spec format_raw_parse_error({{integer, integer}, :absinthe_parser, [charlist]}) ::
     91           Phase.Error.t()
     92   defp format_raw_parse_error({{line, column}, :absinthe_parser, msgs}) do
     93     message = msgs |> Enum.map(&to_string/1) |> Enum.join("")
     94     %Phase.Error{message: message, locations: [%{line: line, column: column}], phase: __MODULE__}
     95   end
     96 
     97   @spec format_raw_parse_error({integer, :absinthe_parser, [charlist]}) ::
     98           Phase.Error.t()
     99   defp format_raw_parse_error({line, :absinthe_parser, msgs}) do
    100     message = msgs |> Enum.map(&to_string/1) |> Enum.join("")
    101     %Phase.Error{message: message, locations: [%{line: line, column: 0}], phase: __MODULE__}
    102   end
    103 
    104   @spec format_raw_parse_error({:lexer, String.t(), {line :: pos_integer, column :: pos_integer}}) ::
    105           Phase.Error.t()
    106   defp format_raw_parse_error({:lexer, rest, {line, column}}) do
    107     sample_slice = String.slice(rest, 0, 10)
    108     sample = if String.valid?(sample_slice), do: sample_slice, else: inspect(sample_slice)
    109 
    110     message = "Parsing failed at `#{sample}`"
    111     %Phase.Error{message: message, locations: [%{line: line, column: column}], phase: __MODULE__}
    112   end
    113 
    114   @unknown_error_msg "An unknown error occurred during parsing"
    115   @spec format_raw_parse_error(map) :: Phase.Error.t()
    116   defp format_raw_parse_error(%{} = error) do
    117     detail =
    118       if Exception.exception?(error) do
    119         ": " <> Exception.message(error)
    120       else
    121         ""
    122       end
    123 
    124     %Phase.Error{message: @unknown_error_msg <> detail, phase: __MODULE__}
    125   end
    126 end