Combo is a simple parser combinator library for Ocaml providing common parsers and combinators. It is highly inspired by this paper with a few changes to integrate better with Ocaml and ideas taken from other libraries. It is named combo because it is based on COMBinig COMBinators in Ocaml.
Here is a simple calculator described in the paper:
open Combo
open Fun
let positive = int_of_string <$> (inplode <$> many1 digit)
let int = opt id (( * ) (-1) <$ char '-') <*> positive
let op (f, s) = spaces *> (f <$ word s) <* spaces
let anyop l = choice (List.map op l)
let addops = anyop [(+), "+"; (-), "-"]
let mulops = anyop [( * ), "*"]
let rec expr s =
List.fold_right chainl1 [addops; mulops] (int <|> packs "(" expr ")") s
let () =
let s = read_line () in
match expr (explode s) with
None -> print_endline "ERROR: bad expression."
| Some (n, _) -> print_int n
More examples can be found in the example directory (note: the JSON example needs this ppx).
Combo is not yet in opam, so it needs dune
to be installed, assuming you are
on a Unix like operating system, you can do:
git clone https://github.com/4y8/combo.git
cd combo/src
dune build ./combo.a
dune install
explode s
turns the string s
into a list of characters.
val explode : string -> char list
inplode l
turns the list of characters l
into a string.
val inplode : char list -> string
parser
is the type of parsers.
type ('a, 'b) parser = 'a list -> ('b * 'a list) option
return a
is a basic combinator that always succeeds returning the value
a
.
val return : 'a -> ('s, 'a) parser
fail
is a basic combinator which always fails.
val fail: ('s, 'a) parser
p <*> q
is the sequence combinator appliying the result of parser p
to
the parser q
.
val ( <*> ) : ('s, 'b -> 'a) parser -> ('s, 'b) parser -> ('s, 'a) parser
p <**> q
is the sequence combinator applying the result of parser q
to
the parser p
, it is the same as <*>
but in the other way.
val ( <**> ) : ('s, 'b) parser -> ('s, 'b -> 'a) parser -> ('s, 'a) parser
<??>
is the reverse sequencing operator but which doesn’t modify the first
result if the second one failed.
val ( <??> ) : ('s, 'a) parser -> ('s, 'a -> 'a) parser -> ('s, 'a) parser
Sequence monad.
val ( >>= ) : ('s, 'a) parser -> ('a -> ('s, 'b) parser) -> ('s, 'b) parser
p <|> q
is the choice combinator trying the parser p
, if it works,
returns the result, else return the result of the parser q
.
val ( <|> ) : ('s, 'a) parser -> ('s, 'a) parser -> ('s, 'a) parser
f <$> p
is the map combinator applying the function f
the witness returned
by the parser p
, if he succeeds.
val ( <$> ) : ('b -> 'a) -> ('s, 'b) parser -> ('s, 'a) parser
p <&> f
is the flipped map combinator applying the function f
the witness
returned by the parser p
, if he succeeds.
val ( <&> ) : ('b -> 'a) -> ('s, 'b) parser -> ('s, 'a) parser
f <$ p
is the map combinator ignoring the value returned by the parser p
.
val ( <$ ) : 'a -> ('s, 'b) parser -> ('s, 'a) parser
p $> f
is the reverse map combinator ignoring the value returned by the parser
p
.
val ( $> ) : ('s, 'a) parser -> 'b -> ('s, 'b) parser
p *> q
is the sequence combinator but ignores value returned by the parser
p
, it’s the missing bracket.
val ( *> ) : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b) parser
p <* q
is the sequence combinator but ignores value returned by the parser
q
, it’s the missing bracket.
val ( <* ) : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'a) parser
p <?> err
is the error combinator raising the error err if the parser p
failed.
val( <?> ) : ('s, 'a) parser -> exn -> ('s, 'a) parser
choice l
is a combinator that turns the list of parser l
into a single
one which will match one of them.
val choice : ('s, 'a) parser list -> ('s, 'a) parser
seq l
is a combinator that turns a list of parser l
into a single one
which will match all of them and return the result in a list.
val seq : ('s, 'a) parser list -> ('s, 'a list) parser
between open p close
parses the parser open
, then p
and close
and
returns the value of p
.
val between : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'c) parser -> ('s, 'b) parser
sepBy sep p
is a parser that parses 0 or more times the parser p
separated
by the parser sep
.
val sepBy : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b list) parser
sepBy1 sep p
is a parser that parses 1 or more times the parser p
separated
by the parser sep
.
val sepBy1 : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b list) parser
endBy sep p
is a parser that parses 0 or more times the parser p
separated and ended by the parser sep
.
val endBy : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b list) parser
endBy1 sep p
is a parser that parses 1 or more times the parser p
separated and ended by the parser sep
.
val endBy1 : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b list) parser
sepEndBy sep p
is a parser that parses 0 or more times the parser p
separated and optionally ended by the parser sep
.
val seEndpBy : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b list) parser
sepEndBy1 sep p
is a parser that parses 1 or more times the parser p
separated and optionally ended by the parser sep
.
val sepEndBy1 : ('s, 'a) parser -> ('s, 'b) parser -> ('s, 'b list) parser
Lazy combinators are really useful for some recursive combinators that may cause a stack overflow otherwise.
p <*>| q
is the lazy sequence combinator appliying the result of parser p
to
the parser q
, but only evaluating the parser q
if p
worked.
val ( <*>| ) : ('s, 'b -> 'a) parser -> ('s, 'b) parser lazy_t -> ('s, 'a) parser
p <|>| q
is the lazy choice combinator trying the parser p
, if it works,
returns the result, else evaluate the parser q
and returns it result.
val ( <|>| ) : ('s, 'a) parser -> ('s, 'a) parser lazy_t -> ('s, 'a) parser
p *>| q
is the lazy sequence combinator but ignores value returned by the
parser p
, it’s the missing bracket. The parser q
is evaluated only if p
succeeded.
val( *>| ) : ('s, 'a) parser -> ('s, 'b) parser lazy_t -> ('s, 'b) parser
p <*| q
is the sequence combinator but ignores value returned by the parser
q
, it’s the missing bracket. The parser q
is evaluated only if p
succeeded.
val( <*| ) : ('s, 'a) parser -> ('s, 'b) parser lazy_t -> ('s, 'a) parser
satisfyp
is a parser that matches an element satisfying the predicate p
.
val satisfy: ('a -> bool) -> ('a, 'a) parser
any
is a parser that matches anything.
val any : ('a, 'a) parser
opt default p
is parser that runs the parser p
and if it succeeds return
the result, else, it returns the default
value given.
val opt : 'a -> ('s, 'a) parser -> ('s, 'a) parser
many p
is a parser that runs the parser p
0 or more times and returns
all the obtained results in a list.
val many : ('s, 'a) parser -> ('s, 'a list) parser
many1 p
is a parser that runs the parser p
1 or more times and returns
all the obtained results in a list.
val many1 : ('s, 'a) parser -> ('s, 'a list) parser
chainl1 op p
is a parser that parses the operand p
, as left-associative,
separated by the separator op
, one or more times.
val chainl1 : ('s, 'a -> 'a -> 'a) parser -> ('s, 'a) parser -> ('s, 'a) parser
chainl op p default
is a parser that parses the operand p
, as
left-associative, separated by the separator op
, if it failed, returns the
value default
.
val chainl : ('s, 'a -> 'a -> 'a) parser -> ('s, 'a) parser -> 'a -> ('s, 'a) parser
chainr1 op p
is a parser that parses the operand p
, as right-associative,
separated by the separator op
, one or more times.
val chainr1 : ('s, 'a -> 'a -> 'a) parser -> ('s, 'a) parser -> ('s, 'a) parser
chainr op p default
is a parser that parses the operand p
, as
right-associative, separated by the separator op
, if it failed, returns the
value default
.
val chainr : ('s, 'a -> 'a -> 'a) parser -> ('s, 'a) parser -> 'a -> ('s, 'a) parser
sym s
is a parser that matches the symbol s
.
val sym : 'a -> ('a, 'a) parser
syms s
is a parser that matches the list of symbol s
.
val syms : 'a list -> ('a, 'a list) parser
char c
is a parser that matches the character c
.
val char : char -> (char, char) parser
word w
is a parser that matches the string w
.
val word : string -> (char, char list) parser
range l r
is a parser that matches a character between the characters l
and
r
included.
val range : char -> char -> (char, char) parser
lower
is a parser that matches a lowercase character
val lower : (char, char) parser
upper
is a parser that matches an uppercase character
val upper : (char, char) parser
letter
is a parser that matches an alphabet character.
val letter : (char, char) parser
digit
is a parser that matches a digit.
val digit : (char, char) parser
alphaNum
is a parser that matches a letter or a digit.
val alphaNum : (char, char) parser
octDigit
is a parser that matches an octal digit.
val octDigit : (char, char) parser
hexDigit
is a parser that matches a hexadecimal digit.
val octDigit : (char, char) parser
space
is a parser that matches a space.
val space : (char, char) parser
spaces
is a parser that matches 0 or more spaces.
val spaces : (char, char list) parser
newline
is a parser that matches a newline character.
val newline : (char, char) parser
tab
is a parser that matches a tab character.
val tab : (char, char) parser
pack l p r
is a parser that matches the parser p
between the symbols l
and r
.
val pack : 's list -> ('s, 'a) parser -> 's list -> ('s, 'a) parser
packs l p r
is a parser that matches the parser p
between the strings
l
and r
.
val packs : string -> (char, 'a) parser -> string -> (char, 'a) parser
oneOf l
is a parser that matches a symbol from the list l
.
val oneOf : 'a list -> ('a, 'a) parser