2012-06-27 18:09:30 +02:00
|
|
|
(***********************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* Heptagon *)
|
|
|
|
(* *)
|
|
|
|
(* Gwenael Delaval, LIG/INRIA, UJF *)
|
|
|
|
(* Leonard Gerard, Parkas, ENS *)
|
|
|
|
(* Adrien Guatto, Parkas, ENS *)
|
|
|
|
(* Cedric Pasteur, Parkas, ENS *)
|
2012-06-29 01:43:15 +02:00
|
|
|
(* Marc Pouzet, Parkas, ENS *)
|
2012-06-27 18:09:30 +02:00
|
|
|
(* *)
|
|
|
|
(* Copyright 2012 ENS, INRIA, UJF *)
|
|
|
|
(* *)
|
|
|
|
(* This file is part of the Heptagon compiler. *)
|
|
|
|
(* *)
|
|
|
|
(* Heptagon is free software: you can redistribute it and/or modify it *)
|
|
|
|
(* under the terms of the GNU General Public License as published by *)
|
|
|
|
(* the Free Software Foundation, either version 3 of the License, or *)
|
|
|
|
(* (at your option) any later version. *)
|
|
|
|
(* *)
|
|
|
|
(* Heptagon is distributed in the hope that it will be useful, *)
|
|
|
|
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
|
|
|
|
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
|
|
|
|
(* GNU General Public License for more details. *)
|
|
|
|
(* *)
|
|
|
|
(* You should have received a copy of the GNU General Public License *)
|
|
|
|
(* along with Heptagon. If not, see <http://www.gnu.org/licenses/> *)
|
|
|
|
(* *)
|
|
|
|
(***********************************************************************)
|
2010-06-15 10:49:03 +02:00
|
|
|
(* useful stuff *)
|
|
|
|
|
|
|
|
let optional f = function
|
|
|
|
| None -> None
|
|
|
|
| Some x -> Some (f x)
|
|
|
|
|
2010-07-08 17:41:00 +02:00
|
|
|
let optional_wacc f acc = function
|
|
|
|
| None -> None, acc
|
|
|
|
| Some x -> let x, acc = f acc x in Some x, acc
|
|
|
|
|
2010-06-15 10:49:03 +02:00
|
|
|
let optunit f = function
|
|
|
|
| None -> ()
|
|
|
|
| Some x -> f x
|
|
|
|
|
|
|
|
|
2010-12-14 18:29:55 +01:00
|
|
|
(** Print to a string *)
|
|
|
|
let print_pp_to_string print_fun element =
|
|
|
|
let _ = Format.flush_str_formatter () in (* Ensure that the buffer is empty *)
|
|
|
|
print_fun Format.str_formatter element;
|
|
|
|
Format.flush_str_formatter ()
|
|
|
|
|
|
|
|
(** Replace all non [a-z A-Z 0-9] character of a string by [_] *)
|
|
|
|
let sanitize_string s =
|
|
|
|
Str.global_replace (Str.regexp "[^a-zA-Z0-9]") "_" s
|
|
|
|
|
|
|
|
|
2010-06-15 10:49:03 +02:00
|
|
|
(* creation of names. Ensure unicity for the whole compilation chain *)
|
|
|
|
let symbol = ref 0
|
|
|
|
|
|
|
|
let gen_symbol () = incr symbol; "_"^(string_of_int !symbol)
|
|
|
|
let reset_symbol () = symbol := (*!min_symbol*) 0
|
|
|
|
|
|
|
|
let unique l =
|
2010-09-14 09:39:02 +02:00
|
|
|
let tbl = Hashtbl.create (List.length l) in
|
2010-06-15 10:49:03 +02:00
|
|
|
List.iter (fun i -> Hashtbl.replace tbl i ()) l;
|
2010-09-14 09:39:02 +02:00
|
|
|
Hashtbl.fold (fun key _ accu -> key :: accu) tbl []
|
2010-06-15 10:49:03 +02:00
|
|
|
|
2010-12-14 18:31:09 +01:00
|
|
|
let rec map_butlast f l =
|
2010-06-26 16:53:25 +02:00
|
|
|
match l with
|
2010-06-15 10:49:03 +02:00
|
|
|
| [] -> []
|
|
|
|
| [a] -> [a]
|
2010-12-14 18:31:09 +01:00
|
|
|
| a::l -> (f a)::(map_butlast f l)
|
2010-06-15 10:49:03 +02:00
|
|
|
|
2011-06-27 10:58:14 +02:00
|
|
|
let map_butnlast n f l =
|
|
|
|
let rec aux l = match l with
|
|
|
|
| [] -> [], 0
|
2011-06-27 19:20:47 +02:00
|
|
|
| a::l ->
|
2011-06-27 10:58:14 +02:00
|
|
|
let (res, k) = aux l in
|
2011-06-27 19:20:47 +02:00
|
|
|
if k < n then
|
2011-06-27 10:58:14 +02:00
|
|
|
a::res, (k + 1)
|
|
|
|
else
|
|
|
|
(f a)::res, (k+1)
|
|
|
|
in
|
|
|
|
let res, _ = aux l in
|
|
|
|
res
|
|
|
|
|
2010-06-15 10:49:03 +02:00
|
|
|
let rec last_element l =
|
2010-06-26 16:53:25 +02:00
|
|
|
match l with
|
2010-06-15 10:49:03 +02:00
|
|
|
| [] -> assert false
|
|
|
|
| [v] -> v
|
2010-09-14 09:39:02 +02:00
|
|
|
| _::l -> last_element l
|
2010-06-15 10:49:03 +02:00
|
|
|
|
|
|
|
(** [split_last l] returns l without its last element and
|
|
|
|
the last element of l. *)
|
|
|
|
let rec split_last = function
|
|
|
|
| [] -> assert false
|
|
|
|
| [a] -> [], a
|
2010-06-26 16:53:25 +02:00
|
|
|
| v::l ->
|
2010-06-15 10:49:03 +02:00
|
|
|
let l, a = split_last l in
|
2010-06-26 16:53:25 +02:00
|
|
|
v::l, a
|
2010-06-15 10:49:03 +02:00
|
|
|
|
2011-06-27 10:58:14 +02:00
|
|
|
(** [split_nlasts l] returns l without its last n elements and
|
|
|
|
the last n elements of l. *)
|
2013-11-08 18:51:06 +01:00
|
|
|
let split_nlast n l =
|
2011-06-27 10:58:14 +02:00
|
|
|
let rec aux l = match l with
|
|
|
|
| [] -> [], [], 0
|
2011-06-27 19:20:47 +02:00
|
|
|
| a::l ->
|
2011-06-27 10:58:14 +02:00
|
|
|
let (l1, l2, k) = aux l in
|
2011-06-27 19:20:47 +02:00
|
|
|
if k < n then
|
2011-06-27 10:58:14 +02:00
|
|
|
l1, a::l2, (k + 1)
|
|
|
|
else
|
|
|
|
a::l1, l2, (k+1)
|
|
|
|
in
|
|
|
|
let l1, l2, k = aux l in
|
|
|
|
if (k < n) then
|
|
|
|
assert false
|
|
|
|
else l1, l2
|
|
|
|
|
2011-03-21 17:22:03 +01:00
|
|
|
exception List_too_short
|
2017-03-03 11:41:57 +01:00
|
|
|
|
2011-03-21 17:22:03 +01:00
|
|
|
(** [split_at n l] splits [l] in two after the [n]th value.
|
|
|
|
Raises List_too_short exception if the list is too short. *)
|
|
|
|
let rec split_at n l = match n, l with
|
|
|
|
| 0, l -> [], l
|
|
|
|
| _, [] -> raise List_too_short
|
|
|
|
| n, x::l ->
|
|
|
|
let l1, l2 = split_at (n-1) l in
|
|
|
|
x::l1, l2
|
|
|
|
|
2012-03-30 14:43:33 +02:00
|
|
|
let take n l =
|
|
|
|
let (l, _) = split_at n l in
|
|
|
|
l
|
|
|
|
|
|
|
|
let drop n l =
|
|
|
|
let (_, l) = split_at n l in
|
|
|
|
l
|
2011-07-04 11:25:01 +02:00
|
|
|
|
2011-11-17 15:28:46 +01:00
|
|
|
let rec nth_of_list n l = match n, l with
|
2013-11-08 18:51:06 +01:00
|
|
|
| 1, h::_ -> h
|
|
|
|
| n, _::t -> nth_of_list (n-1) t
|
2011-11-17 15:28:46 +01:00
|
|
|
| _ -> raise List_too_short
|
|
|
|
|
|
|
|
|
2010-06-15 10:49:03 +02:00
|
|
|
let remove x l =
|
|
|
|
List.filter (fun y -> x <> y) l
|
|
|
|
|
2010-09-30 19:24:41 +02:00
|
|
|
let list_compare c l1 l2 =
|
2010-08-24 11:07:05 +02:00
|
|
|
let rec aux l1 l2 = match (l1, l2) with
|
|
|
|
| (h1::t1, h2::t2) ->
|
|
|
|
let result = c h1 h2 in
|
|
|
|
if result = 0 then aux t1 t2 else result
|
|
|
|
| ([], [] ) -> 0
|
|
|
|
| (_, [] ) -> 1
|
|
|
|
| ([], _ ) -> -1
|
|
|
|
in aux l1 l2
|
|
|
|
|
2010-09-30 19:24:41 +02:00
|
|
|
let option_compare f ox1 ox2 = match ox1, ox2 with
|
|
|
|
| None, None -> 0
|
|
|
|
| Some x1, Some x2 -> f x1 x2
|
|
|
|
| None, _ -> -1
|
|
|
|
| _, None -> 1
|
|
|
|
|
2010-06-15 10:49:03 +02:00
|
|
|
let is_empty = function
|
|
|
|
| [] -> true
|
|
|
|
| _ -> false
|
|
|
|
|
|
|
|
(** [repeat_list v n] returns a list with n times the value v. *)
|
|
|
|
let repeat_list v n =
|
|
|
|
let rec aux = function
|
|
|
|
| 0 -> []
|
|
|
|
| n -> v::(aux (n-1))
|
|
|
|
in
|
2010-06-26 16:53:25 +02:00
|
|
|
aux n
|
2010-06-15 10:49:03 +02:00
|
|
|
|
|
|
|
(** Same as List.mem_assoc but using the value instead of the key. *)
|
|
|
|
let rec memd_assoc value = function
|
|
|
|
| [] -> false
|
2014-03-18 11:01:56 +01:00
|
|
|
| (_,d)::l -> (d = value) || (memd_assoc value l)
|
2010-06-15 10:49:03 +02:00
|
|
|
|
|
|
|
(** Same as List.assoc but searching for a data and returning the key. *)
|
|
|
|
let rec assocd value = function
|
|
|
|
| [] -> raise Not_found
|
2010-06-26 16:53:25 +02:00
|
|
|
| (k,d)::l ->
|
2010-06-15 10:49:03 +02:00
|
|
|
if d = value then
|
2010-06-26 16:53:25 +02:00
|
|
|
k
|
2010-06-15 10:49:03 +02:00
|
|
|
else
|
2010-06-26 16:53:25 +02:00
|
|
|
assocd value l
|
2010-07-07 15:11:32 +02:00
|
|
|
|
2011-09-07 17:27:58 +02:00
|
|
|
(** [list_diff l dl] returns [l] without the elements belonging to [dl].*)
|
|
|
|
let rec list_diff l dl = match l with
|
|
|
|
| [] -> []
|
|
|
|
| x::l ->
|
|
|
|
let l = list_diff l dl in
|
|
|
|
if List.mem x dl then l else x::l
|
2010-07-08 17:41:00 +02:00
|
|
|
|
2013-11-08 18:51:06 +01:00
|
|
|
(** {3 Compiler iterators} *)
|
2010-07-08 17:41:00 +02:00
|
|
|
|
2011-04-29 14:13:54 +02:00
|
|
|
(** Mapfold *) (* TODO optim : in a lot of places we don't need the List.rev *)
|
2010-07-07 15:11:32 +02:00
|
|
|
let mapfold f acc l =
|
2010-07-14 00:55:14 +02:00
|
|
|
let l,acc = List.fold_left
|
|
|
|
(fun (l,acc) e -> let e,acc = f acc e in e::l, acc)
|
|
|
|
([],acc) l in
|
2010-07-07 15:11:32 +02:00
|
|
|
List.rev l, acc
|
|
|
|
|
2011-05-02 10:12:42 +02:00
|
|
|
let mapfold2 f acc l1 l2 =
|
|
|
|
let l,acc = List.fold_left2
|
|
|
|
(fun (l,acc) e1 e2 -> let e,acc = f acc e1 e2 in e::l, acc)
|
|
|
|
([],acc) l1 l2 in
|
|
|
|
List.rev l, acc
|
|
|
|
|
2010-07-19 17:19:02 +02:00
|
|
|
let mapfold_right f l acc =
|
|
|
|
List.fold_right (fun e (acc, l) -> let acc, e = f e acc in (acc, e :: l))
|
|
|
|
l (acc, [])
|
2010-07-14 00:55:14 +02:00
|
|
|
|
2011-06-30 17:41:25 +02:00
|
|
|
let rec fold_right_1 f l = match l with
|
|
|
|
| [] -> invalid_arg "fold_right_1: empty list"
|
|
|
|
| [x] -> x
|
|
|
|
| x :: l -> f x (fold_right_1 f l)
|
|
|
|
|
2011-07-04 11:25:01 +02:00
|
|
|
let rec fold_left_1 f l = match l with
|
|
|
|
| [] -> invalid_arg "fold_left_1: empty list"
|
|
|
|
| [x] -> x
|
|
|
|
| x :: l -> f (fold_left_1 f l) x
|
|
|
|
|
2011-07-05 17:42:31 +02:00
|
|
|
let rec fold_left4 f acc l1 l2 l3 l4 = match l1, l2, l3, l4 with
|
|
|
|
| [], [], [], [] -> acc
|
|
|
|
| x1 :: l1, x2 :: l2, x3 :: l3, x4 :: l4 -> fold_left4 f (f acc x1 x2 x3 x4) l1 l2 l3 l4
|
|
|
|
| _ -> invalid_arg "Misc.fold_left4"
|
|
|
|
|
2010-07-09 15:28:26 +02:00
|
|
|
let mapi f l =
|
|
|
|
let rec aux i = function
|
|
|
|
| [] -> []
|
|
|
|
| v::l -> (f i v)::(aux (i+1) l)
|
|
|
|
in
|
|
|
|
aux 0 l
|
|
|
|
|
|
|
|
let mapi2 f l1 l2 =
|
|
|
|
let rec aux i l1 l2 =
|
|
|
|
match l1, l2 with
|
|
|
|
| [], [] -> []
|
|
|
|
| [], _ -> invalid_arg ""
|
|
|
|
| _, [] -> invalid_arg ""
|
|
|
|
| v1::l1, v2::l2 -> (f i v1 v2)::(aux (i+1) l1 l2)
|
|
|
|
in
|
|
|
|
aux 0 l1 l2
|
|
|
|
|
|
|
|
let mapi3 f l1 l2 l3 =
|
|
|
|
let rec aux i l1 l2 l3 =
|
|
|
|
match l1, l2, l3 with
|
|
|
|
| [], [], [] -> []
|
|
|
|
| [], _, _ -> invalid_arg ""
|
|
|
|
| _, [], _ -> invalid_arg ""
|
|
|
|
| _, _, [] -> invalid_arg ""
|
|
|
|
| v1::l1, v2::l2, v3::l3 ->
|
|
|
|
(f i v1 v2 v3)::(aux (i+1) l1 l2 l3)
|
|
|
|
in
|
|
|
|
aux 0 l1 l2 l3
|
2010-09-09 00:35:06 +02:00
|
|
|
|
2010-09-30 19:24:41 +02:00
|
|
|
let fold_righti f l acc =
|
|
|
|
let rec aux i l acc = match l with
|
|
|
|
| [] -> acc
|
|
|
|
| h :: l -> f i h (aux (i + 1) l acc) in
|
|
|
|
aux 0 l acc
|
|
|
|
|
2011-09-07 17:27:58 +02:00
|
|
|
let rec map3 f l1 l2 l3 = match l1, l2, l3 with
|
|
|
|
| [], [], [] -> []
|
|
|
|
| v1::l1, v2::l2, v3::l3 -> (f v1 v2 v3)::(map3 f l1 l2 l3)
|
|
|
|
| _ -> invalid_arg "Misc.map3"
|
|
|
|
|
2011-02-07 14:24:17 +01:00
|
|
|
exception Assert_false
|
2011-05-23 09:24:57 +02:00
|
|
|
let internal_error passe =
|
2011-09-29 20:44:29 +02:00
|
|
|
Format.eprintf "@.---------@\n\
|
|
|
|
Internal compiler error@\n\
|
|
|
|
Passe : %s@\n\
|
2011-05-23 09:24:57 +02:00
|
|
|
----------@." passe;
|
2011-02-07 14:24:17 +01:00
|
|
|
raise Assert_false
|
|
|
|
|
|
|
|
exception Unsupported
|
2011-05-23 09:24:57 +02:00
|
|
|
let unsupported passe =
|
2011-09-29 20:44:29 +02:00
|
|
|
Format.eprintf "@.---------@\n\
|
|
|
|
Unsupported feature, please report it@\n\
|
|
|
|
Passe : %s@\n\
|
|
|
|
----------@." passe;
|
2011-02-07 14:24:17 +01:00
|
|
|
raise Unsupported
|
|
|
|
|
2010-09-13 13:32:35 +02:00
|
|
|
(* Functions to decompose a list into a tuple *)
|
|
|
|
let _arity_error i l =
|
2011-09-29 20:44:29 +02:00
|
|
|
Format.eprintf "@.---------@\n\
|
|
|
|
Internal compiler error: wrong list size (found %d, expected %d).@\n\
|
|
|
|
----------@." (List.length l) i;
|
2011-02-07 14:24:17 +01:00
|
|
|
raise Assert_false
|
2010-09-13 13:32:35 +02:00
|
|
|
|
|
|
|
let _arity_min_error i l =
|
2011-09-29 20:44:29 +02:00
|
|
|
Format.eprintf "@.---------@\n\
|
|
|
|
Internal compiler error: wrong list size (found %d, expected %d at least).@\n\
|
|
|
|
----------@." (List.length l) i;
|
2011-02-07 14:24:17 +01:00
|
|
|
raise Assert_false
|
2010-09-13 13:32:35 +02:00
|
|
|
|
|
|
|
let assert_empty = function
|
|
|
|
| [] -> ()
|
2010-09-14 17:15:43 +02:00
|
|
|
| l -> _arity_error 0 l
|
2010-09-13 13:32:35 +02:00
|
|
|
|
|
|
|
let assert_1 = function
|
|
|
|
| [v] -> v
|
|
|
|
| l -> _arity_error 1 l
|
|
|
|
|
2010-09-13 16:02:33 +02:00
|
|
|
let assert_1min = function
|
|
|
|
| v::l -> v, l
|
|
|
|
| l -> _arity_min_error 1 l
|
|
|
|
|
2010-09-13 13:32:35 +02:00
|
|
|
let assert_2 = function
|
|
|
|
| [v1; v2] -> v1, v2
|
2010-09-14 17:15:43 +02:00
|
|
|
| l -> _arity_error 2 l
|
2010-09-13 13:32:35 +02:00
|
|
|
|
|
|
|
let assert_2min = function
|
|
|
|
| v1::v2::l -> v1, v2, l
|
2010-09-14 17:15:43 +02:00
|
|
|
| l -> _arity_min_error 2 l
|
2010-09-13 13:32:35 +02:00
|
|
|
|
|
|
|
let assert_3 = function
|
|
|
|
| [v1; v2; v3] -> v1, v2, v3
|
2010-09-14 17:15:43 +02:00
|
|
|
| l -> _arity_error 3 l
|
2011-01-07 17:16:50 +01:00
|
|
|
|
|
|
|
let (|>) x f = f x
|
|
|
|
|
|
|
|
let split_string s separator = Str.split (separator |> Str.quote |> Str.regexp) s
|
|
|
|
|
|
|
|
let file_extension s = split_string s "." |> last_element
|
|
|
|
|
2011-04-20 15:41:15 +02:00
|
|
|
(** Memoize the result of the function [f]*)
|
2011-04-20 14:05:55 +02:00
|
|
|
let memoize f =
|
|
|
|
let map = Hashtbl.create 100 in
|
|
|
|
fun x ->
|
|
|
|
try
|
|
|
|
Hashtbl.find map x
|
|
|
|
with
|
|
|
|
| Not_found -> let r = f x in Hashtbl.add map x r; r
|
|
|
|
|
2011-04-20 15:41:15 +02:00
|
|
|
(** Memoize the result of the function [f], taht should expect a
|
|
|
|
tuple as input and be reflexive (f (x,y) = f (y,x)) *)
|
2011-04-20 14:05:55 +02:00
|
|
|
let memoize_couple f =
|
|
|
|
let map = Hashtbl.create 100 in
|
|
|
|
fun (x,y) ->
|
|
|
|
try
|
|
|
|
Hashtbl.find map (x,y)
|
|
|
|
with
|
|
|
|
| Not_found ->
|
|
|
|
let r = f (x,y) in Hashtbl.add map (x,y) r; Hashtbl.add map (y,x) r; r
|
|
|
|
|
|
|
|
(** [iter_couple f l] calls f for all x and y distinct in [l]. *)
|
|
|
|
let rec iter_couple f l = match l with
|
|
|
|
| [] -> ()
|
|
|
|
| x::l ->
|
|
|
|
List.iter (f x) l;
|
|
|
|
iter_couple f l
|
|
|
|
|
2011-04-20 15:41:15 +02:00
|
|
|
(** [iter_couple_2 f l1 l2] calls f for all x in [l1] and y in [l2]. *)
|
|
|
|
let iter_couple_2 f l1 l2 =
|
|
|
|
List.iter (fun v1 -> List.iter (f v1) l2) l1
|
2011-01-24 16:07:26 +01:00
|
|
|
|
2011-04-26 18:02:18 +02:00
|
|
|
(** [index p l] returns the idx of the first element in l
|
|
|
|
that satisfies predicate p.*)
|
|
|
|
let index p l =
|
|
|
|
let rec aux i = function
|
|
|
|
| [] -> -1
|
|
|
|
| v::l -> if p v then i else aux (i+1) l
|
|
|
|
in
|
|
|
|
aux 0 l
|