1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
(* camlp5r *)
(* ploc.ml,v *)
(* Copyright (c) INRIA 2007-2017 *)
#load "pa_macro.cmo";
type t =
{ fname : string;
line_nb : int;
bol_pos : int;
line_nb_last : int;
bol_pos_last : int;
bp : int;
ep : int;
comm : string;
ecomm : string }
;
value make_loc fname line_nb bol_pos (bp, ep) comm =
{fname = fname; line_nb = line_nb; bol_pos = bol_pos;
line_nb_last = line_nb; bol_pos_last = bol_pos;
bp = bp; ep = ep; comm = comm; ecomm = ""}
;
value make_unlined (bp, ep) =
{fname = ""; line_nb = 1; bol_pos = 0; line_nb_last = -1; bol_pos_last = 0;
bp = bp; ep = ep; comm = ""; ecomm = ""}
;
value dummy =
{fname = ""; line_nb = 1; bol_pos = 0; line_nb_last = -1; bol_pos_last = 0;
bp = 0; ep = 0; comm = ""; ecomm = ""}
;
value file_name loc = loc.fname;
value first_pos loc = loc.bp;
value last_pos loc = loc.ep;
value line_nb loc = loc.line_nb;
value bol_pos loc = loc.bol_pos;
value line_nb_last loc = loc.line_nb_last;
value bol_pos_last loc = loc.bol_pos_last;
value comment loc = loc.comm;
value comment_last loc = loc.ecomm;
value encl loc1 loc2 =
if loc1.bp < loc2.bp then
if loc1.ep < loc2.ep then
{fname = loc1.fname; line_nb = loc1.line_nb; bol_pos = loc1.bol_pos;
line_nb_last = loc2.line_nb_last; bol_pos_last = loc2.bol_pos_last;
bp = loc1.bp; ep = loc2.ep; comm = loc1.comm; ecomm = loc2.comm}
else
loc1
else
if loc2.ep < loc1.ep then
{fname = loc2.fname; line_nb = loc2.line_nb; bol_pos = loc2.bol_pos;
line_nb_last = loc1.line_nb_last; bol_pos_last = loc1.bol_pos_last;
bp = loc2.bp; ep = loc1.ep; comm = loc2.comm; ecomm = loc1.comm}
else
loc2
;
value shift sh loc = {(loc) with bp = sh + loc.bp; ep = sh + loc.ep};
value sub loc sh len = {(loc) with bp = loc.bp + sh; ep = loc.bp + sh + len};
value after loc sh len =
{(loc) with bp = loc.ep + sh; ep = loc.ep + sh + len}
;
value with_comment loc comm = {(loc) with comm = comm};
value with_comment_last loc ecomm = {(loc) with ecomm = ecomm};
value with_line_nb_last loc n = {(loc) with line_nb_last = n};
value with_bol_pos_last loc n = {(loc) with bol_pos_last = n};
value name = ref "loc";
value from_file fname loc =
let (bp, ep) = (first_pos loc, last_pos loc) in
try
let ic = open_in_bin fname in
let strm = Stream.of_channel ic in
let rec loop fname lin =
let rec not_a_line_dir col =
parser cnt
[ [: `c; s :] ->
if cnt < bp then
if c = '\n' then loop fname (lin + 1)
else not_a_line_dir (col + 1) s
else
let col = col - (cnt - bp) in
(fname, lin, col, col + ep - bp)
| [: :] ->
(fname, lin, col, col + 1) ]
in
let rec a_line_dir str n col =
parser
[ [: `'\n' :] -> loop str n
| [: `_; s :] -> a_line_dir str n (col + 1) s ]
in
let rec spaces col =
parser
[ [: `' '; s :] -> spaces (col + 1) s
| [: :] -> col ]
in
let rec check_string str n col =
parser
[ [: `'"'; col = spaces (col + 1); s :] -> a_line_dir str n col s
| [: `c when c <> '\n'; s :] ->
check_string (str ^ String.make 1 c) n (col + 1) s
| [: a = not_a_line_dir col :] -> a ]
in
let check_quote n col =
parser
[ [: `'"'; s :] -> check_string "" n (col + 1) s
| [: a = not_a_line_dir col :] -> a ]
in
let rec check_num n col =
parser
[ [: `('0'..'9' as c); s :] ->
check_num (10 * n + Char.code c - Char.code '0') (col + 1) s
| [: col = spaces col; s :] -> check_quote n col s ]
in
let begin_line =
parser
[ [: `'#'; col = spaces 1; s :] -> check_num 0 col s
| [: a = not_a_line_dir 0 :] -> a ]
in
begin_line strm
in
let r =
try loop fname 1 with
[ Stream.Failure ->
let bol = bol_pos loc in
(fname, line_nb loc, bp - bol, ep - bol) ]
in
do { close_in ic; r }
with
[ Sys_error _ -> (fname, 1, bp, ep) ]
;
value second_line fname ep0 (line, bp) ep = do {
let ic = open_in fname in
seek_in ic bp;
loop line bp bp where rec loop line bol p =
if p = ep then do {
close_in ic;
if bol = bp then (line, ep0)
else (line, ep - bol)
}
else do {
let (line, bol) =
match input_char ic with
[ '\n' -> (line + 1, p + 1)
| _ -> (line, bol) ]
in
loop line bol (p + 1)
}
};
value get loc = do {
if loc.fname = "" || loc.fname = "-" then do {
(loc.line_nb, loc.bp - loc.bol_pos, loc.line_nb, loc.ep - loc.bol_pos,
loc.ep - loc.bp)
}
else do {
let (bl, bc, ec) =
(loc.line_nb, loc.bp - loc.bol_pos, loc.ep - loc.bol_pos)
in
let (el, eep) = second_line loc.fname ec (bl, loc.bp) loc.ep in
(bl, bc, el, eep, ec - bc)
}
};
value call_with r v f a =
let saved = r.val in
try do {
r.val := v;
let b = f a in
r.val := saved;
b
}
with e -> do { r.val := saved; raise e }
;
exception Exc of t and exn;
value raise loc exc =
match exc with
[ Exc _ _ -> raise exc
| _ -> raise (Exc loc exc) ]
;
type vala 'a =
[ VaAnt of string
| VaVal of 'a ]
;
value warned = ref True;
value warning_deprecated_since_6_00 name =
if not warned.val then do {
Printf.eprintf "<W> %s deprecated since version 6.00" name;
warned.val := True
}
else ()
;
value make line_nb bol_pos (bp, ep) =
let _ = warning_deprecated_since_6_00 "Ploc.make" in
{fname = ""; line_nb = line_nb; bol_pos = bol_pos; line_nb_last = line_nb;
bol_pos_last = bol_pos; bp = bp; ep = ep; comm = ""; ecomm = ""}
;
value string_of_loc fname line bp ep =
match Sys.os_type with
[ "MacOS" ->
Printf.sprintf "File \"%s\"; line %d; characters %d to %d\n### " fname line
bp ep
| _ ->
Printf.sprintf "File \"%s\", line %d, characters %d-%d:\n" fname line bp ep ]
;
value string_of_location {fname=fname; bp=bp; ep=ep; line_nb=line; bol_pos=bol} =
string_of_loc fname line (bp - bol) (ep - bol)
;
|