Parse
Combinatory parsing in Gren.
Data types
Data type for intermediate results
Data type for parsers
Basic parsers
Parse a fixed string.
> parse = Parse.string "abc"
> parse "abcdef"
Just { backlog = "def", values = [ "abc" ] }
Always fail.
> Parse.fail "abc"
Nothing
Always succeed and produce a fixed list of values.
> parse = Parse.succeed [ "x" ]
> parse "abc"
Just ( backlog = "abc", values = [ "x" ] )
Combinators
Apply a parser and discard the result.
> parse = Parse.skip ( Parse.string "abc" )
> parse "abcdef"
Just { backlog = "def", values = [] }
Apply a parser if possible.
> parse = Parse.optional ( Parse.string "x" )
> parse "xyz"
Just { backlog = "yz", values = [ "x" ] }
Do not fail if the parser cannot be applied.
> parse = Parse.optional ( Parse.string "x" )
> parse "abc"
Just { backlog = "abc", values = [] }
Apply a parser as often as possible.
> parse = Parse.zeroOrMore ( Parse.string "x" )
> parse "xxxxa"
Just { backlog = "a", values = [ "x", "x", "x", "x" ] }
> parse = Parse.zerorMore ( Parse.string "x" )
> parse "aaaaa"
Just { backlog = "aaaaa", values = [] }
Apply a parser as often as possible, but at least once.
> parse = Parse.oneOrMore ( Parse.string "x" )
> parse "xxxxa"
Just { backlog = "a", values = [ "x", "x", "x", "x" ] }
> parse = Parse.oneOrMore ( Parse.string "x" )
> parse "aaaaa"
Nothing
Apply the first successful parser from a list of parsers.
> parse =
Parse.oneOf
[ Parse.string "x"
, Parse.string "y"
, Parse.string "z"
]
> parse "yak"
Just { backlog = "ak", values = [ "y" ] }
Apply several parsers in succession.
> parse =
Parse.sequence
[ Parse.string "x"
, Parse.string "y"
, Parse.string "z"
]
> parse "xyz"
Just { backlog = "", values = [ "x", "y", "z" ] }
Transformations
Transform the parsed values.
> parse = Parse.map ( Array.map String.reverse ) ( string "abc" )
> parse "abcdef"
Just { backlog = "def", values = [ "cba" ] }
This can be used, for example, to change the target data type of a parser.
> parse = Parse.string "true" |> Parse.map ( \ _ -> True )
> parse "true"
> Just { backlog = "", values = [ True ] }
Transform the result of a parser.
This can do everything that map
can do.
In addition, you can use it to decide whether a parser should fail based on the values it produces.
For example, we can use it to limit zeroOrMore
to three repetitions.
> parse =
Parse.zeroOrMore ( Parse.string "x" )
|> Parse.andThen
( \ r ->
if Array.length r.values > 3 then Nothing
else Just { backlog = r.backlog, values = r.values }
)
> parse "xxx"
Just { backlog = "", values = ["x", "x", "x"] }
> parse "xxxx"
Nothing
Execution
Apply a parser and produce a final result.
The Result
data type carries an input backlog and a list of parsed values.
This is necessary for combining parsers.
But a finished parser should process the whole input and produce exactly one value.
run
ensures this and returns the result value if the parser was successful.
> parser = Parse.string "foo"
> run parser "foo"
Just "foo"
> run parser "foox"
Nothing
Internals
The following functions are only exported so that my test code can access them.
Use the first parser, or the second if the first fails.
> parse = eitherOr ( string "x" ) ( string "y" )
> parse "yak"
Just { backlog = "ak", values = [ "y" ] }
oneOf
is defined as a fold over this function.
Therefore:
oneOf [ a, b ] == eitherOr a b
Concatenate two parsers.
> parse = pair ( string "x" ) ( string "y" )
> parse "xyz"
Just { backlog = "z", values = [ "x", "y" ] }
sequence
is defined as a fold over this function.
Therefore:
sequence [ a, b ] == pair a b