Bogdanp/elm-combine/2.2.0

NOTE: this package is not compatible with Elm 0.19.1

Combine

This library provides reasonably fast parser combinators.

type Parser res

The Parser type.

At their core, Parsers simply wrap functions from a Context to a tuple of a Result res and a new Context.

type alias Context =
{ input : String
, position : Int
}

The contex over which Parsers operate.

Constructing Parsers

primitive : (Context -> ( Result res, Context )) -> Parser res

Construct a new primitive Parser.

If you find yourself reaching for this function often consider opening a Github issue with the library to have your custom Parsers included in the standard distribution.

Running a Parser

parse : Parser res -> String -> ( Result res, Context )

Parse a string.

import Combine.Num exposing (int)


parse int "123" ==
  (Ok 123, { input = "", position = 3 })


parse int "abc" ==
  (Err ["expected an integer"], { input = "abc", position = 0 })
app : Parser res -> Context -> ( Result res, Context )

Unwrap a parser so it can be applied to a context.

rec : (() -> Parser res) -> Parser res

Defer a parser's evaluation.

type E = ETerm String | EList (List E)


whitespace : Parser String
whitespace = regex "[ \t\r\n]*"


term : Parser E
term = ETerm `map` (whitespace *> regex "[a-zA-Z]+" <* whitespace)


list : Parser E
list = rec (\() -> EList `map` (string "(" *> many (term `or` list) <* string ")"))


parse list "" ==
  (Err ["expected \"(\""], { input = "", position = 0 })


parse list "()" ==
  (Ok (EList []), { input = "", position = 2 })


parse list "(a (b c))" ==
  (Ok (EList [ETerm "a", EList [ETerm "b", ETerm "c"]]), { input = "", position = 9 })

Transforming Parsers

(res -> res_)
-> (List String -> List String)
-> Parser res
-> Parser res_

Transform both the result and error message of a parser.

map : (res -> res_) -> Parser res -> Parser res_

Transform the result of a parser.

parse (map String.toUpper (string "a")) "a" ==
  (Ok "A", { input = "", position = 1 })
mapError : (List String -> List String) -> Parser res -> Parser res

Transform the error of a parser.

parse (mapError (\_ -> ["bad input"]) (string "a")) "b" ==
  (Err ["bad input"], { input = "b", position = 0 })

Chaining Parsers

andThen : Parser res -> (res -> Parser res_) -> Parser res_

Sequence two parsers, passing the result of the first parser to a function that returns the second parser. The value of the second parser is returned on success.

import Combine.Num exposing (int)


choosy : Parser String
choosy =
  int
    `andThen` \x -> if x % 2 == 0
                    then string " is even"
                    else string " is odd"


parse choosy "1 is odd" ==
  (Ok " is odd", { input = "", position = 8 })


parse choosy "1 is even" ==
  (Err ["expected \" is odd\""], { input = " is even", position = 1 })
andMap : Parser (a -> res) -> Parser a -> Parser res

Sequence two parsers.

import Maybe
import Result
import String


num : Parser Int
num = (Maybe.withDefault 0 << Result.toMaybe << String.toInt) `map` regex "[0-9]+"


sum : Parser Int
sum = (+) `map` (num <* string "+") `andMap` num


parse sum "1+2" ==
  (Ok 3, { input = "", position = 3 })
sequence : List (Parser res) -> Parser (List res)

Run a list of parsers in sequence, accumulating the results.

parse (sequence [string "a", string "b"]) "ab" ==
  (Ok ["a", "b"], { input = "", position = 2 })


parse (sequence [string "a", string "b"]) "ac" ==
  (Err ["expected \"b\"", { input = "c", position = 1 })

Parsers

fail : List String -> Parser res

Fail without consuming any input.

succeed : res -> Parser res

Return a value without consuming any input.

parse (succeed 1) "a" ==
  (Ok 1, { input = "a", position = 0 })
string : String -> Parser String

Parse an exact string match.

parse (string "hello") "hello world" ==
  (Ok "hello", { input = " world", position = 5 })


parse (string "hello") "goodbye" ==
  (Err ["expected \"hello\""], { input = "goodbye", position = 0 })
regex : String -> Parser String

Parse a Regex match.

Regular expressions must match from the beginning of the input and their subgroups are ignored. A ^ is added implicitly to the beginning of every pattern unless one already exists.

parse (regex "a+") "aaaaab" ==
  (Ok "aaaaa", { input = "b", position = 5 })
while : (Char -> Bool) -> Parser String

Consume input while the predicate matches.

parse (while ((/=) ' ')) "test 123" ==
  (Ok "test", { input = " 123", position = 4 })
end : Parser ()

Fail when the input is not empty.

parse end "" == (Ok (), { input = "", position = 0 })
parse end "a" == (Err ["expected end of input"], { input = "a", position = 0 })
or : Parser res -> Parser res -> Parser res

Choose between two parsers.

parse (string "a" `or` string "b") "a" ==
  (Ok "a", { input = "", position = 1 })


parse (string "a" `or` string "b") "b" ==
  (Ok "b", { input = "", position = 1 })


parse (string "a" `or` string "b") "c" ==
  (Err ["expected \"a\"", "expected \"b\""], { input = "c", position = 0 })
choice : List (Parser res) -> Parser res

Choose between a list of parsers.

parse (choice [string "a", string "b"]) "a" ==
  (Ok "a", { input = "", position = 1 })


parse (choice [string "a", string "b"]) "b" ==
  (Ok "b", { input = "", position = 1 })
optional : res -> Parser res -> Parser res

Return a default value when the given parser fails.

letterA : Parser String
letterA = optional "a" (string "a")


parse letterA "a" == (Ok "a", { input = "", position = 1 })
parse letterA "b" == (Ok "a", { input = "b", position = 0 })
maybe : Parser res -> Parser (Maybe res)

Wrap the return value into a Maybe. Returns Nothing on failure.

parse (maybe (string "a")) "a" ==
  (Ok (Just "a"), { input = "", position = 1 })


parse (maybe (string "a")) "b" ==
  (Ok Nothing, { input = "b", position = 0 })
many : Parser res -> Parser (List res)

Apply a parser until it fails and return a list of the results.

parse (many (string "a")) "aaab" ==
  (Ok ["a", "a", "a"], { input = "b", position = 3 })


parse (many (string "a")) "" ==
  (Ok [], { input = "", position = 0 })
many1 : Parser res -> Parser (List res)

Parse at least one result.

parse (many1 (string "a")) "a" ==
  (Ok ["a"], { input = "", position = 1 })


parse (many1 (string "a")) "" ==
  (Err ["expected \"a\""], { input = "", position = 0 })
manyTill : Parser res -> Parser end -> Parser (List res)

Apply parser p zero or more times until parser end succeeds. On success, the list of p's results is returned.

string "<!--" *> manyTill anyChar (string "-->")
sepBy : Parser x -> Parser res -> Parser (List res)

Parser zero or more occurences of one parser separated by another.

parse (sepBy (string ",") (string "a")) "b" ==
  (Ok [], { input = "b", position = 0 })


parse (sepBy (string ",") (string "a")) "a,a,a" ==
  (Ok ["a", "a", "a"], { input = "", position = 5 })


parse (sepBy (string ",") (string "a")) "a,a,b" ==
  (Ok ["a", "a"], { input = ",b", position = 3 })
sepBy1 : Parser x -> Parser res -> Parser (List res)

Parse one or more occurences of one parser separated by another.

sepEndBy : Parser x -> Parser res -> Parser (List res)

Parse zero or more occurences of one parser separated and optionally ended by another.

parse (sepEndBy (string ",") (string "a")) "a,a,a," ==
  (Ok ["a", "a", "a"], { input = "", position = 6 })
sepEndBy1 : Parser x -> Parser res -> Parser (List res)

Parse one or more occurences of one parser separated and optionally ended by another.

parse (sepEndBy1 (string ",") (string "a")) "" ==
  (Err ["expected \"a\""], { input = "", position = 0 })


parse (sepEndBy1 (string ",") (string "a")) "a" ==
  (Ok ["a"], { input = "", position = 1 })


parse (sepEndBy1 (string ",") (string "a")) "a," ==
  (Ok ["a"], { input = "", position = 2 })
skipMany : Parser x -> Parser ()

Apply a parser and skip its result many times.

skipMany1 : Parser x -> Parser ()

Apply a parser and skip its result at least once.

chainl : Parser res -> Parser (res -> res -> res) -> Parser res

Parse one or more occurences of p separated by op, recursively apply all functions returned by op to the values returned by p. See the examples/Calc.elm file for an example.

chainr : Parser res -> Parser (res -> res -> res) -> Parser res

Similar to chainl but functions of op are applied in right-associative order to the values of p.

count : Int -> Parser res -> Parser (List res)

Parse n occurences of p.

between : Parser left -> Parser right -> Parser res -> Parser res

Parse something between two other parsers.

The parser

between (string "(") (string ")") (string "a")

is equivalent to the parser

string "(" *> string "a" <* string ")"
parens : Parser res -> Parser res

Parse something between parentheses.

braces : Parser res -> Parser res

Parse something between braces {}.

brackets : Parser res -> Parser res

Parse something between square brackets [].