ligo/vendors/ligo-utils/simple-utils/region.mli
2020-01-20 10:57:07 +01:00

146 lines
4.8 KiB
OCaml

(** Regions of a file
A {e region} is a contiguous series of bytes, for example, in a
text file. It is here denoted by the object type [t].
*)
(** {1 Definition} *)
(** The start (included) of the region is given by the field [start],
which is a {e position}, and the end (excluded) is the position
given by the field [stop]. The convention of including the start
and excluding the end enables to have empty regions if, and only
if, [start = stop], which a fast and easy check. See module {!
Pos} for the definition of positions.
The first byte of a file starts at the offset zero (that is,
column one), and [start] is always lower than or equal to [stop],
and they must refer to the same file.
{ul
{li The call [region#shift_bytes n] evaluates in a region that
is the translation of region [region] of [n] bytes forward
in the file.}
{li The call [region#shift_one_uchar n] is similar to
[region#shift_bytes n], except that it assumes that [n] is
the number of bytes making up one unicode point.}
{li The call [region#set_file f] sets the file name to be [f].}
{li The method [file] returns the file name.}
{li The method [pos] returns the values of the fields [start]
and [stop].}
{li The method [byte_pos] returns the start and end positions of
the region at hand {e interpreting them as lexing
positions}, that is, the unit is the byte.}
{li The call [region#to_string ~file ~offsets mode] evaluates in
a string denoting the region [region], in the manner of the
OCaml compilers.}
{li The name of the file is present if, and only if, [file =
true] or [file] is missing.}
{li The positions in the file are expressed as horizontal
offsets if [offsets = true] or [offsets] is missing (the
default), otherwise as columns.}
{li If [mode = `Byte], those positions will be assumed to have
bytes as their unit, otherwise, if [mode = `Point], they
will be assumed to refer to code points.}
{li The method [compact] has the same signature as and calling
convention as [to_string], except that the resulting string
is shorter (usually for debugging or tracing).}}
*)
type t = private <
start : Pos.t;
stop : Pos.t;
(* Setters *)
shift_bytes : int -> t;
shift_one_uchar : int -> t;
set_file : string -> t;
(* Getters *)
file : string;
pos : Pos.t * Pos.t;
byte_pos : Lexing.position * Lexing.position;
(* Predicates *)
is_ghost : bool;
(* Conversions to type [string] *)
to_string : ?file:bool -> ?offsets:bool -> [`Byte | `Point] -> string;
compact : ?file:bool -> ?offsets:bool -> [`Byte | `Point] -> string
>
(** The type [region] is a synonym of [t] to use after [open Region].
*)
type region = t
(** The type ['a reg] enables the concept of some value of type ['a] to
be related to a region in a source file.
*)
type 'a reg = {region: t; value: 'a}
(* {1 Constructors} *)
exception Invalid
(** The function [make] creates a region from two positions. If the
positions are not properly ordered or refer to different files,
the exception [Invalid] is raised.
@raise [Invalid]
*)
val make : start:Pos.t -> stop:Pos.t -> t
(** {1 Special regions} *)
(** To deal with ghost expressions, that is, pieces of abstract syntax
that have not been built from excerpts of concrete syntax, we need
{e ghost regions}. The module {! Pos} provides a [ghost] position,
and we also provide a [ghost] region and, in type [t], the method
[is_ghost] to check it. It is implemented as two [Pos.ghost]
positions. *)
val ghost : t
(** The call to [wrap_ghost] wraps a value within a ghost region.
*)
val wrap_ghost : 'a -> 'a reg
(** Occasionnally, we may need a minimum region. It is here made of
two minimal positions.
*)
val min : t
(** {1 Comparisons} *)
(** Two regions are equal if, and only if, they refer to the same file
and their start positions are equal and their stop positions are
equal. See {! Pos.equal}. Note that [r1] and [r2] can be
ghosts. *)
val equal : t -> t -> bool
(** The call [lt r1 r2] ("lower than") has the value [true] if, and
only if, regions [r1] and [r2] refer to the same file, none is a
ghost and the start position of [r1] is lower than that of
[r2]. (See {! Pos.lt}.) *)
val lt : t -> t -> bool
(** Given two regions [r1] and [r2], we may want the region [cover r1
r2] that covers [r1] and [r2]. We have the property [equal (cover
r1 r2) (cover r2 r1)]. (In a sense, it is the maximum region, but
we avoid that name because of the [min] function above.) If [r1]
is a ghost, the cover is [r2], and if [r2] is a ghost, the cover
is [r1].
*)
val cover : t -> t -> t