Source file Msg.ml
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
open Printf
module Coord =
struct
type t = int * int
let line = fst
let col = snd
let toString (r, c) = sprintf "(%d:%d)" r c
let next isNewline (r, c) = if isNewline then (r + 1, 1) else (r, c + 1)
let shift coord s b n =
let rec inner i coord =
if i = n
then coord
else inner (i+1) (next (s.[i] = '\n') coord)
in inner b coord
let compare (r, c) (r', c') =
let x = compare r r' in
if x = 0 then compare c c' else x
end
module MC = Map.Make(Coord)
module rec Locator :
sig
type t =
No
| Point of Coord.t
| Interval of Coord.t * Coord.t
| Set of t list
val makeInterval : t -> t -> t
val least : t -> Coord.t
val most : t -> Coord.t
val updateToString : FileLoc.r -> string -> unit
val toString : t -> string
val compare : t -> t -> int
end
=
struct
type t = No | Point of Coord.t | Interval of Coord.t * Coord.t | Set of t list
and l = t
let makeInterval x y =
match x, y with
| Point x, Point y -> Interval (x, y)
| _ -> Set [x; y]
let relocs = ref MC.empty
let source = ref ""
let defaultWriter _ coord = !relocs, None, Coord.toString coord
let writer = ref defaultWriter
let rec least = function
| No -> (0, 0)
| Point x
| Interval (x, _) -> x
| Set x -> List.hd (List.sort Coord.compare (List.map least x))
let rec most = function
| No -> (0, 0)
| Point x
| Interval (_, x) -> x
| Set x -> List.hd (List.sort (fun x y -> - Coord.compare x y) (List.map most x))
let updateToString rlcs src =
if MC.is_empty rlcs || src = ""
then begin
relocs := MC.empty;
source := "";
writer := defaultWriter
end
else begin
relocs := FileLoc.addFirst rlcs;
source := src;
writer := fun rlcs coord -> let succ, fil, coord = FileLoc.getSuccReloc !source rlcs coord in succ, fil, Coord.toString coord
end
let rec toString = function
| No -> ""
| Point x ->
let _, fil, coord = !writer !relocs x in
(match fil with None -> "" | Some fil -> sprintf "%s: " fil) ^ coord
| Interval (x, y) ->
let succ, filx, x =
!writer !relocs x in
let _, fily, y =
!writer succ y in
(match filx, fily with
| None, None -> sprintf "%s-%s" x y
| Some filx, None -> sprintf "(%s: %s)-%s" filx x y
| None, Some fily -> sprintf "%s-(%s: %s)" x fily y
| Some filx, Some fily ->
if filx = fily
then sprintf "%s: %s-%s" filx x y
else sprintf "(%s: %s)-(%s: %s)" filx x fily y
)
| Set x ->
let module M = View.List (struct type t = l let toString = toString end) in
M.toString x
let compare x y =
if Stdlib.compare x y = 0 then 0
else
match (x, y) with
| No, No -> 0
| No, _ -> -1
| _ , No -> 1
| _ -> Coord.compare (least x) (least y)
end
and FileLoc :
sig
type t = string * Locator.t
type r = (int * (string * Coord.t)) list MC.t
val no : t
val filename : string ref
val debug : bool ref
val interval : <loc: Locator.t; ..> -> <loc: Locator.t; ..> -> t
val toText : t -> string
val unite : t -> t -> t
val toLineDir : t -> string -> string
val getSuccReloc : string -> r -> Coord.t -> r * string option * Coord.t
val stripLines : string -> r * string
val addFirst : r -> r
val printRelocs : r -> unit
(** works only before calling Locator.updateToString *)
val printReloc : string -> r -> Locator.t -> unit
end
=
struct
open Locator
type t = string * Locator.t
type r = (int * (string * Coord.t)) list MC.t
let no = "", No
let filename = ref ""
let debug = ref false
let interval x y = !filename, makeInterval x#loc y#loc
let toText (fil, loc) = sprintf "at %s in file %s" (toString loc) fil
let brackLoc loc = if loc = No then "" else sprintf "[%s]" (toString loc)
let unite (fnx, x) (fny, y) =
if fnx = fny
then (fnx,
(match (x, y) with
| No, x
| x, No -> x
| x, y -> Interval (least x, most y)
))
else (sprintf "%s%s, %s%s" fnx (brackLoc x) fny (brackLoc y), No)
let toLineDir (fil, loc) s = sprintf "\n#line \"%s\" %s\n%s\n#line \"%s\" %s\n" fil (Coord.toString (least loc)) s fil (Coord.toString (most loc))
let splitSucc c m =
let prev, this, succ = MC.split c m in
let (key, bnd) as res =
match this with
| Some item -> c, item
| None -> MC.max_binding prev
in
res, MC.add key bnd succ
let shift s i loc_from loc_to reloc =
let rec inner i loc reloc =
if Coord.compare loc loc_to = 0
then reloc
else let next = Coord.next (s.[i] = '\n') in
inner (i+1) (next loc) (next reloc)
in inner i loc_from reloc
let getSuccReloc s m p =
let (loc, relocs), succ = splitSucc p m in
let (pos, (fil, reloc)) = List.hd relocs in
let reloc = shift s pos loc p reloc in
succ, Some fil, reloc
let stripLines s =
let r = Re.Str.regexp {|\r?\n#line \"\([^\"]*\)\" (\([0-9]+\):\([0-9]+\))\r?\n|} in
let makeInt i s = int_of_string (Re.Str.matched_group i s) in
let rec inner pos loc m s acc =
try
if !debug then printf "loc was: %s\n" (Coord.toString loc);
let first = Re.Str.search_forward r s 0 in
let reloc = (Re.Str.matched_group 1 s, (makeInt 2 s, makeInt 3 s)) in
let loc = if first > 0 then Coord.shift loc s 0 first else loc in
let current = try MC.find loc m with Not_found -> [] in
let last = Re.Str.match_end () in
let newpos = pos + first in
if !debug then begin
printf "loc is: %s\n" (Coord.toString loc);
printf "'";
for i = 0 to min 20 (String.length s - 1) do printf "%c" s.[i] done;
printf "'\n";
end;
inner newpos loc (MC.add loc ((newpos, reloc)::current) m) (Re.Str.string_after s last) (acc ^ (Re.Str.string_before s first))
with Not_found -> m, acc ^ s
in inner 0 (1, 1) MC.empty s ""
let addFirst m = MC.add (0, 0) [0, ("", (0, 0))] m
let printRelocs m =
let module VL = View.List (View.Pair(View.Integer)(View.Pair(View.String)(Coord))) in
MC.iter (fun p lst -> printf "%s: %s\n" (Coord.toString p) (VL.toString lst)) m
let printReloc s m (Interval (p, q) as intrvl) =
let succ, Some fil, beg_c = getSuccReloc s m p in
let _, _, end_c = getSuccReloc s succ q in
printf "%s -> \"%s\" %s\n" (toString intrvl) fil (toString (Interval (beg_c, end_c)))
end
type t = {phrase: string; args: string array; loc: Locator.t}
let make phrase args loc = {phrase=phrase; args=args; loc=loc}
let loc t = t.loc
let phrase phrase = make phrase [||] Locator.No
let orphan phrase args = make phrase args Locator.No
let string t =
let parmExpr = Re.Str.regexp "%\\([0-9]+\\)" in
Re.Str.global_substitute
parmExpr
(fun s ->
try
t.args.(int_of_string (Re.Str.replace_matched "\\1" s))
with
| Failure s when String.equal s "int_of_string" ->
raise (Failure
(sprintf "invalid integer parameter specification in message phrase %S" s)
)
| Invalid_argument s when String.equal s "index out of bounds" ->
raise (Failure
(sprintf "index out of bound while accessing message parameter in %S" s)
)
)
t.phrase
let toString t =
let message = string t in
match Locator.toString t.loc with
| "" -> message
| loc -> message ^ " at " ^ loc
let augment msg loc = match msg.loc with Locator.No -> {msg with loc = loc} | _ -> msg
let augmentList msgs loc = List.map (fun x -> augment x loc) msgs
let extend msg str = {msg with phrase=str ^ msg.phrase}
let extendList msgs str = List.map (fun msg -> extend msg str) msgs