Data.Parser (data v0.6.0)
Higher-order functions to create and modify parsers.
Summary
Functions
Takes a parser p
and creates a parser that will successfully parse lists of values that all satisfy p
.
Takes a key parser and a value parser and creates a parser that will parse maps of keys and values.
Takes a parser and transforms it so that it works ~c"inside" Maybe.t
values.
Creates a parser that behaves exactly the same as the list/1
parser, except
that it will return the domain error :empty_list
if applied to an empty list.
Takes a list of values, elements
, and returns a parser that returns
successfully if its input is present in elements
.
Takes a boolean function p
(the predicate), and returns a parser
that parses successfully those values for which p
is true
.
Takes a boolean function p
(the predicate) and a default value, and returns
a parser that parses successfully those values for which p
is true
.
Takes a parser p
and creates a parser that will successfully parse sets of
values that all satisfy p
.
Takes a list of parsers and creates a parser that returns the first successful parse result, or an error listing the parsers and the failed input.
Types
@type t(a, b) :: (any() -> FE.Result.t(a, b))
A parser is a function that takes any value as input and produces a Result.t
.
More specifically, a parser(a,b)
is a fuction that takes any input and
returns {:ok, a}
on a successful parse or {:error, b}
if parsing failed.
Functions
See Data.Parser.KV.new/1
.
Takes a parser p
and creates a parser that will successfully parse lists of values that all satisfy p
.
Specifically, the input:
Must be a list
p
must parse successfully all elements in the input
If this is the case, the output will be {:ok, list_of_parsed_values}
.
If not all values can be parsed with p
, the result will be the original
parse error, enriched with the field :failed_element
in the error details.
If the input is not a list, the domain error :not_a_list
will be returned.
Examples
iex> Data.Parser.list(Data.Parser.BuiltIn.integer()).([])
{:ok, []}
iex> Data.Parser.list(Data.Parser.BuiltIn.integer()).([1,2,3])
{:ok, [1, 2, 3]}
iex> {:error, e} = Data.Parser.list(Data.Parser.BuiltIn.integer()).(%{a: :b})
...> Error.reason(e)
:not_a_list
iex> {:error, e} = Data.Parser.list(Data.Parser.BuiltIn.integer()).([1, :b, 3])
...> Error.reason(e)
:not_an_integer
...> Error.details(e)
%{failed_element: :b}
Takes a key parser and a value parser and creates a parser that will parse maps of keys and values.
Specifically, the input:
Must be a map
All keys of the input map must be parsed correctly by the key parser
All values of the input map must be parsed correctly by the value parser
If this is the case, the output will be {:ok, map_of_parsed_keys_and_values}
.
If not all keys can be parsed with the key parser, the result will be the
original parse error, enriched with the field :failed_key
in the error details.
If not all values can be parsed with the value parser, the result will be the
original parse error, enriched with the field :failed_value
in the error details.
If the input is not a map, the domain error :not_a_map
will be returned.
Examples
iex> Data.Parser.map(Data.Parser.BuiltIn.string(), Data.Parser.BuiltIn.integer()).(%{})
{:ok, %{}}
iex> Data.Parser.map(Data.Parser.BuiltIn.string(), Data.Parser.BuiltIn.integer()).(%{"a" => 1, "b" => 2})
{:ok, %{"a" => 1, "b" => 2}}
iex> {:error, e} = Data.Parser.map(Data.Parser.BuiltIn.string(), Data.Parser.BuiltIn.integer()).([])
...> Error.reason(e)
:not_a_map
iex> {:error, e} = Data.Parser.map(Data.Parser.BuiltIn.string(), Data.Parser.BuiltIn.integer()).(%{:a => 1})
...> Error.reason(e)
:failed_to_parse_key
...> Error.details(e)
%{key: :a}
iex> {:error, e} = Data.Parser.map(Data.Parser.BuiltIn.string(), Data.Parser.BuiltIn.integer()).(%{"a" => "not_int"})
...> Error.reason(e)
:failed_to_parse_value
...> Error.details(e)
%{key: "a", value: "not_int"}
@spec maybe(t(a, b)) :: t(FE.Maybe.t(a), FE.Maybe.t(b))
Takes a parser and transforms it so that it works ~c"inside" Maybe.t
values.
If the original parser works on String.t()
, the new one will work on
Maybe.t(String.t())
.
Successful parses on just()
values return {:ok, {:just, result_of_parse}}
.
Unsuccessful parses on just()
values reutrn {:error, parse_error}
.
The parser will successfully return {:ok, :nothing}
when applied to :nothing
.
Examples
iex(2)> Data.Parser.maybe(
...> Data.Parser.predicate( &is_binary/1, :invalid)).({:just, "good"})
{:ok, {:just, "good"}}
iex> Data.Parser.maybe(
...> Data.Parser.predicate( &is_binary/1, :invalid)).({:just, ~c"bad"})
{:error, :invalid}
iex> Data.Parser.maybe(
...> Data.Parser.predicate( &is_binary/1, :invalid)).(:nothing)
{:ok, :nothing}
Creates a parser that behaves exactly the same as the list/1
parser, except
that it will return the domain error :empty_list
if applied to an empty list.
Examples
iex> Data.Parser.nonempty_list(Data.Parser.BuiltIn.integer()).([1, 2, 3])
{:ok, [1, 2, 3]}
iex> {:error, e} = Data.Parser.nonempty_list(Data.Parser.BuiltIn.integer()).([1, :b, 3])
...> Error.reason(e)
:not_an_integer
...> Error.details(e)
%{failed_element: :b}
iex> {:error, e} = Data.Parser.nonempty_list(Data.Parser.BuiltIn.integer()).([])
...> Error.reason(e)
:empty_list
@spec one_of([a], b | (a -> b)) :: t(a, b) when a: var, b: var
Takes a list of values, elements
, and returns a parser that returns
successfully if its input is present in elements
.
If the input is not a member of elements
and default
is a value, the
parser fails with {:error, default}
. If default
is a unary function, the
parser fails with {:error, default.(input)}
.
Examples
iex> Data.Parser.one_of([:he, :ne, :ar, :kr, :xe, :rn], "not a noble gas").(:he)
{:ok, :he}
iex> Data.Parser.one_of([:he, :ne, :ar, :kr, :xe, :rn], "not a noble gas").(:n)
{:error, "not a noble gas"}
iex> Data.Parser.one_of([:he, :ne, :ar, :kr, :xe, :rn],
...> fn x -> "not a noble gas: #{inspect x}" end).(:o)
{:error, "not a noble gas: :o"}
Takes a boolean function p
(the predicate), and returns a parser
that parses successfully those values for which p
is true
.
If the predicate returns false
the parser will return a domain Error
with the input value and the predicate functions listed in the error details.
Examples
iex> {:error, e} = Data.Parser.predicate(&is_binary/1).(~c"charlists are not ok")
...> e.reason
:predicate_not_satisfied
...> e.details
%{input: ~c"charlists are not ok", predicate: &is_binary/1}
iex> Data.Parser.predicate(&is_binary/1).("this is fine")
{:ok, "this is fine"}
iex> Data.Parser.predicate(&(&1<10)).(5)
{:ok, 5}
iex> {:error, e} = Data.Parser.predicate(&(&1<10)).(55)
...> e.details.input
55
Takes a boolean function p
(the predicate) and a default value, and returns
a parser that parses successfully those values for which p
is true
.
If the predicate function applied to the input returns true
, the parser
wraps the input in an {:ok, input}
tuple.
If the predicate function returns false
, and default
is a value, the
parser returns {:error, default}
If the predicate returns false
and default
is a unary function, the
parser returns {:error, default.(the_failed_input)}
.
Examples
iex> Data.Parser.predicate(&is_binary/1, "invalid string").(~c"charlists are not ok")
{:error, "invalid string"}
iex> Data.Parser.predicate(&is_binary/1, "invalid string").(<<0::1, 1::2>>)
{:error, "invalid string"}
iex> Data.Parser.predicate(&is_binary/1, "invalid string").("this is fine")
{:ok, "this is fine"}
iex> Data.Parser.predicate(&is_binary/1, fn x -> "the bad value is: #{inspect x}" end).(12345)
{:error, "the bad value is: 12345"}
Takes a parser p
and creates a parser that will successfully parse sets of
values that all satisfy p
.
Specifically, the input:
must be a
MapSet
all elements of the input set must be parsed correctly by
p
If this is the case, the output will be {:ok, set_of_parsed_values}
.
If not all values can be parsed with p
, the result will be the original parse
error, enriched with the field :failed_element
in the error details.
If the input is not a MapSet
, the domain error :not_a_set
will be returned.
Examples
iex> {:ok, s} = Data.Parser.set(Data.Parser.BuiltIn.integer()).(MapSet.new())
...> s
MapSet.new([])
iex> {:ok, s} = Data.Parser.set(Data.Parser.BuiltIn.integer()).(MapSet.new([1,2,3]))
...> s
MapSet.new([1, 2, 3])
iex> {:error, e} = Data.Parser.set(Data.Parser.BuiltIn.integer()).(%{a: :b})
...> Error.reason(e)
:not_a_set
iex> {:error, e} = Data.Parser.set(Data.Parser.BuiltIn.integer()).(MapSet.new([1, :b, 3]))
...> Error.reason(e)
:not_an_integer
...> Error.details(e)
%{failed_element: :b}
Takes a list of parsers and creates a parser that returns the first successful parse result, or an error listing the parsers and the failed input.
Examples
iex> Data.Parser.union(
...> [Data.Parser.BuiltIn.integer(),
...> Data.Parser.BuiltIn.boolean()]).(true)
{:ok, true}
iex> Data.Parser.union(
...> [Data.Parser.BuiltIn.integer(),
...> Data.Parser.BuiltIn.boolean()]).(1)
{:ok, 1}
iex> {:error, e} = Data.Parser.union(
...> [Data.Parser.BuiltIn.integer(),
...> Data.Parser.BuiltIn.boolean()]).(:atom)
...> Error.reason(e)
:no_parser_applies
...> Error.details(e).input
:atom