open CCParse;;
type tree = L of int | N of tree * tree;;
let mk_leaf x = L x
let mk_node x y = N(x,y)
let ptree = fix @@ fun self ->
skip_space *>
( (try_ (char '(') *> (pure mk_node <*> self <*> self) <* char ')')
<|>
(U.int >|= mk_leaf) )
;;
parse_string_exn ptree "(1 (2 3))" ;;
parse_string_exn ptree "((1 2) (3 (4 5)))" ;;
Parse a list of words
open Containers.Parse;;
let p = U.list ~sep:"," U.word;;
parse_string_exn p "[abc , de, hello ,world ]";;
Stress Test
This makes a list of 100_000 integers, prints it and parses it back.
let p = CCParse.(U.list ~sep:"," U.int);;
let l = CCList.(1 -- 100_000);;
let l_printed =
CCFormat.(to_string (within "[" "]" (list ~sep:(return ",@,") int))) l;;
let l' = CCParse.parse_string_exn p l_printed;;
assert (l=l');;
a <|> b tries to parse a, and if a fails without
consuming any input, backtracks and tries
to parse b, otherwise it fails as a.
See try_ to ensure a does not consume anything (but it is best
to avoid wrapping large parsers with try_).
a <?> msg behaves like a, but if a fails without
consuming any input, it fails with msg
instead. Useful as the last choice in a series of <|>:
a <|> b <|> c <?> "expected a|b|c".
Memoize the parser. memo p will behave like p, but when called
in a state (read: position in input) it has already processed, memo p
returns a result directly. The implementation uses an underlying
hashtable.
This can be costly in memory, but improve the run time a lot if there
is a lot of backtracking involving p.