Convenience combinators
Section titled “Convenience combinators”Convenience combinators provide ready-to-use parsers for common patterns like digits, letters, and whitespace.
Character classes
Section titled “Character classes”Parseff.digit parses a decimal digit (0-9) and returns its integer value.
val digit : unit -> int(* Parse two-digit number *)let two_digits () = let a = Parseff.digit () in let b = Parseff.digit () in a * 10 + b
(* Matches "42" -> 42 *)letter
Section titled “letter”Parseff.letter parses an ASCII letter (a-z or A-Z).
val letter : unit -> charlet initial () = Parseff.letter ()
(* Matches "A" -> 'A' *)(* Matches "z" -> 'z' *)(* Fails on "1" *)alphanum
Section titled “alphanum”Parseff.alphanum parses an alphanumeric character (letter or digit).
val alphanum : unit -> charlet username () = let first = Parseff.letter () in let rest = Parseff.many Parseff.alphanum () in String.make 1 first ^ String.of_seq (List.to_seq rest)
(* Matches "user123" -> "user123" *)(* Fails on "123user" (must start with letter) *)any_char
Section titled “any_char”Parseff.any_char parses any character. Fails only at end of input.
val any_char : unit -> char(* Skip past a single unknown character *)let skip_one () = let _ = Parseff.any_char () in ()
(* Peek at the next character without consuming it *)let peek () = Parseff.look_ahead Parseff.any_charWhitespace
Section titled “Whitespace”is_whitespace
Section titled “is_whitespace”Parseff.is_whitespace returns true for whitespace characters (space, tab, newline, carriage return). This is a predicate, not a parser.
val is_whitespace : char -> boollet trim_parser () = Parseff.skip_while Parseff.is_whitespace; let value = Parseff.take_while1 (fun c -> not (Parseff.is_whitespace c)) ~label:"value" in Parseff.skip_while Parseff.is_whitespace; value
(* Matches " hello " -> "hello" *)whitespace
Section titled “whitespace”Parseff.whitespace parses zero or more whitespace characters. Returns the matched string. Always succeeds (returns empty string if no whitespace).
val whitespace : unit -> stringlet spaced_values () = let a = Parseff.digit () in let _ = Parseff.whitespace () in let b = Parseff.digit () in (a, b)
(* Matches "1 2" -> (1, 2) *)(* Matches "1 2" -> (1, 2) *)(* Matches "12" -> (1, 2) *)whitespace1
Section titled “whitespace1”Parseff.whitespace1 parses one or more whitespace characters. Fails if no whitespace found.
val whitespace1 : unit -> stringlet words () = Parseff.sep_by1 (fun () -> Parseff.take_while1 (fun c -> not (Parseff.is_whitespace c)) ~label:"word") (fun () -> Parseff.whitespace1 ()) ()
(* Matches "hello world" -> ["hello"; "world"] *)(* Fails on "helloworld" (no whitespace separator) *)skip_whitespace
Section titled “skip_whitespace”Parseff.skip_whitespace skips zero or more whitespace characters (returns unit). More efficient than Parseff.whitespace when you don’t need the matched string.
val skip_whitespace : unit -> unit(* Parse comma-separated list with flexible spacing *)let flexible_list () = let _ = Parseff.char '[' in Parseff.skip_whitespace (); let values = Parseff.sep_by (fun () -> Parseff.skip_whitespace (); let n = Parseff.digit () in Parseff.skip_whitespace (); n) (fun () -> Parseff.char ',') () in Parseff.skip_whitespace (); let _ = Parseff.char ']' in values
(* All of these parse to [1; 2; 3]: *)(* "[1,2,3]" *)(* "[ 1 , 2 , 3 ]" *)(* "[ 1 , 2 , 3 ]" *)(* allocates a string you don't need *)let _ = Parseff.whitespace () inparse_value ()
(* skips without allocating *)Parseff.skip_whitespace ();parse_value ()