Parse

Combinatory parsing in Gren.

Data types

type alias Result a = { backlog : String, values : Array a }

Data type for intermediate results

type alias Parser a = String -> Maybe (Result a)

Data type for parsers

Basic parsers

string : String -> String -> Maybe (Result String)

Parse a fixed string.

> parse = Parse.string "abc"
> parse "abcdef"
Just { backlog = "def", values = [ "abc" ] }
fail : String -> Maybe (Result a)

Always fail.

> Parse.fail "abc"
Nothing
succeed : Array a -> String -> Maybe (Result a)

Always succeed and produce a fixed list of values.

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

Combinators

optional : Parser a -> String -> Maybe (Result a)

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 = [] }
zeroOrMore : Parser a -> String -> Maybe (Result a)

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 = [] }
oneOrMore : Parser a -> String -> Maybe (Result a)

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
oneOf : Array (Parser a) -> String -> Maybe (Result a)

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" ] }
sequence : Array (Parser a) -> String -> Maybe (Result a)

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

map :
(Array a -> Array b)
-> Parser a
-> String
-> Maybe (Result b)

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 ] }
andThen :
(Result a -> Maybe ( Result b))
-> Parser a
-> String
-> Maybe (Result b)

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

Execution

run : Parser a -> String -> Maybe a

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.

eitherOr : Parser a -> Parser a -> String -> Maybe (Result a)

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
pair : Parser a -> Parser a -> String -> Maybe (Result a)

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