ArrayParser

Parsing of tokenized input



Data types


type alias Parser src dst = Array src -> Maybe (Result src dst)

A parser processes a sequence of src values. If it is successful, it produces a result. Otherwise, it produces Nothing.


type alias Result src dst = { backlog : Array src, values : Array dst }

If a parser has only processed part of its input, a backlog remains. This is the unprocessed part of the input. A Result src dst consists of this backlog and the sequence of produced values of type dst.



Basic parsers


array : Array a -> Array a -> Maybe (Result a a)

Parse a fixed array.

> parse = Parse.array [ "a", "b", "c" ]
> parse [ "a", "b", "c", "d", "e", "f" ]
Just { backlog = [ "d", "e", "f" ], values = [ "a", "b", "c" ] }


fail : Array src -> Maybe (Result src dst)

Always fail.

> parse = Parse.fail
> parse [ "a", "b", "c" ]
Nothing

succeed : Array dst -> Array src -> Maybe (Result src dst)

Always succeed and produce a fixed list of values.

> parse = Parse.succeed [ "x" ]
> parse [ "a", "b", "c" ]
Just ( backlog = [ "a", "b", "c" ], values = [ "x" ] )


Combinators



optional : Parser src dst -> Array src -> Maybe (Result src dst)

Apply a parser if possible.

> parse = Parse.optional ( Parse.array [ "x" ] )
> parse [ "x", "y", "z" ]
Just { backlog = [ "y", "z" ], values = [ "x" ] }

Do not fail if the parser cannot be applied.

> parse = Parse.optional ( Parse.string [ "x" ] )
> parse [ "a", "b", "c" ]
Just { backlog = [ "a", "b", "c" ], values = [] }

zeroOrMore : Parser src dst -> Array src -> Maybe (Result src dst)

Apply a parser as often as possible.

> parse = Parse.zeroOrMore ( Parse.array [ "x" ] )
> parse [ "x", "x", "x", "x", "a" ]
Just { backlog = [ "a" ], values = [ "x", "x", "x", "x" ] }
> parse = Parse.zerorMore ( Parse.array [ "x" ] )
> parse [ "a", "a", "a", "a", "a" ]
Just { backlog = [ "a", "a", "a", "a", "a" ], values = [] }

oneOrMore : Parser src dst -> Array src -> Maybe (Result src dst)

Apply a parser as often as possible, but at least once.

> parse = Parse.oneOrMore ( Parse.array [ "x" ] )
> parse [ "x", "x", "x", "x", "a" ]
Just { backlog = [ "a" ], values = [ "x", "x", "x", "x" ] }
> parse = Parse.oneOrMore ( Parse.array [ "x" ] )
> parse [ "a", "a", "a", "a", "a" ]
Nothing

oneOf :
Array (Parser src dst)
-> Array src
-> Maybe (Result src dst)

Apply the first successful parser from a list of parsers.

> parse =
      Parse.oneOf
          [ Parse.array [ "x" ]
          , Parse.array [ "y" ]
          , Parse.array [ "z" ]
          ]
> parse [ "y", "a", "k" ]
Just { backlog = [ "a", "k" ], values = [ "y" ] }

sequence :
Array (Parser src dst)
-> Array src
-> Maybe (Result src dst)

Apply several parsers in succession.

> parse =
      Parse.sequence
          [ Parse.array [ "x" ]
          , Parse.array [ "y" ]
          , Parse.array [ "z" ]
          ]
> parse [ "x", "y", "z" ]
Just { backlog = [], values = [ "x", "y", "z" ] }


Transformations


map :
(Array dst1 -> Array dst2) -> Parser src dst1 -> Array src -> Maybe (Result src dst2)

Transform the parsed values.

> parse = Parse.map ( Array.map Array.reverse ) ( Parse.array [ "a", "b", "c" ] )
> parse [ "a", "b", "c", "d", "ef" ]
Just { backlog = [ "d", "e", "f" ], values = [ "c", "b", "a" ] }

This can be used, for example, to change the target data type of a parser.

> parse = Parse.array [ "true" ] |> Parse.map ( \ _ -> [ True ] )
> parse [ "true" ]
> Just { backlog = [], values = [ True ] }

andThen :
(Result src dst1 -> Maybe (Result src dst2)) -> Parser src dst1 -> Array src -> Maybe (Result src dst2)

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.array [ "x" ] )
      |> Parse.andThen
          ( \ result ->
              if Array.length result.values > 3 then Nothing
              else Just result
          )
> parse [ "x", "x", "x" ]
Just { backlog = [], values = [ "x", "x", "x" ] }
> parse [ "x", "x", "x", "x" ]
Nothing


Execution


run : Parser src dst -> Array src -> Maybe dst

Apply a parser and produce a final result.

run expects a parser to process its input completely (i.e. to leave an empty backlog), and to produce exactly one value. If successful, the produced value is returned. Otherwise, nothing is returned.

> parser = Parse.array [ "foo" ]
> run parser [ "foo" ]
Just "foo"
> run parser [ "foo", "x" ]
Nothing