This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
688
unikernel/duniverse/angstrom/lib/angstrom.mli
Normal file
688
unikernel/duniverse/angstrom/lib/angstrom.mli
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
(*----------------------------------------------------------------------------
|
||||
Copyright (c) 2016 Inhabited Type LLC.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the author nor the names of his contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------------*)
|
||||
|
||||
(** Parser combinators built for speed and memory-efficiency.
|
||||
|
||||
Angstrom is a parser-combinator library that provides monadic and
|
||||
applicative interfaces for constructing parsers with unbounded lookahead.
|
||||
Its parsers can consume input incrementally, whether in a blocking or
|
||||
non-blocking environment. To achieve efficient incremental parsing,
|
||||
Angstrom offers both a buffered and unbuffered interface to input streams,
|
||||
with the {!module:Unbuffered} interface enabling zero-copy IO. With these
|
||||
features and low-level iteration parser primitives like {!take_while} and
|
||||
{!skip_while}, Angstrom makes it easy to write efficient, expressive, and
|
||||
reusable parsers suitable for high-performance applications. *)
|
||||
|
||||
|
||||
type +'a t
|
||||
(** A parser for values of type ['a]. *)
|
||||
|
||||
|
||||
type bigstring = Bigstringaf.t
|
||||
|
||||
(** {2 Basic parsers} *)
|
||||
|
||||
val peek_char : char option t
|
||||
(** [peek_char] accepts any char and returns it, or returns [None] if the end
|
||||
of input has been reached.
|
||||
|
||||
This parser does not advance the input. Use it for lookahead. *)
|
||||
|
||||
val peek_char_fail : char t
|
||||
(** [peek_char_fail] accepts any char and returns it. If end of input has been
|
||||
reached, it will fail.
|
||||
|
||||
This parser does not advance the input. Use it for lookahead. *)
|
||||
|
||||
val peek_string : int -> string t
|
||||
(** [peek_string n] accepts exactly [n] characters and returns them as a
|
||||
string. If there is not enough input, it will fail.
|
||||
|
||||
This parser does not advance the input. Use it for lookahead. *)
|
||||
|
||||
val char : char -> char t
|
||||
(** [char c] accepts [c] and returns it. *)
|
||||
|
||||
val not_char : char -> char t
|
||||
(** [not_char] accepts any character that is not [c] and returns the matched
|
||||
character. *)
|
||||
|
||||
val any_char : char t
|
||||
(** [any_char] accepts any character and returns it. *)
|
||||
|
||||
val satisfy : (char -> bool) -> char t
|
||||
(** [satisfy f] accepts any character for which [f] returns [true] and
|
||||
returns the accepted character. In the case that none of the parser
|
||||
succeeds, then the parser will fail indicating the offending
|
||||
character. *)
|
||||
|
||||
val string : string -> string t
|
||||
(** [string s] accepts [s] exactly and returns it. *)
|
||||
|
||||
val string_ci : string -> string t
|
||||
(** [string_ci s] accepts [s], ignoring case, and returns the matched string,
|
||||
preserving the case of the original input. *)
|
||||
|
||||
val skip : (char -> bool) -> unit t
|
||||
(** [skip f] accepts any character for which [f] returns [true] and discards
|
||||
the accepted character. [skip f] is equivalent to [satisfy f] but discards
|
||||
the accepted character. *)
|
||||
|
||||
val skip_while : (char -> bool) -> unit t
|
||||
(** [skip_while f] accepts input as long as [f] returns [true] and discards
|
||||
the accepted characters. *)
|
||||
|
||||
val take : int -> string t
|
||||
(** [take n] accepts exactly [n] characters of input and returns them as a
|
||||
string. *)
|
||||
|
||||
val take_while : (char -> bool) -> string t
|
||||
(** [take_while f] accepts input as long as [f] returns [true] and returns the
|
||||
accepted characters as a string.
|
||||
|
||||
This parser does not fail. If [f] returns [false] on the first character,
|
||||
it will return the empty string. *)
|
||||
|
||||
val take_while1 : (char -> bool) -> string t
|
||||
(** [take_while1 f] accepts input as long as [f] returns [true] and returns the
|
||||
accepted characters as a string.
|
||||
|
||||
This parser requires that [f] return [true] for at least one character of
|
||||
input, and will fail otherwise. *)
|
||||
|
||||
val take_till : (char -> bool) -> string t
|
||||
(** [take_till f] accepts input as long as [f] returns [false] and returns the
|
||||
accepted characters as a string.
|
||||
|
||||
This parser does not fail. If [f] returns [true] on the first character, it
|
||||
will return the empty string. *)
|
||||
|
||||
val consumed : _ t -> string t
|
||||
(** [consumed p] runs [p] and returns the contents that were consumed during the
|
||||
parsing as a string *)
|
||||
|
||||
val take_bigstring : int -> bigstring t
|
||||
(** [take_bigstring n] accepts exactly [n] characters of input and returns them
|
||||
as a newly allocated bigstring. *)
|
||||
|
||||
val take_bigstring_while : (char -> bool) -> bigstring t
|
||||
(** [take_bigstring_while f] accepts input as long as [f] returns [true] and
|
||||
returns the accepted characters as a newly allocated bigstring.
|
||||
|
||||
This parser does not fail. If [f] returns [false] on the first character,
|
||||
it will return the empty bigstring. *)
|
||||
|
||||
val take_bigstring_while1 : (char -> bool) -> bigstring t
|
||||
(** [take_bigstring_while1 f] accepts input as long as [f] returns [true] and
|
||||
returns the accepted characters as a newly allocated bigstring.
|
||||
|
||||
This parser requires that [f] return [true] for at least one character of
|
||||
input, and will fail otherwise. *)
|
||||
|
||||
val take_bigstring_till : (char -> bool) -> bigstring t
|
||||
(** [take_bigstring_till f] accepts input as long as [f] returns [false] and
|
||||
returns the accepted characters as a newly allocated bigstring.
|
||||
|
||||
This parser does not fail. If [f] returns [true] on the first character, it
|
||||
will return the empty bigstring. *)
|
||||
|
||||
val consumed_bigstring : _ t -> bigstring t
|
||||
(** [consumed p] runs [p] and returns the contents that were consumed during the
|
||||
parsing as a bigstring *)
|
||||
|
||||
val advance : int -> unit t
|
||||
(** [advance n] advances the input [n] characters, failing if the remaining
|
||||
input is less than [n]. *)
|
||||
|
||||
val end_of_line : unit t
|
||||
(** [end_of_line] accepts either a line feed [\n], or a carriage return
|
||||
followed by a line feed [\r\n] and returns unit. *)
|
||||
|
||||
val at_end_of_input : bool t
|
||||
(** [at_end_of_input] returns whether the end of the end of input has been
|
||||
reached. This parser always succeeds. *)
|
||||
|
||||
val end_of_input : unit t
|
||||
(** [end_of_input] succeeds if all the input has been consumed, and fails
|
||||
otherwise. *)
|
||||
|
||||
val scan : 'state -> ('state -> char -> 'state option) -> (string * 'state) t
|
||||
(** [scan init f] consumes until [f] returns [None]. Returns the final state
|
||||
before [None] and the accumulated string *)
|
||||
|
||||
val scan_state : 'state -> ('state -> char -> 'state option) -> 'state t
|
||||
(** [scan_state init f] is like {!scan} but only returns the final state before
|
||||
[None]. Much more efficient than {!scan}. *)
|
||||
|
||||
val scan_string : 'state -> ('state -> char -> 'state option) -> string t
|
||||
(** [scan_string init f] is like {!scan} but discards the final state and returns
|
||||
the accumulated string. *)
|
||||
|
||||
val int8 : int -> int t
|
||||
(** [int8 i] accepts one byte that matches the lower-order byte of [i] and
|
||||
returns unit. *)
|
||||
|
||||
val any_uint8 : int t
|
||||
(** [any_uint8] accepts any byte and returns it as an unsigned int8. *)
|
||||
|
||||
val any_int8 : int t
|
||||
(** [any_int8] accepts any byte and returns it as a signed int8. *)
|
||||
|
||||
(** Big endian parsers *)
|
||||
module BE : sig
|
||||
val int16 : int -> unit t
|
||||
(** [int16 i] accept two bytes that match the two lower order bytes of [i]
|
||||
and returns unit. *)
|
||||
|
||||
val int32 : int32 -> unit t
|
||||
(** [int32 i] accept four bytes that match the four bytes of [i]
|
||||
and returns unit. *)
|
||||
|
||||
val int64 : int64 -> unit t
|
||||
(** [int64 i] accept eight bytes that match the eight bytes of [i] and
|
||||
returns unit. *)
|
||||
|
||||
val any_int16 : int t
|
||||
val any_int32 : int32 t
|
||||
val any_int64 : int64 t
|
||||
(** [any_intN] reads [N] bits and interprets them as big endian signed integers. *)
|
||||
|
||||
val any_uint16 : int t
|
||||
(** [any_uint16] reads [16] bits and interprets them as a big endian unsigned
|
||||
integer. *)
|
||||
|
||||
val any_float : float t
|
||||
(** [any_float] reads 32 bits and interprets them as a big endian floating
|
||||
point value. *)
|
||||
|
||||
val any_double : float t
|
||||
(** [any_double] reads 64 bits and interprets them as a big endian floating
|
||||
point value. *)
|
||||
end
|
||||
|
||||
(** Little endian parsers *)
|
||||
module LE : sig
|
||||
val int16 : int -> unit t
|
||||
(** [int16 i] accept two bytes that match the two lower order bytes of [i]
|
||||
and returns unit. *)
|
||||
|
||||
val int32 : int32 -> unit t
|
||||
(** [int32 i] accept four bytes that match the four bytes of [i]
|
||||
and returns unit. *)
|
||||
|
||||
val int64 : int64 -> unit t
|
||||
(** [int32 i] accept eight bytes that match the eight bytes of [i] and
|
||||
returns unit. *)
|
||||
|
||||
val any_int16 : int t
|
||||
val any_int32 : int32 t
|
||||
val any_int64 : int64 t
|
||||
(** [any_intN] reads [N] bits and interprets them as little endian signed
|
||||
integers. *)
|
||||
|
||||
val any_uint16 : int t
|
||||
(** [uint16] reads [16] bits and interprets them as a little endian unsigned
|
||||
integer. *)
|
||||
|
||||
val any_float : float t
|
||||
(** [any_float] reads 32 bits and interprets them as a little endian floating
|
||||
point value. *)
|
||||
|
||||
val any_double : float t
|
||||
(** [any_double] reads 64 bits and interprets them as a little endian floating
|
||||
point value. *)
|
||||
end
|
||||
|
||||
|
||||
(** {2 Combinators} *)
|
||||
|
||||
val option : 'a -> 'a t -> 'a t
|
||||
(** [option v p] runs [p], returning the result of [p] if it succeeds and [v]
|
||||
if it fails. *)
|
||||
|
||||
|
||||
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||
(** [both p q] runs [p] followed by [q] and returns both results in a tuple *)
|
||||
|
||||
val list : 'a t list -> 'a list t
|
||||
(** [list ps] runs each [p] in [ps] in sequence, returning a list of results of
|
||||
each [p]. *)
|
||||
|
||||
val count : int -> 'a t -> 'a list t
|
||||
(** [count n p] runs [p] [n] times, returning a list of the results. *)
|
||||
|
||||
val many : 'a t -> 'a list t
|
||||
(** [many p] runs [p] {i zero} or more times and returns a list of results from
|
||||
the runs of [p]. *)
|
||||
|
||||
val many1 : 'a t -> 'a list t
|
||||
(** [many1 p] runs [p] {i one} or more times and returns a list of results from
|
||||
the runs of [p]. *)
|
||||
|
||||
val many_till : 'a t -> _ t -> 'a list t
|
||||
(** [many_till p e] runs parser [p] {i zero} or more times until action [e]
|
||||
succeeds and returns the list of result from the runs of [p]. *)
|
||||
|
||||
val sep_by : _ t -> 'a t -> 'a list t
|
||||
(** [sep_by s p] runs [p] {i zero} or more times, interspersing runs of [s] in between. *)
|
||||
|
||||
val sep_by1 : _ t -> 'a t -> 'a list t
|
||||
(** [sep_by1 s p] runs [p] {i one} or more times, interspersing runs of [s] in between. *)
|
||||
|
||||
val skip_many : _ t -> unit t
|
||||
(** [skip_many p] runs [p] {i zero} or more times, discarding the results. *)
|
||||
|
||||
val skip_many1 : _ t -> unit t
|
||||
(** [skip_many1 p] runs [p] {i one} or more times, discarding the results. *)
|
||||
|
||||
val fix : ('a t -> 'a t) -> 'a t
|
||||
(** [fix f] computes the fixpoint of [f] and runs the resultant parser. The
|
||||
argument that [f] receives is the result of [fix f], which [f] must use,
|
||||
paradoxically, to define [fix f].
|
||||
|
||||
[fix] is useful when constructing parsers for inductively-defined types
|
||||
such as sequences, trees, etc. Consider for example the implementation of
|
||||
the {!many} combinator defined in this library:
|
||||
|
||||
{[let many p =
|
||||
fix (fun m ->
|
||||
(cons <$> p <*> m) <|> return [])]}
|
||||
|
||||
[many p] is a parser that will run [p] zero or more times, accumulating the
|
||||
result of every run into a list, returning the result. It's defined by
|
||||
passing [fix] a function. This function assumes its argument [m] is a
|
||||
parser that behaves exactly like [many p]. You can see this in the
|
||||
expression comprising the left hand side of the alternative operator
|
||||
[<|>]. This expression runs the parser [p] followed by the parser [m], and
|
||||
after which the result of [p] is cons'd onto the list that [m] produces.
|
||||
The right-hand side of the alternative operator provides a base case for
|
||||
the combinator: if [p] fails and the parse cannot proceed, return an empty
|
||||
list.
|
||||
|
||||
Another way to illustrate the uses of [fix] is to construct a JSON parser.
|
||||
Assuming that parsers exist for the basic types such as [false], [true],
|
||||
[null], strings, and numbers, the question then becomes how to define a
|
||||
parser for objects and arrays? Both contain values that are themselves JSON
|
||||
values, so it seems as though it's impossible to write a parser that will
|
||||
accept JSON objects and arrays before writing a parser for JSON values as a
|
||||
whole.
|
||||
|
||||
This is the exact situation that [fix] was made for. By defining the
|
||||
parsers for arrays and objects within the function that you pass to [fix],
|
||||
you will gain access to a parser that you can use to parse JSON values, the
|
||||
very parser you are defining!
|
||||
|
||||
{[let json =
|
||||
fix (fun json ->
|
||||
let arr = char '[' *> sep_by (char ',') json <* char ']' in
|
||||
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} *)
|
||||
|
||||
val (<|>) : 'a t -> 'a t -> 'a t
|
||||
(** [p <|> q] runs [p] and returns the result if succeeds. If [p] fails, then
|
||||
the input will be reset and [q] will run instead. *)
|
||||
|
||||
val choice : ?failure_msg:string -> 'a t list -> 'a t
|
||||
(** [choice ?failure_msg ts] runs each parser in [ts] in order until one
|
||||
succeeds and returns that result. In the case that none of the parser
|
||||
succeeds, then the parser will fail with the message [failure_msg], if
|
||||
provided, or a much less informative message otherwise. *)
|
||||
|
||||
val (<?>) : 'a t -> string -> 'a t
|
||||
(** [p <?> name] associates [name] with the parser [p], which will be reported
|
||||
in the case of failure. *)
|
||||
|
||||
val commit : unit t
|
||||
(** [commit] prevents backtracking beyond the current position of the input,
|
||||
allowing the manager of the input buffer to reuse the preceding bytes for
|
||||
other purposes.
|
||||
|
||||
The {!module:Unbuffered} parsing interface will report directly to the
|
||||
caller the number of bytes committed to the when returning a
|
||||
{!Unbuffered.state.Partial} state, allowing the caller to reuse those bytes
|
||||
for any purpose. The {!module:Buffered} will keep track of the region of
|
||||
committed bytes in its internal buffer and reuse that region to store
|
||||
additional input when necessary. *)
|
||||
|
||||
|
||||
(** {2 Monadic/Applicative interface} *)
|
||||
|
||||
val return : 'a -> 'a t
|
||||
(** [return v] creates a parser that will always succeed and return [v] *)
|
||||
|
||||
val fail : string -> _ t
|
||||
(** [fail msg] creates a parser that will always fail with the message [msg] *)
|
||||
|
||||
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
||||
(** [p >>= f] creates a parser that will run [p], pass its result to [f], run
|
||||
the parser that [f] produces, and return its result. *)
|
||||
|
||||
val bind : 'a t -> f:('a -> 'b t) -> 'b t
|
||||
(** [bind] is a prefix version of [>>=] *)
|
||||
|
||||
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
|
||||
(** [p >>| f] creates a parser that will run [p], and if it succeeds with
|
||||
result [v], will return [f v] *)
|
||||
|
||||
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
||||
(** [f <*> p] is equivalent to [f >>= fun f -> p >>| f]. *)
|
||||
|
||||
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
|
||||
(** [f <$> p] is equivalent to [p >>| f] *)
|
||||
|
||||
val ( *>) : _ t -> 'a t -> 'a t
|
||||
(** [p *> q] runs [p], discards its result and then runs [q], and returns its
|
||||
result. *)
|
||||
|
||||
val (<* ) : 'a t -> _ t -> 'a t
|
||||
(** [p <* q] runs [p], then runs [q], discards its result, and returns the
|
||||
result of [p]. *)
|
||||
|
||||
val lift : ('a -> 'b) -> 'a t -> 'b t
|
||||
val lift2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
|
||||
val lift3 : ('a -> 'b -> 'c -> 'd) -> 'a t -> 'b t -> 'c t -> 'd t
|
||||
val lift4 : ('a -> 'b -> 'c -> 'd -> 'e) -> 'a t -> 'b t -> 'c t -> 'd t -> 'e t
|
||||
(** The [liftn] family of functions promote functions to the parser monad.
|
||||
For any of these functions, the following equivalence holds:
|
||||
|
||||
{[liftn f p1 ... pn = f <$> p1 <*> ... <*> pn]}
|
||||
|
||||
These functions are more efficient than using the applicative interface
|
||||
directly, mostly in terms of memory allocation but also in terms of speed.
|
||||
Prefer them over the applicative interface, even when the arity of the
|
||||
function to be lifted exceeds the maximum [n] for which there is an
|
||||
implementation for [liftn]. In other words, if [f] has an arity of [5] but
|
||||
only [lift4] is provided, do the following:
|
||||
|
||||
{[lift4 f m1 m2 m3 m4 <*> m5]}
|
||||
|
||||
Even with the partial application, it will be more efficient than the
|
||||
applicative implementation. *)
|
||||
|
||||
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
|
||||
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
|
||||
val map4 : 'a t -> 'b t -> 'c t -> 'd t -> f:('a -> 'b -> 'c -> 'd -> 'e) -> 'e t
|
||||
(** The [mapn] family of functions are just like [liftn], with a slightly
|
||||
different interface. *)
|
||||
|
||||
(** The [Let_syntax] module is intended to be used with the [ppx_let]
|
||||
pre-processor, and just contains copies of functions described elsewhere. *)
|
||||
module Let_syntax : sig
|
||||
val return : 'a -> 'a t
|
||||
val ( >>| ) : 'a t -> ('a -> 'b) -> 'b t
|
||||
val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t
|
||||
|
||||
module Let_syntax : sig
|
||||
val return : 'a -> 'a t
|
||||
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||
val bind : 'a t -> f:('a -> 'b t) -> 'b t
|
||||
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
|
||||
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
|
||||
val map4 : 'a t -> 'b t -> 'c t -> 'd t -> f:('a -> 'b -> 'c -> 'd -> 'e) -> 'e t
|
||||
end
|
||||
end
|
||||
|
||||
val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
|
||||
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
|
||||
val ( and+ ) : 'a t -> 'b t -> ('a * 'b) t
|
||||
|
||||
(** Unsafe Operations on Angstrom's Internal Buffer
|
||||
|
||||
These functions are considered {b unsafe} as they expose the input buffer
|
||||
to client code without any protections against modification, or leaking
|
||||
references. They are exposed to support performance-sensitive parsers that
|
||||
want to avoid allocation at all costs. Client code should take care to
|
||||
write the input buffer callback functions such that they:
|
||||
|
||||
{ul
|
||||
{- do not modify the input buffer {i outside} of the range
|
||||
[\[off, off + len)];}
|
||||
{- do not modify the input buffer {i inside} of the range
|
||||
[\[off, off + len)] if the parser might backtrack; and}
|
||||
{- do not return any direct or indirect references to the input buffer.}}
|
||||
|
||||
If the input buffer callback functions do not do any of these things, then
|
||||
the client may consider their use safe. *)
|
||||
module Unsafe : sig
|
||||
|
||||
val take : int -> (bigstring -> off:int -> len:int -> 'a) -> 'a t
|
||||
(** [take n f] accepts exactly [n] characters of input into the parser's
|
||||
internal buffer then calls [f buffer ~off ~len]. [buffer] is the
|
||||
parser's internal buffer. [off] is the offset from the start of [buffer]
|
||||
containing the requested content. [len] is the length of the requested
|
||||
content. [len] is guaranteed to be equal to [n]. *)
|
||||
|
||||
val take_while : (char -> bool) -> (bigstring -> off:int -> len:int -> 'a) -> 'a t
|
||||
(** [take_while check f] accepts input into the parser's interal buffer as
|
||||
long as [check] returns [true] then calls [f buffer ~off ~len]. [buffer]
|
||||
is the parser's internal buffer. [off] is the offset from the start of
|
||||
[buffer] containing the requested content. [len] is the length of the
|
||||
content matched by [check].
|
||||
|
||||
This parser does not fail. If [check] returns [false] on the first
|
||||
character, [len] will be [0]. *)
|
||||
|
||||
val take_while1 : (char -> bool) -> (bigstring -> off:int -> len:int -> 'a) -> 'a t
|
||||
(** [take_while1 check f] accepts input into the parser's interal buffer as
|
||||
long as [check] returns [true] then calls [f buffer ~off ~len]. [buffer]
|
||||
is the parser's internal buffer. [off] is the offset from the start of
|
||||
[buffer] containing the requested content. [len] is the length of the
|
||||
content matched by [check].
|
||||
|
||||
This parser requires that [f] return [true] for at least one character of
|
||||
input, and will fail otherwise. *)
|
||||
|
||||
val take_till : (char -> bool) -> (bigstring -> off:int -> len:int -> 'a) -> 'a t
|
||||
(** [take_till check f] accepts input into the parser's interal buffer as
|
||||
long as [check] returns [false] then calls [f buffer ~off ~len]. [buffer]
|
||||
is the parser's internal buffer. [off] is the offset from the start of
|
||||
[buffer] containing the requested content. [len] is the length of the
|
||||
content matched by [check].
|
||||
|
||||
This parser does not fail. If [check] returns [true] on the first
|
||||
character, [len] will be [0]. *)
|
||||
|
||||
val peek : int -> (bigstring -> off:int -> len:int -> 'a) -> 'a t
|
||||
(** [peek n ~f] accepts exactly [n] characters and calls [f buffer ~off ~len]
|
||||
with [len = n]. If there is not enough input, it will fail.
|
||||
|
||||
This parser does not advance the input. Use it for lookahead. *)
|
||||
end
|
||||
|
||||
|
||||
(** {2 Running} *)
|
||||
|
||||
module Consume : sig
|
||||
type t =
|
||||
| Prefix
|
||||
| All
|
||||
end
|
||||
|
||||
val parse_bigstring : consume:Consume.t -> 'a t -> bigstring -> ('a, string) result
|
||||
|
||||
(** [parse_bigstring ~consume t bs] runs [t] on [bs]. The parser will receive
|
||||
an [`Eof] after all of [bs] has been consumed. Passing {!Prefix} in the
|
||||
[consume] argument allows the parse to successfully complete without
|
||||
reaching eof. To require the parser to reach eof, pass {!All} in the
|
||||
[consume] argument.
|
||||
|
||||
For use-cases requiring that the parser be fed input incrementally, see the
|
||||
{!module:Buffered} and {!module:Unbuffered} modules below. *)
|
||||
|
||||
|
||||
val parse_string : consume:Consume.t -> 'a t -> string -> ('a, string) result
|
||||
(** [parse_string ~consume t bs] runs [t] on [bs]. The parser will receive an
|
||||
[`Eof] after all of [bs] has been consumed. Passing {!Prefix} in the
|
||||
[consume] argument allows the parse to successfully complete without
|
||||
reaching eof. To require the parser to reach eof, pass {!All} in the
|
||||
[consume] argument.
|
||||
|
||||
For use-cases requiring that the parser be fed input incrementally, see the
|
||||
{!module:Buffered} and {!module:Unbuffered} modules below. *)
|
||||
|
||||
|
||||
(** Buffered parsing interface.
|
||||
|
||||
Parsers run through this module perform internal buffering of input. The
|
||||
parser state will keep track of unconsumed input and attempt to minimize
|
||||
memory allocation and copying. The {!Buffered.state.Partial} parser state
|
||||
will accept newly-read, incremental input and copy it into the internal
|
||||
buffer. Users can feed parser states using the {!feed} function. As a
|
||||
result, the interface is much easier to use than the one exposed by the
|
||||
{!Unbuffered} module.
|
||||
|
||||
On success or failure, any unconsumed input will be returned to the user
|
||||
for additional processing. The buffer that the unconsumed input is returned
|
||||
in can also be reused. *)
|
||||
module Buffered : sig
|
||||
type unconsumed =
|
||||
{ buf : bigstring
|
||||
; off : int
|
||||
; len : int }
|
||||
|
||||
type input =
|
||||
[ `Bigstring of bigstring
|
||||
| `String of string ]
|
||||
|
||||
type 'a state =
|
||||
| Partial of ([ input | `Eof ] -> 'a state) (** The parser requires more input. *)
|
||||
| Done of unconsumed * 'a (** The parser succeeded. *)
|
||||
| Fail of unconsumed * string list * string (** The parser failed. *)
|
||||
|
||||
val parse : ?initial_buffer_size:int -> 'a t -> 'a state
|
||||
(** [parse ?initial_buffer_size t] runs [t] and awaits input if needed.
|
||||
[parse] will allocate a buffer of size [initial_buffer_size] (defaulting
|
||||
to 4k bytes) to do input buffering and automatically grows the buffer as
|
||||
needed. *)
|
||||
|
||||
val feed : 'a state -> [ input | `Eof ] -> 'a state
|
||||
(** [feed state input] supplies the parser state with more input. If [state] is
|
||||
[Partial], then parsing will continue where it left off. Otherwise, the
|
||||
parser is in a [Fail] or [Done] state, in which case the [input] will be
|
||||
copied into the state's buffer for later use by the caller. *)
|
||||
|
||||
val state_to_option : 'a state -> 'a option
|
||||
(** [state_to_option state] returns [Some v] if the parser is in the
|
||||
[Done (bs, v)] state and [None] otherwise. This function has no effect on
|
||||
the current state of the parser. *)
|
||||
|
||||
val state_to_result : 'a state -> ('a, string) result
|
||||
(** [state_to_result state] returns [Ok v] if the parser is in the [Done (bs, v)]
|
||||
state and [Error msg] if it is in the [Fail] or [Partial] state.
|
||||
|
||||
This function has no effect on the current state of the parser. *)
|
||||
|
||||
val state_to_unconsumed : _ state -> unconsumed option
|
||||
(** [state_to_unconsumed state] returns [Some bs] if [state = Done(bs, _)] or
|
||||
[state = Fail(bs, _, _)] and [None] otherwise. *)
|
||||
|
||||
end
|
||||
|
||||
(** Unbuffered parsing interface.
|
||||
|
||||
Use this module for total control over memory allocation and copying.
|
||||
Parsers run through this module perform no internal buffering. Instead, the
|
||||
user is responsible for managing a buffer containing the entirety of the
|
||||
input that has yet to be consumed by the parser. The
|
||||
{!Unbuffered.state.Partial} parser state reports to the user how much input
|
||||
the parser consumed during its last run, via the
|
||||
{!Unbuffered.partial.committed} field. This area of input must be discarded
|
||||
before parsing can resume. Once additional input has been collected, the
|
||||
unconsumed input as well as new input must be passed to the parser state
|
||||
via the {!Unbuffered.partial.continue} function, together with an
|
||||
indication of whether there is {!Unbuffered.more} input to come.
|
||||
|
||||
The logic that must be implemented in order to make proper use of this
|
||||
module is intricate and tied to your OS environment. It's advisable to use
|
||||
the {!Buffered} module when initially developing and testing your parsers.
|
||||
For production use-cases, consider the Async and Lwt support that this
|
||||
library includes before attempting to use this module directly. *)
|
||||
module Unbuffered : sig
|
||||
type more =
|
||||
| Complete
|
||||
| Incomplete
|
||||
|
||||
type 'a state =
|
||||
| Partial of 'a partial (** The parser requires more input. *)
|
||||
| Done of int * 'a (** The parser succeeded, consuming specified bytes. *)
|
||||
| Fail of int * string list * string (** The parser failed, consuming specified bytes. *)
|
||||
and 'a partial =
|
||||
{ committed : int
|
||||
(** The number of bytes committed during the last input feeding.
|
||||
Callers must drop this number of bytes from the beginning of the
|
||||
input on subsequent calls. See {!commit} for additional details. *)
|
||||
; continue : bigstring -> off:int -> len:int -> more -> 'a state
|
||||
(** A continuation of a parse that requires additional input. The input
|
||||
should include all uncommitted input (as reported by previous partial
|
||||
states) in addition to any new input that has become available, as
|
||||
well as an indication of whether there is {!more} input to come. *)
|
||||
}
|
||||
|
||||
val parse : 'a t -> 'a state
|
||||
(** [parse t] runs [t] and await input if needed. *)
|
||||
|
||||
val state_to_option : 'a state -> 'a option
|
||||
|
||||
(** [state_to_option state] returns [Some v] if the parser is in the
|
||||
[Done (bs, v)] state and [None] otherwise. This function has no effect on the
|
||||
current state of the parser. *)
|
||||
|
||||
val state_to_result : 'a state -> ('a, string) result
|
||||
(** [state_to_result state] returns [Ok v] if the parser is in the
|
||||
[Done (bs, v)] state and [Error msg] if it is in the [Fail] or [Partial]
|
||||
state.
|
||||
|
||||
This function has no effect on the current state of the parser. *)
|
||||
end
|
||||
|
||||
(** {2 Expert Parsers}
|
||||
|
||||
For people that know what they're doing. If you want to use them, read the
|
||||
code. No further documentation will be provided. *)
|
||||
|
||||
val pos : int t
|
||||
val available : int t
|
||||
Loading…
Add table
Add a link
Reference in a new issue