combine v0.10.0 Combine.Helpers View Source
Helpers for building custom parsers.
Link to this section Summary
Functions
Macro helper for building a custom parser
Link to this section Functions
Macro helper for building a custom parser.
A custom parser validates the next input against some rules. If the validation succeeds, the parser should:
- add one term to the result
- update the position
- remove the parsed part from the input
Otherwise, the parser should return a corresponding error message.
For example, let’s take a look at the implementation of Combine.Parsers.Text.string/2
,
which matches a required string and outputs it:
defparser string(%ParserState{status: :ok, line: line, column: col, input: input, results: results} = state, expected)
when is_binary(expected)
do
byte_size = :erlang.size(expected)
case input do
<<^expected::binary-size(byte_size), rest::binary>> ->
# string has been matched -> add the term, and update the position
new_col = col + byte_size
%{state | :column => new_col, :input => rest, :results => [expected|results]}
_ ->
# no match -> report an error
%{state | :status => :error, :error => "Expected `#{expected}`, but was not found at line #{line}, column #{col}."}
end
end
The macro above will generate a function which takes two arguments. The first
argument (parser state) can be omitted (i.e. you can use the macro as
string(expected_string)
). In this case, you’re just creating a basic parser
specification.
However, you can also chain parsers by providing the first argument:
parser1()
|> string(expected_string)
In this example, the state produced by parser1
is used when invoking the
string
parser. In other words, string
parser parses the remaining output.
On success, the final result will contain terms emitted by both parsers.
Note: if your parser doesn’t output exactly one term it might not work properly
with other parsers which rely on this property, especially those from
Combine.Parsers.Base
. As a rule, try to always output exactly one term. If you
need to produce more terms, you can group them in a list, a tuple, or a map. If
you don’t want to produce anything, you can produce the atom :__ignore
, which
will be later removed from the output.