Source

planck / planck_intf.ml

open Spotlib.Spot

module type S = sig
  module Str : Stream_intf.S
  (** Underlied stream *)

  type error = Str.Pos.t * string

  exception Critical_error of error
  (** Exception of critical error. Used for non recoverable errors. *)

  module Profile : sig
    val incr : unit -> unit
    val format : Format.t -> unit
    val reset : unit -> unit
    val recover_all : unit -> unit (* format will print the over all result *)
  end

  type param = Str.t
  type +'a result = ('a * Str.t, error) Result.t 

  include Monad_intf.T with type 'a t = param -> 'a result
  (** Monadic interface. ['a t] is a function, so \eta expandable *)

  (** Parser combinators *)

  val take : Str.elem t
  val take_ : unit t
  (** Take the head token.

      [take_] is the same as [take], but the element is ignored. Following Haskell xxxM_ convention.
  *)

  val stream : Str.t t
  (** return the underlying stream of the current position *)

  val set_stream : Str.t -> unit t
  (** change the underlying stream *)

  val position : Str.Pos.t t
  (** Returns the position of the head token in the stream. *)

  val error : string -> 'a t
  (** [error mes] fails with the error message [mes].
      The error can be covered by other combinators like [<|>] and [<!>].
  *)

  val throw : error -> 'a t

  val critical_error : Str.Pos.t -> string -> 'a t
  (** Raise the critical error exception. The exception must be caught by [try ... with].

      Note: The exception is raised when the monad is executed.
      Therefore, it cannot be caught at the monad construction time. It must be caught at the execution.
  *)

  val throw : error -> 'a t
  (** same as [error] but with position *)

  val eos : unit t
  (** Matches with End Of Stream *)

  val token : Str.elem -> unit t
  (** [token e] matches with the token [e] *)

  val tokenp : (Str.elem -> bool) -> Str.elem t
  (** [tokenp p] matches with the token [e] where [p e = true]. *)

  val token_option : (Str.elem -> 'a option) -> 'a t
  (** [token_option f] matches with the token [e] where [f e = Some v] for some [v], and  returns [v]. *)

  val token_result : (Str.elem -> ('a, string) Result.t) -> 'a t
  (** Same as [token_option] but with customizable error messages *)

  val one_of : Str.elem list -> Str.elem t

  val tokens : Str.elem list -> unit t
  (** Tail rec. Faster than using sequence of token *)

  val option : 'a t -> 'a option t
  val option_ : unit t -> unit t
  val result : 'a t -> ('a, error) Result.t t

  val try_finally : 'a t -> (('a, error) Result.t -> unit) -> 'a t
  (** [try_finally t f] performs [t] then run [f] over the result of [t].
      The result of the expression is the result of [t].
  *)

  val surrounded : 'a t -> 'b t -> 'c t -> 'c t
  (** ['b t] must not accept ['c t] *)

  val list_with_sep : ?optional_head:bool -> sep:unit t -> 'a t -> 'a list t

  (** `*' and `+' operators of Regexp

      NOTE: It is without backtrack:
      [?* (token A) >>= fun () -> token A] does not match AAA, since [?* (token A)] eats all the AAA,
      and nothing is left for the latter [token A].
  *)
  val ( ?** ) : 'a t -> 'a list t
  val ( ?* )  : 'a t -> unit t
  val ( ?++ ) : 'a t -> 'a list t
  val ( ?+ )  : 'a t -> unit t

  val critical : 'a t -> 'a t
  (** If [t] fails, [critical t] reports its error as a critical error exception *)

  val ( <?!> ) : 'a t -> string -> 'a t
  (** Enrich error: [m <?!> mes] returns an error message [mes] at error *)

  val ( <?> ) : 'a t -> string -> 'a t
  (** Enrich error: [m <?> mes] returns an error message ["expected " ^ mes] at error *)

  val ( <?@> ) : 'a t -> Str.Pos.t -> 'a t
  (** [m <?@> pos] changes the position of error of [m] to [pos], if happens *)

  val ( <|> ) : 'a t -> 'a t -> 'a t
  (** Parsec's <|>. The right is tried only when the left fails without consuming any input *)

  val try_ : 'a t -> 'a t
  (** Parsec's try *)

  (** With backtracks *)
  val ( <!> ) : 'a t -> 'a t -> 'a t
  (** Unlike [<|>], it performs full backtracks.
      (try_ a <|> b) == (a <!> b)
  *)

  val eos_as_none : 'a t -> 'a option t
  (** End of stream is reported as None *)

  val ( <&> ) : 'a t -> ('a -> 'b t) -> 'b t
  (** For push back. [t <&> f] is like [t >>= f], but the result monad's stream position
      is the same as [t]. *)

  (** Regex style operators *)

  val ( /**/ ) : 'a list t -> 'a list t -> 'a list t
    (** not tail rec *)
  val ( /*/ ) : unit t -> unit t -> unit t
  val ( /++/ ) : 'a list t -> 'a list t -> 'a list t
    (** not tail rec *)
  val ( /+/ ) : unit t -> unit t -> unit t
  val ( /?/ ) : 'a list t -> 'a list t -> 'a list t

  val begin_with : 'a t -> 'b t -> 'b option t
  (** [begin_with b w]: if [b] matches then try [w] and returns [w]'s result.
      Otherwise, it returns [None]. *)

  val run : 'a t -> Str.t -> ('a * Str.t, error) Result.t
  (** Run the monad over the stream *)
end