Blame camlp4/Camlp4/Struct/Loc.ml

Packit 1f8b6b
(****************************************************************************)
Packit 1f8b6b
(*                                                                          *)
Packit 1f8b6b
(*                                   OCaml                                  *)
Packit 1f8b6b
(*                                                                          *)
Packit 1f8b6b
(*                            INRIA Rocquencourt                            *)
Packit 1f8b6b
(*                                                                          *)
Packit 1f8b6b
(*  Copyright  2006   Institut National de Recherche  en  Informatique et   *)
Packit 1f8b6b
(*  en Automatique.  All rights reserved.  This file is distributed under   *)
Packit 1f8b6b
(*  the terms of the GNU Library General Public License, with the special   *)
Packit 1f8b6b
(*  exception on linking described in LICENSE at the top of the Camlp4      *)
Packit 1f8b6b
(*  source tree.                                                            *)
Packit 1f8b6b
(*                                                                          *)
Packit 1f8b6b
(****************************************************************************)
Packit 1f8b6b
Packit 1f8b6b
(* Authors:
Packit 1f8b6b
 * - Daniel de Rauglaudre: initial version
Packit 1f8b6b
 * - Nicolas Pouillard: refactoring
Packit 1f8b6b
 *)
Packit 1f8b6b
(* camlp4r *)
Packit 1f8b6b
Packit 1f8b6b
open Format;
Packit 1f8b6b
Packit 1f8b6b
(* FIXME
Packit 1f8b6b
   Study these 2 others implementations which change the ghost
Packit 1f8b6b
   handling:
Packit 1f8b6b
Packit 1f8b6b
   type pos = ... the same ...
Packit 1f8b6b
Packit 1f8b6b
   1/
Packit 1f8b6b
Packit 1f8b6b
   type loc = {
Packit 1f8b6b
     file_name : string;
Packit 1f8b6b
     start     : pos;
Packit 1f8b6b
     stop      : pos
Packit 1f8b6b
   };
Packit 1f8b6b
Packit 1f8b6b
   type t =
Packit 1f8b6b
     [ Nowhere
Packit 1f8b6b
     | Ghost of loc (* the closest non ghost loc *)
Packit 1f8b6b
     | Concrete of loc ];
Packit 1f8b6b
Packit 1f8b6b
   2/
Packit 1f8b6b
Packit 1f8b6b
   type loc = {
Packit 1f8b6b
     file_name : string;
Packit 1f8b6b
     start     : pos;
Packit 1f8b6b
     stop      : pos
Packit 1f8b6b
   };
Packit 1f8b6b
Packit 1f8b6b
   type t = option loc;
Packit 1f8b6b
Packit 1f8b6b
   3/
Packit 1f8b6b
Packit 1f8b6b
   type t = {
Packit 1f8b6b
     file_name : option string;
Packit 1f8b6b
     start     : pos;
Packit 1f8b6b
     stop      : pos
Packit 1f8b6b
   };
Packit 1f8b6b
Packit 1f8b6b
*)
Packit 1f8b6b
Packit 1f8b6b
type pos = {
Packit 1f8b6b
  line : int;
Packit 1f8b6b
  bol  : int;
Packit 1f8b6b
  off  : int
Packit 1f8b6b
};
Packit 1f8b6b
Packit 1f8b6b
type t = {
Packit 1f8b6b
  file_name : string;
Packit 1f8b6b
  start     : pos;
Packit 1f8b6b
  stop      : pos;
Packit 1f8b6b
  ghost     : bool
Packit 1f8b6b
};
Packit 1f8b6b
Packit 1f8b6b
(* Debug section *)
Packit 1f8b6b
value dump_sel f x =
Packit 1f8b6b
  let s =
Packit 1f8b6b
    match x with
Packit 1f8b6b
    [ `start -> "`start"
Packit 1f8b6b
    | `stop  -> "`stop"
Packit 1f8b6b
    | `both  -> "`both"
Packit 1f8b6b
    | _      -> "<not-printable>" ]
Packit 1f8b6b
  in pp_print_string f s;
Packit 1f8b6b
value dump_pos f x =
Packit 1f8b6b
  fprintf f "@[<hov 2>{ line = %d ;@ bol = %d ;@ off = %d } : pos@]"
Packit 1f8b6b
          x.line x.bol x.off;
Packit 1f8b6b
value dump_long f x =
Packit 1f8b6b
  fprintf f
Packit 1f8b6b
    "@[<hov 2>{ file_name = %s ;@ start = %a (%d-%d);@ stop = %a (%d);@ ghost = %b@ } : Loc.t@]"
Packit 1f8b6b
    x.file_name dump_pos x.start (x.start.off - x.start.bol)
Packit 1f8b6b
    (x.stop.off - x.start.bol) dump_pos x.stop
Packit 1f8b6b
    (x.stop.off - x.stop.bol) x.ghost;
Packit 1f8b6b
value dump f x =
Packit 1f8b6b
  fprintf f "[%S: %d:%d-%d %d:%d%t]"
Packit 1f8b6b
    x.file_name x.start.line (x.start.off - x.start.bol)
Packit 1f8b6b
    (x.stop.off - x.start.bol) x.stop.line (x.stop.off - x.stop.bol)
Packit 1f8b6b
    (fun o -> if x.ghost then fprintf o " (ghost)" else ());
Packit 1f8b6b
Packit 1f8b6b
value start_pos = { line = 1 ; bol = 0 ; off = 0 };
Packit 1f8b6b
Packit 1f8b6b
value ghost =
Packit 1f8b6b
  { file_name = "ghost-location";
Packit 1f8b6b
    start     = start_pos;
Packit 1f8b6b
    stop      = start_pos;
Packit 1f8b6b
    ghost     = True     };
Packit 1f8b6b
Packit 1f8b6b
value mk file_name =
Packit 1f8b6b
  debug loc "mk %s@\n" file_name in
Packit 1f8b6b
  { file_name = file_name;
Packit 1f8b6b
    start     = start_pos;
Packit 1f8b6b
    stop      = start_pos;
Packit 1f8b6b
    ghost     = False    };
Packit 1f8b6b
Packit 1f8b6b
value of_tuple (file_name, start_line, start_bol, start_off,
Packit 1f8b6b
                          stop_line,  stop_bol,  stop_off, ghost) =
Packit 1f8b6b
  { file_name = file_name;
Packit 1f8b6b
    start     = { line = start_line ; bol = start_bol ; off = start_off };
Packit 1f8b6b
    stop      = { line = stop_line  ; bol = stop_bol  ; off = stop_off  };
Packit 1f8b6b
    ghost     = ghost };
Packit 1f8b6b
Packit 1f8b6b
value to_tuple
Packit 1f8b6b
  { file_name = file_name;
Packit 1f8b6b
    start     = { line = start_line ; bol = start_bol ; off = start_off };
Packit 1f8b6b
    stop      = { line = stop_line  ; bol = stop_bol  ; off = stop_off  };
Packit 1f8b6b
    ghost     = ghost } =
Packit 1f8b6b
  (file_name, start_line, start_bol, start_off,
Packit 1f8b6b
              stop_line,  stop_bol,  stop_off, ghost);
Packit 1f8b6b
Packit 1f8b6b
value pos_of_lexing_position p =
Packit 1f8b6b
  let pos =
Packit 1f8b6b
  { line = p.Lexing.pos_lnum ;
Packit 1f8b6b
    bol  = p.Lexing.pos_bol  ;
Packit 1f8b6b
    off  = p.Lexing.pos_cnum } in
Packit 1f8b6b
  debug loc "pos_of_lexing_position: %a@\n" dump_pos pos in
Packit 1f8b6b
  pos;
Packit 1f8b6b
Packit 1f8b6b
value pos_to_lexing_position p file_name =
Packit 1f8b6b
  (* debug loc "pos_to_lexing_position: %a@\n" dump_pos p in *)
Packit 1f8b6b
  { Lexing.
Packit 1f8b6b
    pos_fname = file_name;
Packit 1f8b6b
    pos_lnum  = p.line   ;
Packit 1f8b6b
    pos_bol   = p.bol    ;
Packit 1f8b6b
    pos_cnum  = p.off    };
Packit 1f8b6b
Packit 1f8b6b
value better_file_name a b =
Packit 1f8b6b
  match (a, b) with
Packit 1f8b6b
  [ ("", "") -> a
Packit 1f8b6b
  | ("", x)  -> x
Packit 1f8b6b
  | (x, "")  -> x
Packit 1f8b6b
  | ("-", x) -> x
Packit 1f8b6b
  | (x, "-") -> x
Packit 1f8b6b
  | (x, _)   -> x ];
Packit 1f8b6b
Packit 1f8b6b
value of_lexbuf lb =
Packit 1f8b6b
  let start = Lexing.lexeme_start_p lb
Packit 1f8b6b
  and stop  = Lexing.lexeme_end_p lb in
Packit 1f8b6b
  let loc =
Packit 1f8b6b
  { file_name = better_file_name start.Lexing.pos_fname stop.Lexing.pos_fname;
Packit 1f8b6b
    start     = pos_of_lexing_position start;
Packit 1f8b6b
    stop      = pos_of_lexing_position stop;
Packit 1f8b6b
    ghost     = False } in
Packit 1f8b6b
  debug loc "of_lexbuf: %a@\n" dump loc in
Packit 1f8b6b
  loc;
Packit 1f8b6b
Packit 1f8b6b
value of_lexing_position pos =
Packit 1f8b6b
  let loc =
Packit 1f8b6b
  { file_name = pos.Lexing.pos_fname;
Packit 1f8b6b
    start     = pos_of_lexing_position pos;
Packit 1f8b6b
    stop      = pos_of_lexing_position pos;
Packit 1f8b6b
    ghost     = False } in
Packit 1f8b6b
  debug loc "of_lexing_position: %a@\n" dump loc in
Packit 1f8b6b
  loc;
Packit 1f8b6b
Packit 1f8b6b
value to_ocaml_location x =
Packit 1f8b6b
  debug loc "to_ocaml_location: %a@\n" dump x in
Packit 1f8b6b
  { Location.
Packit 1f8b6b
    loc_start = pos_to_lexing_position x.start x.file_name;
Packit 1f8b6b
    loc_end   = pos_to_lexing_position x.stop x.file_name;
Packit 1f8b6b
    loc_ghost = x.ghost };
Packit 1f8b6b
Packit 1f8b6b
value of_ocaml_location { Location.loc_start = a; loc_end = b; loc_ghost = g } =
Packit 1f8b6b
  let res =
Packit 1f8b6b
    { file_name = better_file_name a.Lexing.pos_fname b.Lexing.pos_fname;
Packit 1f8b6b
      start     = pos_of_lexing_position a;
Packit 1f8b6b
      stop      = pos_of_lexing_position b;
Packit 1f8b6b
      ghost     = g } in
Packit 1f8b6b
  debug loc "of_ocaml_location: %a@\n" dump res in
Packit 1f8b6b
  res;
Packit 1f8b6b
Packit 1f8b6b
value start_pos x = pos_to_lexing_position x.start x.file_name;
Packit 1f8b6b
value stop_pos x = pos_to_lexing_position x.stop x.file_name;
Packit 1f8b6b
Packit 1f8b6b
value merge a b =
Packit 1f8b6b
  if a == b then
Packit 1f8b6b
    debug loc "trivial merge@\n" in
Packit 1f8b6b
    a
Packit 1f8b6b
  else
Packit 1f8b6b
    let r =
Packit 1f8b6b
      match (a.ghost, b.ghost) with
Packit 1f8b6b
      [ (False, False) ->
Packit 1f8b6b
        (* FIXME if a.file_name <> b.file_name then
Packit 1f8b6b
          raise (Invalid_argument
Packit 1f8b6b
            (sprintf "Loc.merge: Filenames must be equal: %s <> %s"
Packit 1f8b6b
                    a.file_name b.file_name))                          *)
Packit 1f8b6b
        (* else *)
Packit 1f8b6b
          { (a) with stop = b.stop }
Packit 1f8b6b
      | (True, True) -> { (a) with stop = b.stop }
Packit 1f8b6b
      | (True, _) -> { (a) with stop = b.stop }
Packit 1f8b6b
      | (_, True) -> { (b) with start = a.start } ]
Packit 1f8b6b
    in debug loc "@[<hov 6>merge %a@ %a@ %a@]@\n" dump a dump b dump r in r;
Packit 1f8b6b
Packit 1f8b6b
value join x = { (x) with stop = x.start };
Packit 1f8b6b
Packit 1f8b6b
value map f start_stop_both x =
Packit 1f8b6b
  match start_stop_both with
Packit 1f8b6b
  [ `start -> { (x) with start = f x.start }
Packit 1f8b6b
  | `stop  -> { (x) with stop  = f x.stop }
Packit 1f8b6b
  | `both  -> { (x) with start = f x.start; stop  = f x.stop } ];
Packit 1f8b6b
Packit 1f8b6b
value move_pos chars x = { (x) with off = x.off + chars };
Packit 1f8b6b
Packit 1f8b6b
value move s chars x =
Packit 1f8b6b
  debug loc "move %a %d %a@\n" dump_sel s chars dump x in
Packit 1f8b6b
  map (move_pos chars) s x;
Packit 1f8b6b
Packit 1f8b6b
value move_line lines x =
Packit 1f8b6b
  debug loc "move_line %d %a@\n" lines dump x in
Packit 1f8b6b
  let move_line_pos x =
Packit 1f8b6b
    { (x) with line = x.line + lines ; bol = x.off }
Packit 1f8b6b
  in map move_line_pos `both x;
Packit 1f8b6b
Packit 1f8b6b
value shift width x =
Packit 1f8b6b
  { (x) with start = x.stop ; stop = move_pos width x.stop };
Packit 1f8b6b
Packit 1f8b6b
value file_name  x = x.file_name;
Packit 1f8b6b
value start_line x = x.start.line;
Packit 1f8b6b
value stop_line  x = x.stop.line;
Packit 1f8b6b
value start_bol  x = x.start.bol;
Packit 1f8b6b
value stop_bol   x = x.stop.bol;
Packit 1f8b6b
value start_off  x = x.start.off;
Packit 1f8b6b
value stop_off   x = x.stop.off;
Packit 1f8b6b
value is_ghost   x = x.ghost;
Packit 1f8b6b
Packit 1f8b6b
value set_file_name s x =
Packit 1f8b6b
  debug loc "set_file_name: %a@\n" dump x in
Packit 1f8b6b
  { (x) with file_name = s };
Packit 1f8b6b
Packit 1f8b6b
value ghostify x =
Packit 1f8b6b
  debug loc "ghostify: %a@\n" dump x in
Packit 1f8b6b
  { (x) with ghost = True };
Packit 1f8b6b
Packit 1f8b6b
value make_absolute x =
Packit 1f8b6b
  debug loc "make_absolute: %a@\n" dump x in
Packit 1f8b6b
  let pwd = Sys.getcwd () in
Packit 1f8b6b
  if Filename.is_relative x.file_name then
Packit 1f8b6b
    { (x) with file_name = Filename.concat pwd x.file_name }
Packit 1f8b6b
  else x;
Packit 1f8b6b
Packit 1f8b6b
value strictly_before x y =
Packit 1f8b6b
  let b = x.stop.off < y.start.off && x.file_name = y.file_name in
Packit 1f8b6b
  debug loc "%a [strictly_before] %a => %b@\n" dump x dump y b in
Packit 1f8b6b
  b;
Packit 1f8b6b
Packit 1f8b6b
value to_string x = do {
Packit 1f8b6b
  let (a, b) = (x.start, x.stop) in
Packit 1f8b6b
  let res = sprintf "File \"%s\", line %d, characters %d-%d"
Packit 1f8b6b
                    x.file_name a.line (a.off - a.bol) (b.off - a.bol) in
Packit 1f8b6b
  if x.start.line <> x.stop.line then
Packit 1f8b6b
    sprintf "%s (end at line %d, character %d)"
Packit 1f8b6b
            res x.stop.line (b.off - b.bol)
Packit 1f8b6b
  else res
Packit 1f8b6b
};
Packit 1f8b6b
Packit 1f8b6b
value print out x = pp_print_string out (to_string x);
Packit 1f8b6b
Packit 1f8b6b
value check x msg =
Packit 1f8b6b
  if ((start_line x) > (stop_line x) ||
Packit 1f8b6b
      (start_bol x) > (stop_bol x) ||
Packit 1f8b6b
      (start_off x) > (stop_off x) ||
Packit 1f8b6b
      (start_line x) < 0 || (stop_line x) < 0 ||
Packit 1f8b6b
      (start_bol x) < 0 || (stop_bol x) < 0 ||
Packit 1f8b6b
      (start_off x) < 0 ||  (stop_off x) < 0)
Packit 1f8b6b
      (* Here, we don't check
Packit 1f8b6b
        (start_off x) < (start_bol x) || (stop_off x) < (start_bol x)
Packit 1f8b6b
        since the lexer is called on antiquotations, with off=0, but line and bolpos
Packit 1f8b6b
        have "correct" values *)
Packit 1f8b6b
  then do {
Packit 1f8b6b
    eprintf "*** Warning: (%s) strange positions ***\n%a@\n" msg print x;
Packit 1f8b6b
    False
Packit 1f8b6b
  }
Packit 1f8b6b
  else True;
Packit 1f8b6b
Packit 1f8b6b
exception Exc_located of t and exn;
Packit 1f8b6b
Packit 1f8b6b
ErrorHandler.register
Packit 1f8b6b
  (fun ppf ->
Packit 1f8b6b
    fun [ Exc_located loc exn ->
Packit 1f8b6b
            fprintf ppf "%a:@\n%a" print loc ErrorHandler.print exn
Packit 1f8b6b
        | exn -> raise exn ]);
Packit 1f8b6b
Packit 1f8b6b
value name = ref "_loc";
Packit 1f8b6b
Packit 1f8b6b
value raise loc exc =
Packit 1f8b6b
  match exc with
Packit 1f8b6b
  [ Exc_located _ _ -> raise exc
Packit 1f8b6b
  | _ -> raise (Exc_located loc exc) ]
Packit 1f8b6b
;