Ctrl K
ComunidadGuías…

libs/lib_parsing/Tok_range.ml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
(*
   Representation of the location of a piece of code by a pair of tokens.

   This is used so far in intermediate, language-specific ASTs.
*)
open Common

type t = Tok.t * Tok.t [@@deriving show]

let fix ((left, right) as loc) =
  if Tok.is_fake left then (right, right)
  else if Tok.is_fake right then (left, left)
  else loc

let create left right =
  if Tok.is_fake left then (right, right)
  else if Tok.is_fake right then (left, left)
  else (left, right)

let is_fake (left, right) = Tok.is_fake left || Tok.is_fake right
let left_loc_tok (left, right) = if Tok.is_fake left then right else left
let right_loc_tok (left, right) = if Tok.is_fake right then left else right

(*
   Form a new location from a leftmost location and a rightmost location.
   We try to mitigate problems due to fake tokens.
*)
let range a b =
  let start_tok = left_loc_tok a in
  let end_tok = right_loc_tok b in
  if Tok.is_fake end_tok then (start_tok, start_tok)
  else if Tok.is_fake start_tok then (end_tok, end_tok)
  else (start_tok, end_tok)

let unsafe_fake_tok = Tok.unsafe_fake_tok "fake"
let unsafe_fake_loc = (unsafe_fake_tok, unsafe_fake_tok)

(*
   'tok_pos_left' and 'tok_pos_right' both return the start position of the
   token. Only their fallback differs when no position is known.
*)
let tok_pos_left tok =
  match Tok.loc_of_tok tok with
  | Ok x -> x.pos.bytepos
  | Error _ -> max_int

let tok_pos_right tok =
  match Tok.loc_of_tok tok with
  | Ok x -> x.pos.bytepos
  | Error _ -> min_int

(* Prefer non-error. In case of a tie, prefer left-handside argument. *)
let min_tok (a : Tok.t) (b : Tok.t) =
  if tok_pos_left a <= tok_pos_left b then a else b

(* Prefer non-error. In case of a tie, prefer right-handside argument. *)
let max_tok (a : Tok.t) (b : Tok.t) =
  if tok_pos_right b >= tok_pos_right a then b else a

let update_start new_start_tok (_, end_) : t = (new_start_tok, end_)
let update_end (start, _) new_end_tok : t = (start, new_end_tok)

(*
   This is safe but a bit heavy.
   Hopefully it's not too expensive in practice.
*)
let extend (start, end_) tok =
  (* Eliminate any fake token that might exist in the original location,
     if possible. *)
  let start = if Tok.is_fake start then end_ else start in
  let end_ = if Tok.is_fake end_ then start else end_ in
  (* Extend the location to the left, to the right, or both in pathological
     cases. *)
  (min_tok start tok, max_tok tok end_)

let of_toks get_tok xs =
  List.fold_left (fun loc x -> extend loc (get_tok x)) unsafe_fake_loc xs

let union loc_a (start, end_) =
  let loc = extend loc_a start in
  extend loc end_

let of_locs locs = List.fold_left union unsafe_fake_loc locs
let of_list get_loc xs = List_.map get_loc xs |> of_locs

(* TODO: we should filter with is_origintok() first, to avoid having
 * the caller to do it.
 * TODO: we should use min_tok, max_tok instead (this function used to be
 * in Parse_info.ml)
 *)
let min_max_toks_by_pos xs =
  match xs with
  | [] ->
      raise
        (Tok.NoTokenLocation
           "Match returned an empty list with no token location information; \
            this may be fixed by adding enclosing token information (e.g. \
            bracket or parend tokens) to the list's enclosing node type.")
  | [ x ] -> (x, x)
  | x :: xs ->
      let pos_leq p1 p2 = Tok.compare_pos p1 p2 =|= -1 in
      xs
      |> List.fold_left
           (fun (minii, maxii) e ->
             let maxii' = if pos_leq maxii e then e else maxii in
             let minii' = if pos_leq e minii then e else minii in
             (minii', maxii'))
           (x, x)