#light type range = int * int type input = string * int type token = | Char of char | Identifier of string | Node of string * token list | Digit of token list type rule = input -> (input * token list) option let (||) r1 r2 a = match r1 a with | None -> r2 a | Some b -> Some b let after res = function | None -> None | Some (a, res') -> Some (a, res' @ res) let (&&) r1 r2 a = match r1 a with | None -> None | Some (a', res) -> after res (r2 a') let char c (str:string, pos) = try if str.[pos] = c then Some ((str, pos + 1), [Char c]) else None with _ -> None let rec loop rule a = (rule && loop rule || rule) a let nnode c rule a = match rule a with | None -> None | Some (a', res) -> Some (a', [c (res)]) let bin = let digit = char '0' || char '1' in nnode (function x -> Digit x) (loop digit)