1
|
(********************************************************************)
|
2
|
(* *)
|
3
|
(* The LustreC compiler toolset / The LustreC Development Team *)
|
4
|
(* Copyright 2012 - -- ONERA - CNRS - INPT *)
|
5
|
(* *)
|
6
|
(* LustreC is free software, distributed WITHOUT ANY WARRANTY *)
|
7
|
(* under the terms of the GNU Lesser General Public License *)
|
8
|
(* version 2.1. *)
|
9
|
(* *)
|
10
|
(********************************************************************)
|
11
|
|
12
|
open Graph
|
13
|
|
14
|
type rat = int * int
|
15
|
|
16
|
type ident = string
|
17
|
|
18
|
type tag = int
|
19
|
|
20
|
type longident = (string * tag) list
|
21
|
|
22
|
exception TransposeError of int * int
|
23
|
|
24
|
(** General utility functions. *)
|
25
|
let create_hashtable size init =
|
26
|
let tbl = Hashtbl.create size in
|
27
|
List.iter (fun (key, data) -> Hashtbl.add tbl key data) init;
|
28
|
tbl
|
29
|
|
30
|
module IdentModule = struct
|
31
|
(* Node module *)
|
32
|
type t = ident
|
33
|
|
34
|
let compare = compare
|
35
|
|
36
|
let hash n = Hashtbl.hash n
|
37
|
|
38
|
let equal n1 n2 = n1 = n2
|
39
|
end
|
40
|
|
41
|
module IMap = struct
|
42
|
include Map.Make (IdentModule)
|
43
|
|
44
|
let diff m1 m2 =
|
45
|
merge
|
46
|
(fun _ o1 o2 ->
|
47
|
match o1, o2 with
|
48
|
| Some v1, Some v2 ->
|
49
|
if v1 = v2 then None else o1
|
50
|
| _ ->
|
51
|
o1)
|
52
|
m1 m2
|
53
|
|
54
|
let of_list l = List.fold_left (fun m (x, v) -> add x v m) empty l
|
55
|
|
56
|
let pp ?(comment = "") pp_val fmt m =
|
57
|
Format.fprintf fmt "@[<hv 0>@[<hv 2>{ %s" comment;
|
58
|
iter (fun key v -> Format.fprintf fmt "@ %s -> %a" key pp_val v) m;
|
59
|
Format.fprintf fmt "@]@ }@]"
|
60
|
end
|
61
|
|
62
|
module ISet = struct
|
63
|
include Set.Make (IdentModule)
|
64
|
|
65
|
let pp fmt t =
|
66
|
let open Format in
|
67
|
fprintf fmt "@[<hv 0>@[<hv 2>{";
|
68
|
iter (fun s -> fprintf fmt "@ %s" s) t;
|
69
|
fprintf fmt "@]@ }@]"
|
70
|
end
|
71
|
|
72
|
module IdentDepGraph = Imperative.Digraph.ConcreteBidirectional (IdentModule)
|
73
|
module TopologicalDepGraph = Topological.Make (IdentDepGraph)
|
74
|
module ComponentsDepGraph = Components.Make (IdentDepGraph)
|
75
|
|
76
|
(*module DotGraph = Graphviz.Dot (IdentDepGraph)*)
|
77
|
module Bfs = Traverse.Bfs (IdentDepGraph)
|
78
|
|
79
|
exception DeSome
|
80
|
|
81
|
let desome x = match x with Some x -> x | None -> raise DeSome
|
82
|
|
83
|
let option_map f o = match o with None -> None | Some e -> Some (f e)
|
84
|
|
85
|
let add_cons x l = if List.mem x l then l else x :: l
|
86
|
|
87
|
let rec remove_duplicates l =
|
88
|
match l with [] -> [] | t :: q -> add_cons t (remove_duplicates q)
|
89
|
|
90
|
let position pred l =
|
91
|
let rec pos p l =
|
92
|
match l with
|
93
|
| [] ->
|
94
|
assert false
|
95
|
| t :: q ->
|
96
|
if pred t then p else pos (p + 1) q
|
97
|
in
|
98
|
pos 0 l
|
99
|
|
100
|
(* TODO: Lélio: why n+1? cf former def below *)
|
101
|
(* if n < 0 then [] else x :: duplicate x (n - 1) *)
|
102
|
let duplicate x n = List.init (n + 1) (fun _ -> x)
|
103
|
|
104
|
let enumerate n = List.init n (fun i -> i)
|
105
|
|
106
|
let rec repeat n f x = if n <= 0 then x else repeat (n - 1) f (f x)
|
107
|
|
108
|
let transpose_list ll =
|
109
|
let rec transpose ll =
|
110
|
match ll with
|
111
|
| [] ->
|
112
|
[]
|
113
|
| [ l ] ->
|
114
|
List.map (fun el -> [ el ]) l
|
115
|
| l :: q ->
|
116
|
List.map2 (fun el eq -> el :: eq) l (transpose q)
|
117
|
in
|
118
|
match ll with
|
119
|
| [] ->
|
120
|
[]
|
121
|
| l :: q ->
|
122
|
let length_l = List.length l in
|
123
|
List.iter
|
124
|
(fun l' ->
|
125
|
let length_l' = List.length l' in
|
126
|
if length_l <> length_l' then
|
127
|
raise (TransposeError (length_l, length_l')))
|
128
|
q;
|
129
|
transpose ll
|
130
|
|
131
|
let rec filter_upto p n l =
|
132
|
if n = 0 then []
|
133
|
else
|
134
|
match l with
|
135
|
| [] ->
|
136
|
[]
|
137
|
| t :: q ->
|
138
|
if p t then t :: filter_upto p (n - 1) q else filter_upto p n q
|
139
|
|
140
|
(** [gcd a b] returns the greatest common divisor of [a] and [b]. *)
|
141
|
let rec gcd a b = if b = 0 then a else gcd b (a mod b)
|
142
|
|
143
|
(** [lcm a b] returns the least common multiple of [a] and [b]. *)
|
144
|
let lcm a b = if a = 0 && b = 0 then 0 else a * b / gcd a b
|
145
|
|
146
|
(** [sum_rat (a,b) (a',b')] returns the sum of rationals [(a,b)] and [(a',b')] *)
|
147
|
let sum_rat (a, b) (a', b') =
|
148
|
if a = 0 && b = 0 then a', b'
|
149
|
else if a' = 0 && b' = 0 then a, b
|
150
|
else
|
151
|
let lcm_bb' = lcm b b' in
|
152
|
(a * lcm_bb' / b) + (a' * lcm_bb' / b'), lcm_bb'
|
153
|
|
154
|
let simplify_rat (a, b) =
|
155
|
let gcd = gcd a b in
|
156
|
if gcd = 0 then a, b else a / gcd, b / gcd
|
157
|
|
158
|
let max_rat (a, b) (a', b') =
|
159
|
let ratio_ab = float_of_int a /. float_of_int b in
|
160
|
let ratio_ab' = float_of_int a' /. float_of_int b' in
|
161
|
if ratio_ab > ratio_ab' then a, b else a', b'
|
162
|
|
163
|
(** [list_union l1 l2] returns the union of list [l1] and [l2]. The result
|
164
|
contains no duplicates. *)
|
165
|
let list_union l1 l2 =
|
166
|
let rec aux l acc =
|
167
|
match l with
|
168
|
| [] ->
|
169
|
acc
|
170
|
| x :: tl ->
|
171
|
if List.mem x acc then aux tl acc else aux tl (x :: acc)
|
172
|
in
|
173
|
let l1' = aux l1 [] in
|
174
|
aux l2 l1'
|
175
|
|
176
|
(** [hashtbl_add h1 h2] adds all the bindings in [h2] to [h1]. If the
|
177
|
intersection is not empty, it replaces the former binding *)
|
178
|
let hashtbl_add h1 h2 =
|
179
|
Hashtbl.iter (fun key value -> Hashtbl.replace h1 key value) h2
|
180
|
|
181
|
let hashtbl_iterlast h f1 f2 =
|
182
|
let l = Hashtbl.length h in
|
183
|
ignore
|
184
|
(Hashtbl.fold
|
185
|
(fun k v cpt ->
|
186
|
if cpt = l then (
|
187
|
f2 k v;
|
188
|
cpt + 1)
|
189
|
else (
|
190
|
f1 k v;
|
191
|
cpt + 1))
|
192
|
h 1)
|
193
|
|
194
|
(** Match types variables to 'a, 'b, ..., for pretty-printing. Type variables
|
195
|
are identified by integers. *)
|
196
|
let tnames = ref ([] : (int * string) list)
|
197
|
|
198
|
let tname_counter = ref 0
|
199
|
|
200
|
(* Same for carriers *)
|
201
|
let crnames = ref ([] : (int * string) list)
|
202
|
|
203
|
let crname_counter = ref 0
|
204
|
|
205
|
(* Same for dimension *)
|
206
|
let dnames = ref ([] : (int * string) list)
|
207
|
|
208
|
let dname_counter = ref 0
|
209
|
|
210
|
(* Same for delays *)
|
211
|
let inames = ref ([] : (int * string) list)
|
212
|
|
213
|
let iname_counter = ref 0
|
214
|
|
215
|
let reset_names () =
|
216
|
tnames := [];
|
217
|
tname_counter := 0;
|
218
|
crnames := [];
|
219
|
crname_counter := 0;
|
220
|
dnames := [];
|
221
|
dname_counter := 0;
|
222
|
inames := [];
|
223
|
iname_counter := 0
|
224
|
|
225
|
(* From OCaml compiler *)
|
226
|
let new_tname () =
|
227
|
let tname =
|
228
|
if !tname_counter < 26 then String.make 1 (Char.chr (97 + !tname_counter))
|
229
|
else
|
230
|
String.make 1 (Char.chr (97 + (!tname_counter mod 26)))
|
231
|
^ string_of_int (!tname_counter / 26)
|
232
|
in
|
233
|
incr tname_counter;
|
234
|
tname
|
235
|
|
236
|
let new_crname () =
|
237
|
incr crname_counter;
|
238
|
Format.sprintf "c%i" (!crname_counter - 1)
|
239
|
|
240
|
let name_of_type id =
|
241
|
try List.assoc id !tnames
|
242
|
with Not_found ->
|
243
|
let name = new_tname () in
|
244
|
tnames := (id, name) :: !tnames;
|
245
|
name
|
246
|
|
247
|
let name_of_carrier id =
|
248
|
let pp_id =
|
249
|
try List.assoc id !crnames
|
250
|
with Not_found ->
|
251
|
let name = new_crname () in
|
252
|
crnames := (id, name) :: !crnames;
|
253
|
name
|
254
|
in
|
255
|
pp_id
|
256
|
|
257
|
let new_dname () =
|
258
|
incr dname_counter;
|
259
|
Format.sprintf "d%i" (!dname_counter - 1)
|
260
|
|
261
|
let name_of_dimension id =
|
262
|
try List.assoc id !dnames
|
263
|
with Not_found ->
|
264
|
let name = new_dname () in
|
265
|
dnames := (id, name) :: !dnames;
|
266
|
name
|
267
|
|
268
|
let new_iname () =
|
269
|
incr iname_counter;
|
270
|
Format.sprintf "t%i" (!iname_counter - 1)
|
271
|
|
272
|
let name_of_delay id =
|
273
|
try List.assoc id !inames
|
274
|
with Not_found ->
|
275
|
let name = new_iname () in
|
276
|
inames := (id, name) :: !inames;
|
277
|
name
|
278
|
|
279
|
open Format
|
280
|
|
281
|
let print_rat fmt (a, b) =
|
282
|
if b = 1 then Format.fprintf fmt "%i" a
|
283
|
else if b < 0 then Format.fprintf fmt "%i/%i" (-a) (-b)
|
284
|
else Format.fprintf fmt "%i/%i" a b
|
285
|
|
286
|
(* Generic pretty printing *)
|
287
|
|
288
|
let pp_final_char_if_non_empty c l fmt =
|
289
|
match l with [] -> () | _ -> Format.fprintf fmt "%(%)" c
|
290
|
|
291
|
let pp_newline_if_non_empty l fmt =
|
292
|
match l with [] -> () | _ -> Format.fprintf fmt "@,"
|
293
|
|
294
|
module Format = struct
|
295
|
include Format
|
296
|
open Format
|
297
|
|
298
|
let with_out_file file f =
|
299
|
let oc = open_out file in
|
300
|
let fmt = formatter_of_out_channel oc in
|
301
|
f fmt;
|
302
|
close_out oc
|
303
|
|
304
|
let pp_print_nothing _fmt _ = ()
|
305
|
|
306
|
let pp_print_cutcut fmt () = fprintf fmt "@,@,"
|
307
|
|
308
|
let pp_print_endcut s fmt () = fprintf fmt "%s@," s
|
309
|
|
310
|
let pp_print_opar fmt () = pp_print_string fmt "("
|
311
|
|
312
|
let pp_print_cpar fmt () = pp_print_string fmt ")"
|
313
|
|
314
|
let pp_print_obracket fmt () = pp_print_string fmt "["
|
315
|
|
316
|
let pp_print_cbracket fmt () = pp_print_string fmt "]"
|
317
|
|
318
|
let pp_print_obrace fmt () = pp_print_string fmt "{"
|
319
|
|
320
|
let pp_print_cbrace fmt () = pp_print_string fmt "}"
|
321
|
|
322
|
let pp_print_opar' fmt () = pp_print_string fmt "( "
|
323
|
|
324
|
let pp_print_cpar' fmt () = pp_print_string fmt " )"
|
325
|
|
326
|
let pp_print_obrace' fmt () = pp_print_string fmt "{ "
|
327
|
|
328
|
let pp_print_cbrace' fmt () = pp_print_string fmt " }"
|
329
|
|
330
|
let pp_print_comma fmt () = fprintf fmt ",@ "
|
331
|
|
332
|
let pp_print_semicolon fmt () = fprintf fmt ";@ "
|
333
|
|
334
|
let pp_print_comma' fmt () = fprintf fmt ","
|
335
|
|
336
|
let pp_print_semicolon' fmt () = fprintf fmt ";"
|
337
|
|
338
|
let pp_open_vbox0 fmt () = pp_open_vbox fmt 0
|
339
|
|
340
|
let pp_print_list ?(pp_prologue = pp_print_nothing)
|
341
|
?(pp_epilogue = pp_print_nothing) ?(pp_op = pp_print_nothing)
|
342
|
?(pp_cl = pp_print_nothing)
|
343
|
?(pp_open_box = fun fmt () -> pp_open_box fmt 0)
|
344
|
?(pp_eol = pp_print_nothing) ?(pp_nil = pp_print_nothing) ?pp_sep pp_v fmt
|
345
|
l =
|
346
|
fprintf fmt "%a%a%a%a%a@]%a%a"
|
347
|
(fun fmt l -> if l <> [] then pp_prologue fmt ())
|
348
|
l pp_op () pp_open_box ()
|
349
|
(fun fmt () ->
|
350
|
if l = [] then pp_nil fmt () else pp_print_list ?pp_sep pp_v fmt l)
|
351
|
()
|
352
|
(fun fmt l -> if l <> [] then pp_eol fmt ())
|
353
|
l pp_cl ()
|
354
|
(fun fmt l -> if l <> [] then pp_epilogue fmt ())
|
355
|
l
|
356
|
|
357
|
let pp_comma_list = pp_print_list ~pp_sep:pp_print_comma
|
358
|
|
359
|
let pp_print_list_i ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box
|
360
|
?pp_eol ?pp_nil ?pp_sep pp_v =
|
361
|
let i = ref 0 in
|
362
|
pp_print_list ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box ?pp_eol
|
363
|
?pp_nil ?pp_sep (fun fmt x ->
|
364
|
pp_v fmt !i x;
|
365
|
incr i)
|
366
|
|
367
|
let pp_print_list2 ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box
|
368
|
?pp_eol ?pp_nil ?pp_sep pp_v fmt (l1, l2) =
|
369
|
pp_print_list ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box ?pp_eol
|
370
|
?pp_nil ?pp_sep pp_v fmt (List.combine l1 l2)
|
371
|
|
372
|
let pp_print_list_i2 ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box
|
373
|
?pp_eol ?pp_nil ?pp_sep pp_v fmt (l1, l2) =
|
374
|
pp_print_list_i ?pp_prologue ?pp_epilogue ?pp_op ?pp_cl ?pp_open_box ?pp_eol
|
375
|
?pp_nil ?pp_sep
|
376
|
(fun fmt i (x1, x2) -> pp_v fmt i x1 x2)
|
377
|
fmt (List.combine l1 l2)
|
378
|
|
379
|
let pp_print_parenthesized ?(pp_sep = pp_print_comma) =
|
380
|
pp_print_list ~pp_op:pp_print_opar ~pp_cl:pp_print_cpar ~pp_sep
|
381
|
|
382
|
let pp_print_bracketed ?(pp_sep = pp_print_comma) =
|
383
|
pp_print_list ~pp_op:pp_print_obracket ~pp_cl:pp_print_cbracket ~pp_sep
|
384
|
|
385
|
let pp_print_braced ?(pp_sep = pp_print_comma) =
|
386
|
pp_print_list ~pp_op:pp_print_obrace ~pp_cl:pp_print_cbrace ~pp_sep
|
387
|
|
388
|
let pp_print_braced' ?(pp_sep = pp_print_comma) =
|
389
|
pp_print_list ~pp_op:pp_print_obrace' ~pp_cl:pp_print_cbrace' ~pp_sep
|
390
|
end
|
391
|
|
392
|
let fprintf_list ?(eol : ('a, formatter, unit) format = "") ~sep f fmt l =
|
393
|
Format.(pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt "%(%)" sep) f fmt l);
|
394
|
if l <> [] then Format.fprintf fmt "%(%)" eol
|
395
|
|
396
|
let pp_list l pp_fun beg_str end_str sep_str =
|
397
|
if beg_str = "\n" then print_newline () else print_string beg_str;
|
398
|
let rec pp_l l =
|
399
|
match l with
|
400
|
| [] ->
|
401
|
()
|
402
|
| [ hd ] ->
|
403
|
pp_fun hd
|
404
|
| hd :: tl ->
|
405
|
pp_fun hd;
|
406
|
if sep_str = "\n" then print_newline () else print_string sep_str;
|
407
|
pp_l tl
|
408
|
in
|
409
|
pp_l l;
|
410
|
if end_str = "\n" then print_newline () else print_string end_str
|
411
|
|
412
|
let pp_array a pp_fun beg_str end_str sep_str =
|
413
|
if beg_str = "\n" then print_newline () else print_string beg_str;
|
414
|
let n = Array.length a in
|
415
|
if n > 0 then (
|
416
|
Array.iter
|
417
|
(fun x ->
|
418
|
pp_fun x;
|
419
|
print_string sep_str)
|
420
|
(Array.sub a 0 (n - 1));
|
421
|
pp_fun a.(n - 1));
|
422
|
if end_str = "\n" then print_newline () else print_string end_str
|
423
|
|
424
|
let pp_hashtbl t pp_fun beg_str end_str sep_str =
|
425
|
if beg_str = "\n" then print_newline () else print_string beg_str;
|
426
|
let pp_fun1 k v =
|
427
|
pp_fun k v;
|
428
|
if sep_str = "\n" then print_newline () else print_string sep_str
|
429
|
in
|
430
|
hashtbl_iterlast t pp_fun1 pp_fun;
|
431
|
if end_str = "\n" then print_newline () else print_string end_str
|
432
|
|
433
|
let pp_longident lid =
|
434
|
let pp_fun (nid, tag) =
|
435
|
print_string nid;
|
436
|
print_string "(";
|
437
|
print_int tag;
|
438
|
print_string ")"
|
439
|
in
|
440
|
pp_list lid pp_fun "" "." "."
|
441
|
|
442
|
let pp_date fmt tm =
|
443
|
let open Unix in
|
444
|
Format.fprintf fmt "%i/%i/%i, %02i:%02i:%02i" (tm.tm_year + 1900) tm.tm_mon
|
445
|
tm.tm_mday tm.tm_hour tm.tm_min tm.tm_sec
|
446
|
|
447
|
(* Used for uid in variables *)
|
448
|
|
449
|
let get_new_id =
|
450
|
let var_id_cpt = ref 0 in
|
451
|
fun () ->
|
452
|
incr var_id_cpt;
|
453
|
!var_id_cpt
|
454
|
|
455
|
let new_tag =
|
456
|
let last_tag = ref (-1) in
|
457
|
fun () ->
|
458
|
incr last_tag;
|
459
|
!last_tag
|
460
|
|
461
|
module List = struct
|
462
|
include List
|
463
|
|
464
|
let iteri2 f l1 l2 =
|
465
|
if List.length l1 <> List.length l2 then
|
466
|
raise (Invalid_argument "iteri2: lists have different lengths")
|
467
|
else
|
468
|
let rec run idx l1 l2 =
|
469
|
match l1, l2 with
|
470
|
| [], [] ->
|
471
|
()
|
472
|
| hd1 :: tl1, hd2 :: tl2 ->
|
473
|
f idx hd1 hd2;
|
474
|
run (idx + 1) tl1 tl2
|
475
|
| _ ->
|
476
|
assert false
|
477
|
in
|
478
|
run 0 l1 l2
|
479
|
|
480
|
let rec extract l fst last =
|
481
|
if last < fst then assert false
|
482
|
else
|
483
|
match l, fst with
|
484
|
| hd :: tl, 0 ->
|
485
|
if last = 0 then [] else hd :: extract tl 0 (last - 1)
|
486
|
| _ :: tl, _ ->
|
487
|
extract tl (fst - 1) (last - 1)
|
488
|
| [], 0 ->
|
489
|
if last = 0 then [] else assert false (* List too short *)
|
490
|
| _ ->
|
491
|
assert false
|
492
|
end
|
493
|
|
494
|
let get_date () =
|
495
|
let tm = Unix.localtime (Unix.time ()) in
|
496
|
let fmt = Format.str_formatter in
|
497
|
pp_date fmt tm;
|
498
|
Format.flush_str_formatter ()
|
499
|
|
500
|
(* Local Variables: *)
|
501
|
(* compile-command:"make -C .." *)
|
502
|
(* End: *)
|