Source

planck / lib / position.ml

open Sexplib.Conv

(* Abstract position interface *)
module type S = sig
  type t
  include Mtypes.Printable with type t := t
  val top : string -> t
  val none : t
end

module None : S with type t = unit = struct
  type t = unit
  let format ppf () = Format.pp_print_string ppf "<no position>"
  let show () = "<no position>"
  let top (_ : string) = ()
  let none = ()
end

module File = struct
  type t = {
    fname : string;
    byte : int; (* in bytes from 0 *)
    line : int; (* from 1 *)
    column : int; (* in bytes from 0 *)
  } with sexp

  let top fname = { fname = fname; byte = 0; line = 1; column = 0; } 
  let add_newlines t n = { t with byte = t.byte + n; line = t.line + n; column = 0; }
  let add_columns t n = { t with byte = t.byte + n; column = t.column + n; }
  let none = { fname = ""; byte = -1; line = -1; column = -1; }
  let show_filename = function
    | "" -> ""
    | s -> Printf.sprintf  "File %s: " s
  let show t = 
    if t.byte < 0 then Printf.sprintf "%s<no location>" (show_filename t.fname)
    else Printf.sprintf "%sline %d, character %d" (show_filename t.fname) t.line t.column
  let format ppf t = 
    if t.byte < 0 then Format.fprintf ppf "%s<no location>" (show_filename t.fname)
    else Format.fprintf ppf "%sline %d, character %d" (show_filename t.fname) t.line t.column
  let format_detailed ppf t = 
    if t.byte < 0 then Format.fprintf ppf "%s<no location>" (show_filename t.fname)
    else Format.fprintf ppf "%sline %d, character %d, byte %d" (show_filename t.fname) t.line t.column t.byte

end

(* CR jfuruse: or Location, if we follow the OCaml tradition *)
module Region = struct
  type t = {
    start : File.t;
    end_ : File.t;
  } with sexp

  let top fname = { start = File.top fname; end_ = File.top fname }
  let none = { start = File.none; end_ = File.none }
  let show t = 
    if t.start.File.byte < 0 then Printf.sprintf "<no location>"
    else 
      let diff = t.end_.File.byte - t.start.File.byte in
      Printf.sprintf "line %d, character %d-%d" t.start.File.line t.start.File.column (t.start.File.column + diff)

  let format ppf t = 
    if t.start.File.byte < 0 then Format.fprintf ppf "<no location>"
    else 
      let diff = t.end_.File.byte - t.start.File.byte in
      Format.fprintf ppf "line %d, character %d-%d" t.start.File.line t.start.File.column (t.start.File.column + diff)

end