new test and small readme section on CCParse

This commit is contained in:
Simon Cruanes 2017-02-16 11:58:47 +01:00
parent 207a5725de
commit cd2d07c76a
2 changed files with 64 additions and 0 deletions

View file

@ -432,3 +432,39 @@ klist:: `'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]` is a lazy list
printer:: `'a printer = Format.formatter -> 'a -> unit` is a pretty-printer
to be used with the standard module `Format`. In particular, in many cases,
`"foo: %a" Foo.print foo` will type-check.
=== Parser Combinator
The module `CCParse` defines basic parser combinators on strings.
Adapting https://github.com/inhabitedtype/angstrom#usage[angstrom's tutorial example] gives the following snippet.
Note that backtracking is explicit in `CCParse`, hence
the use of `try_` to allow it in some places.
Explicit memoization with `memo` and `fix_memo` is also possible.
[source,OCaml]
----
open CCParse.Infix;;
module P = CCParse;;
let parens p = P.try_ (P.char '(') *> p <* P.char ')' ;;
let add = P.char '+' *> P.return (+) ;;
let sub = P.char '-' *> P.return (-) ;;
let mul = P.char '*' *> P.return ( * ) ;;
let div = P.char '/' *> P.return ( / ) ;;
let integer =
P.chars1_if (function '0'..'9'->true|_->false) >|= int_of_string ;;
let chainl1 e op =
P.fix (fun r ->
e >>= fun x -> P.try_ (op <*> P.return x <*> r) <|> P.return x) ;;
let expr : int P.t =
P.fix (fun expr ->
let factor = parens expr <|> integer in
let term = chainl1 factor (mul <|> div) in
chainl1 term (add <|> sub)) ;;
P.parse_string expr "4*1+2";; (* Ok 6 *)
P.parse_string expr "4*(1+2)";; (* Ok 12 *)
----

View file

@ -118,6 +118,34 @@
*)
(*$R
let open CCParse.Infix in
let module P = CCParse in
let parens p = P.try_ (P.char '(') *> p <* P.char ')' in
let add = P.char '+' *> P.return (+) in
let sub = P.char '-' *> P.return (-) in
let mul = P.char '*' *> P.return ( * ) in
let div = P.char '/' *> P.return ( / ) in
let integer =
P.chars1_if (function '0'..'9'->true|_->false) >|= int_of_string in
let chainl1 e op =
P.fix (fun r ->
e >>= fun x -> P.try_ (op <*> P.return x <*> r) <|> P.return x) in
let expr : int P.t =
P.fix (fun expr ->
let factor = parens expr <|> integer in
let term = chainl1 factor (mul <|> div) in
chainl1 term (add <|> sub)) in
assert_equal (Ok 6) (P.parse_string expr "4*1+2");
assert_equal (Ok 12) (P.parse_string expr "4*(1+2)");
()
*)
type 'a or_error = ('a, string) Result.result
type line_num = int