ocaml-containers/tests/core/t_parse.ml
2022-07-02 00:29:25 -04:00

214 lines
7.3 KiB
OCaml

module Tst = (val Containers_testlib.make ~__FILE__ ())
include Tst;;
open CCParse
module T = struct
type tree = L of int | N of tree * tree
end
open T
let mk_leaf x = L x
let mk_node x y = N(x,y)
let ptree = fix @@ fun self ->
skip_space *>
( (char '(' *> (pure mk_node <*> self <*> self) <* char ')')
<|>
(U.int >|= mk_leaf) )
let ptree' = fix_memo @@ fun self ->
skip_space *>
( (char '(' *> (pure mk_node <*> self <*> self) <* char ')')
<|>
(U.int >|= mk_leaf) )
let rec pptree = function
| N (a,b) -> Printf.sprintf "N (%s, %s)" (pptree a) (pptree b)
| L x -> Printf.sprintf "L %d" x
let errpp pp = function
| Ok x -> "Ok " ^ pp x
| Error s -> "Error " ^ s
let errpptree = errpp pptree
let erreq eq x y = match x, y with
| Ok x, Ok y -> eq x y
| Error _ , Error _ -> true
| _ -> false ;;
(* ### start tests ### *)
eq ~printer:errpptree (Ok (N (L 1, N (L 2, L 3))))
(parse_string ptree "(1 (2 3))" );;
eq ~printer:errpptree (Ok (N (N (L 1, L 2), N (L 3, N (L 4, L 5)))))
(parse_string ptree "((1 2) (3 (4 5)))" );;
eq ~printer:errpptree (Ok (N (L 1, N (L 2, L 3))))
(parse_string ptree' "(1 (2 3))" );;
eq ~printer:errpptree (Ok (N (N (L 1, L 2), N (L 3, N (L 4, L 5)))))
(parse_string ptree' "((1 2) (3 (4 5)))" );;
t @@ fun () ->
let p = U.list ~sep:"," U.word in
let printer = function
| Ok l -> "Ok " ^ CCFormat.(to_string (Dump.list string_quoted)) l
| Error s -> "Error " ^ s
in
assert_equal ~printer
(Ok ["abc"; "de"; "hello"; "world"])
(parse_string p "[abc , de, hello ,world ]");
true;;
t @@ fun () ->
let test n =
let p = CCParse.(U.list ~sep:"," U.int) in
let l = CCList.(1 -- n) in
let l_printed =
CCFormat.(to_string (within "[" "]" (list ~sep:(return ",") int))) l in
let l' = CCParse.parse_string_exn p l_printed in
assert_equal ~printer:Q.Print.(list int) l l'
in
test 300_000;
true ;;
t @@ fun () ->
let open CCParse.Infix in
let module P = CCParse in
let parens p = 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 chainr1 e op =
P.fix (fun r ->
e >>= fun x -> (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 = chainr1 factor (mul <|> div) in
chainr1 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)");
true;;
let eq' = eq ~printer:(errpp Q.Print.bool) ~cmp:(erreq (=)) ;;
eq' (Ok true) (parse_string (U.bool <* eoi) "true");;
eq' (Error "") (parse_string (U.bool <* eoi) "true ");;
eq' (Ok true) (parse_string (U.bool <* skip_white <* eoi) "true");;
let eq' = eq ~printer:Q.Print.(pair int int);;
eq' (0,5) (let p = any_char_n 5 *> pos in
match parse_string p "abcde " with
| Ok p -> Position.line_and_column p
| Error _ -> assert false);;
eq ~printer:Q.Print.(list @@ pair int int)
[(0,2); (1,3); (2,1); (3,0); (4,0); (5,2)]
(let p = each_line (skip_space *> pos) in
match parse_string p " a\n b\nc\n\n\n a" with
| Ok ps -> List.map Position.line_and_column ps
| Error _ -> assert false);;
let eq' = eq ~printer:(errpp Q.Print.string) ~cmp:(erreq (=));;
eq' (Ok "abcd") (parse_string all_str "abcd");;
eq' (Ok "cd") (parse_string (string "ab" *> all_str) "abcd");;
eq' (Ok "") (parse_string (string "ab" *> all_str) "ab");;
eq ~printer:(errpp Q.Print.(pair string string)) ~cmp:(erreq (=))
(Ok ("foobar", "")) (parse_string (both all_str all_str) "foobar");;
q Q.(printable_string) (fun s ->
let pred = (function 'a'..'z' | 'A' .. 'Z' | '{' | '}' -> true | _ -> false) in
let p1 = chars1_if pred in
let p2 = take1_if pred >|= Slice.to_string in
parse_string p1 s = parse_string p2 s);;
t @@ fun () ->
let pred = (function 'a'..'z' | 'A' .. 'Z' | '{' | '}' -> true | _ -> false) in
parse_string (chars_if pred) "coucou{lol} 123" = Ok "coucou{lol}" ;;
t @@ fun () ->
let p0 = skip_white *> U.int in
let p = (skip_white *> char '(' *> many p0) <* (skip_white <* char ')') in
let printer = CCFormat.(to_string @@ Dump.result @@ Dump.list int) in
assert_equal ~printer
(Ok [1;2;3]) (parse_string p "(1 2 3)");
assert_equal ~printer
(Ok [1;2; -30; 4]) (parse_string p "( 1 2 -30 4 )");
true;;
let aword = chars1_if (function 'a'..'z'|'A'..'Z'->true|_ -> false);;
eq ~printer:(errpp Q.Print.(list string))
(Ok ["a";"b";"c"])
(parse_string (optional (char '/') *> sep ~by:(char '/') aword) "/a/b/c");;
eq ~printer:(errpp Q.Print.(list string))
(Ok ["a";"b";"c"])
(parse_string (optional (char '/') *> sep ~by:(char '/') aword) "a/b/c");;
eq ~printer:(errpp Q.Print.(string))
(Ok "abc") (parse_string (lookahead (string "ab") *> (string "abc")) "abcd");;
eq ~printer:(errpp Q.Print.(string))
(Ok "1234") (parse_string line_str "1234\nyolo");;
eq ~printer:(errpp Q.Print.(pair String.escaped String.escaped))
(Ok ("1234", "yolo")) (parse_string (line_str ||| line_str) "1234\nyolo\nswag");;
eq ~printer:(errpp Q.Print.(list string)) ~cmp:(erreq (=))
(Ok ["a";"b";"c";"d,e,f"])
(parse_string (split_list_at_most ~on_char:',' 3 >|= List.map Slice.to_string) "a,b,c,d,e,f");;
eq ~printer:(errpp Q.Print.(list string)) ~cmp:(erreq (=))
(Ok ["a";"bc"])
(parse_string (split_list_at_most ~on_char:',' 3 >|= List.map Slice.to_string) "a,bc");;
eq ~printer:(errpp Q.Print.(list @@ list int))
(Ok ([[1;1];[2;2];[3;3];[]]))
(parse_string (each_line (sep ~by:skip_space U.int)) "1 1\n2 2\n3 3\n");;
let eq' = eq ~printer:(errpp Q.Print.int) ~cmp:(erreq (=)) ;;
eq' (Ok 42) (parse_string U.int " 42");;
eq' (Ok 2) (parse_string U.int "2");;
eq' (Error "") (parse_string U.int "abc");;
eq' (Error "") (parse_string U.int "");;
let eq' = eq ~printer:(errpp Q.Print.int) ~cmp:(erreq (=));;
eq' (Ok 15) (parse_string (U.in_paren (U.in_paren U.int)) "( ( 15) )");;
eq' (Ok 2) (parse_string (U.in_paren U.int) "(2)");;
eq' (Error "") (parse_string (U.in_paren U.int) "2");;
eq' (Error "") (parse_string (U.in_paren U.int) "");;
eq' (Ok 2) (parse_string (U.in_parens_opt U.int) "((((2))))");;
eq' (Ok 2) (parse_string (U.in_parens_opt U.int) "2");;
eq' (Ok 200) (parse_string (U.in_parens_opt U.int) "( ( 200 ) )");;
let eq' = eq ~printer:(errpp Q.Print.(option int)) ~cmp:(erreq (=));;
eq' (Ok (Some 12)) (parse_string U.(option int) " Some 12");;
eq' (Ok None) (parse_string U.(option int) " None");;
eq' (Ok (Some 0)) (parse_string U.(option int) "Some 0");;
eq' (Ok (Some 0)) (parse_string U.(in_parens_opt @@ option int) "(( Some 0) )");;
let eq' = eq ~printer:(errpp Q.Print.int) ~cmp:(erreq (=)) ;;
eq' (Ok 16) (parse_string U.hexa_int "0x10");;
eq' (Ok 16) (parse_string U.hexa_int "10");;
eq' (Error "") (parse_string U.hexa_int "x10");;
eq' (Error "") (parse_string U.hexa_int "0xz");;
eq ~printer:(errpp Q.Print.bool) ~cmp:(erreq (=))
(Ok true) (parse_string U.bool "true");;
eq ~printer:(errpp Q.Print.bool) ~cmp:(erreq (=))
(Ok false) (parse_string U.bool "false");;
eq ~printer:Q.Print.(errpp (pair int int))
(Ok(1,2)) U.(parse_string (pair int int) "(1 , 2 )");;