diff --git a/lib/angstrom.ml b/lib/angstrom.ml index b025121..241d052 100644 --- a/lib/angstrom.ml +++ b/lib/angstrom.ml @@ -461,8 +461,7 @@ let fix_direct f = in r -let fix_lazy f = - let max_steps = 20 in +let fix_lazy ~max_steps f = let steps = ref max_steps in let rec p = lazy (f r) and r = { run = fun buf pos more fail succ -> @@ -480,7 +479,7 @@ let fix_lazy f = let fix = match Sys.backend_type with | Native -> fix_direct | Bytecode -> fix_direct - | Other _ -> fix_lazy + | Other _ -> fun f -> fix_lazy ~max_steps:20 f let option x p = p <|> return x @@ -493,9 +492,9 @@ let rec list ps = | p::ps -> lift2 cons p (list ps) let count n p = - if n < 0 + if n < 0 then fail "count: n < 0" - else + else let rec loop = function | 0 -> return [] | n -> lift2 cons p (loop (n - 1)) diff --git a/lib/angstrom.mli b/lib/angstrom.mli index 6f9a4c1..d669595 100644 --- a/lib/angstrom.mli +++ b/lib/angstrom.mli @@ -348,6 +348,15 @@ val fix : ('a t -> 'a t) -> 'a t let obj = char '{' *> ... json ... <* char '}' in choice [str; num; arr json, ...])]} *) +(** [fix_lazy] is like [fix], but after the function reaches [max_steps] + deep, it wraps up the remaining computation and yields + back to the root of the parsing loop where it continues from there. + + This is an effective way to break up the stack trace into more managable + chunks, which is important for Js_of_ocaml due to the lack of tailrec + optimizations for CPS-style tail calls. When compiling for Js_of_ocaml, + [fix] itself is defined as [fix_lazy ~max_steps:20]. *) +val fix_lazy : max_steps:int -> ('a t -> 'a t) -> 'a t (** {2 Alternatives} *) diff --git a/lib_test/test_json.ml b/lib_test/test_json.ml index 98b8a8c..96d720e 100644 --- a/lib_test/test_json.ml +++ b/lib_test/test_json.ml @@ -14,6 +14,6 @@ let read f = let () = let twitter_big = read Sys.argv.(1) in - match Angstrom.(parse_bigstring RFC7159.json twitter_big) with + match Angstrom.(parse_bigstring ~consume:Consume.Prefix RFC7159.json twitter_big) with | Ok _ -> () | Error err -> failwith err