From 86c5e03fd7a31965c1518ea5492c7feab469bea5 Mon Sep 17 00:00:00 2001
From: Erwan Jahier <jahier@imag.fr>
Date: Wed, 18 Jun 2008 17:49:15 +0200
Subject: [PATCH] Add a New module that checks that all variables (outputs and
 locals) are defined exactly once.

This  algo is  naive and does not  work with  slices of  slices with
negative steps.  I commit it  before trying a  new one to  get better
non-reg test.

Fix some non-reg test in the should_work dir that this new check revealed.
---
 src/Makefile                                  |   1 +
 src/TODO                                      |   1 -
 src/compiledData.ml                           |  28 +-
 src/evalClock.ml                              |  19 +-
 src/getEff.ml                                 |   9 +-
 src/lazyCompiler.ml                           |  14 +-
 src/test/should_work/Pascal/left.lus          |   4 +-
 src/test/should_work/clock/clock.lus          |  40 +++
 src/test/should_work/demo/declaration.lus     |   2 +
 src/test/should_work/fab_test/morel.lus       |   2 +-
 src/test/should_work/lionel/Gyroscope.lus     |   4 +
 .../lionel/ProduitBool/produitBool.lus        |   3 +
 .../packageTableau.lus                        |   1 +
 src/test/test.res.exp                         |  46 ++-
 src/uniqueOutput.ml                           | 334 ++++++++++++++++++
 15 files changed, 456 insertions(+), 52 deletions(-)
 create mode 100644 src/test/should_work/clock/clock.lus
 create mode 100644 src/uniqueOutput.ml

diff --git a/src/Makefile b/src/Makefile
index ff93d3dc..982f1974 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -50,6 +50,7 @@ SOURCES =  \
 	./evalClock.ml \
 	./getEff.mli \
 	./getEff.ml \
+	./uniqueOutput.ml \
 	./lazyCompiler.ml \
 	./lazyCompiler.mli \
 	./compile.ml \
diff --git a/src/TODO b/src/TODO
index 5291493a..9513cb9a 100644
--- a/src/TODO
+++ b/src/TODO
@@ -138,7 +138,6 @@ n'est pas le cas pour l'instant...
 
 *** facile
 
-
 * Pb des noms de modules
  ../lus2lic should_work/NONREG/dependeur_struct.lus
  -> 
diff --git a/src/compiledData.ml b/src/compiledData.ml
index 20cc272f..1bddaca7 100644
--- a/src/compiledData.ml
+++ b/src/compiledData.ml
@@ -1,4 +1,4 @@
-(** Time-stamp: <modified the 12/06/2008 (at 17:07) by Erwan Jahier> *)
+(** Time-stamp: <modified the 17/06/2008 (at 10:10) by Erwan Jahier> *)
 
 (** 
 
@@ -286,24 +286,6 @@ and static_arg_eff =
   | NodeStaticArgEff  of (Ident.t * node_exp_eff)
 
 
-(* XXX rm: just for test *)
-let (make_dummy_var: Ident.idref -> var_info_eff) =
-  fun idref ->    
-    let id = Ident.of_idref idref in
-    let str = Ident.string_of_idref idref in
-    let teff =
-      try ignore (int_of_string str); Int_type_eff 
-      with _ -> 
-	try ignore (float_of_string str); Real_type_eff 
-	with _ -> Bool_type_eff
-    in
-      {
-	var_name_eff  = id;
-	var_nature_eff = VarLocal;
-	var_number_eff = 0;
-	var_type_eff   = teff;
-	var_clock_eff  = BaseEff;
-      }
 	
 (****************************************************************************)
 (** Type check_flag
@@ -465,6 +447,14 @@ let rec (clock_of_left_eff: left_eff -> clock_eff) =
   | LeftArrayEff (left_eff,_,_) -> clock_of_left_eff left_eff 
   | LeftSliceEff (left_eff,_,_) ->  clock_of_left_eff left_eff
 
+let rec (var_info_of_left_eff: left_eff -> var_info_eff) =
+  function
+    | LeftVarEff   (v, _) -> v
+    | LeftFieldEff (left_eff,_,_) -> var_info_of_left_eff left_eff
+    | LeftArrayEff (left_eff,_,_) -> var_info_of_left_eff left_eff 
+    | LeftSliceEff (left_eff,_,_) -> var_info_of_left_eff left_eff
+
+
 
 (*---------------------------------------------------------------------
 Une erreur associée à un noeud + 1 lexeme dans le fichier source
diff --git a/src/evalClock.ml b/src/evalClock.ml
index fb1c68b4..40d80c63 100644
--- a/src/evalClock.ml
+++ b/src/evalClock.ml
@@ -1,4 +1,4 @@
-(** Time-stamp: <modified the 12/06/2008 (at 11:10) by Erwan Jahier> *)
+(** Time-stamp: <modified the 16/06/2008 (at 15:26) by Erwan Jahier> *)
  
   
 open Predef
@@ -284,8 +284,22 @@ let (check_res : Lxm.t -> clock_info_res list -> clock_eff list -> unit) =
 
 (******************************************************************************)
 
+let cpt_var_name = ref 0
+let (make_dummy_var: string -> var_info_eff) =
+  fun str ->    
+    let id = Ident.of_string (str ^  (string_of_int !cpt_var_name)) in
+      {
+	var_name_eff  = id;
+	var_nature_eff = VarLocal;
+	var_number_eff = -1;
+	var_type_eff   = Bool_type_eff;
+	var_clock_eff  = BaseEff;
+      }
+
+
 let rec (f : id_solver -> val_exp_eff -> clock_info_res list) =
   fun id_solver ve ->
+    cpt_var_name := 0;
     match ve with
       | CallByPosEff ({it=posop; src=lxm}, OperEff args) -> (
 	  eval_by_pos_clock id_solver posop lxm args
@@ -361,7 +375,8 @@ and (eval_by_pos_clock : id_solver -> by_pos_op_eff -> Lxm.t -> val_exp_eff list
       | TUPLE_eff -> List.flatten (List.map (f id_solver) args)
 
 
-      | IDENT_eff idref  ->  [Base_res(make_dummy_var idref)] (* all constants are on the base clock *)
+      | IDENT_eff idref  ->  [Base_res(make_dummy_var (Ident.string_of_idref idref))] 
+				(* all constants are on the base clock *)
 
 		
 and (eval_by_name_clock : id_solver -> by_name_op_eff -> Lxm.t -> 
diff --git a/src/getEff.ml b/src/getEff.ml
index 965583f1..6b1270ef 100644
--- a/src/getEff.ml
+++ b/src/getEff.ml
@@ -1,4 +1,4 @@
-(** Time-stamp: <modified the 12/06/2008 (at 16:29) by Erwan Jahier> *)
+(** Time-stamp: <modified the 16/06/2008 (at 15:44) by Erwan Jahier> *)
 
 
 open Lxm
@@ -73,10 +73,9 @@ and (type_check_equation: id_solver -> eq_info srcflagged -> left_eff list ->
 and (clock_check_equation:id_solver -> eq_info srcflagged -> left_eff list ->
       val_exp_eff -> unit) =
   fun id_solver eq_info lpl_eff ve_eff ->
-    let lpl_clk = List.map (clock_of_left_eff) lpl_eff in
-    let right_part = EvalClock.f id_solver ve_eff in
-      EvalClock.check_res eq_info.src right_part lpl_clk
-
+(*     let right_part,s = EvalClock.f id_solver EvalClock.empty_subst ve_eff in *)
+(*       EvalClock.check_res eq_info.src s lpl_eff right_part  *)
+    assert false
 
 (******************************************************************************)
 let (get_static_params_from_idref : SymbolTab.t -> Lxm.t -> Ident.idref ->
diff --git a/src/lazyCompiler.ml b/src/lazyCompiler.ml
index c7b2a2e9..6844c872 100644
--- a/src/lazyCompiler.ml
+++ b/src/lazyCompiler.ml
@@ -1,4 +1,4 @@
-(** Time-stamp: <modified the 12/06/2008 (at 18:02) by Erwan Jahier> *)
+(** Time-stamp: <modified the 17/06/2008 (at 15:22) by Erwan Jahier> *)
 
 
 open Lxm
@@ -688,11 +688,12 @@ and (node_check_do: t -> CompiledData.node_key -> Lxm.t -> SymbolTab.t ->
 			    after the local_env.lenv_vars has been
 			    filled
 			 *)
-		 BodyEff {
-		   asserts_eff =
-		     List.map (GetEff.assertion node_id_solver) nb.asserts;
-		   eqs_eff = List.map (GetEff.eq node_id_solver) nb.eqs; 
-		 }
+		 let eq_eff = List.map (GetEff.eq node_id_solver) nb.eqs in
+		   BodyEff {
+		     asserts_eff = 
+		       List.map (GetEff.assertion node_id_solver) nb.asserts;
+		     eqs_eff = eq_eff; 
+		   }
 	      )
 	    )
 
@@ -753,6 +754,7 @@ and (node_check_do: t -> CompiledData.node_key -> Lxm.t -> SymbolTab.t ->
     in
       if not provide_flag then 
 	output_string !Global.oc (CompiledDataDump.node_of_node_exp_eff res);
+      UniqueOutput.check res node_def.src;
       res
 
 
diff --git a/src/test/should_work/Pascal/left.lus b/src/test/should_work/Pascal/left.lus
index 18f444c3..aa21f4f5 100644
--- a/src/test/should_work/Pascal/left.lus
+++ b/src/test/should_work/Pascal/left.lus
@@ -5,10 +5,10 @@ type truc = struct {
 };
 
 
-(* XXX TODO 0..98 should work !!! *)
 node toto(x : bool) returns (t : truc^3);
 let
-        t[0].a[0..98 step 2][48..0 step -2] = true^25;	
+--        t[0].a[0..98 step 2][48..0 step -2] = true^25;	
+        t[0].a[0..98 step 2][0..48 step 2] = true^25;	
 	t[0].a[0..98 step 2][1..49 step 2] = false^25;	
 	t[0].a[1..99 step 2][0] = true;
 	t[0].a[1..99 step 2][1] = true;
diff --git a/src/test/should_work/clock/clock.lus b/src/test/should_work/clock/clock.lus
new file mode 100644
index 00000000..19628523
--- /dev/null
+++ b/src/test/should_work/clock/clock.lus
@@ -0,0 +1,40 @@
+
+-- Entree sur entree:  ok
+extern node clock2(clock2_u: bool; clock2_v: bool when clock2_u) returns (clock2_y: bool );
+
+-- Sortie sur sortie:  ok
+extern node clock3(clock3_u: bool) returns (clock3_toto: bool; clock3_y: bool when clock3_toto);
+
+
+-- Entree sur entree et sortie sur sortie:  ok
+extern node clock4(clock4_u: bool; clock4_v: bool when clock4_u) returns (clock4_x: bool; clock4_y: bool when clock4_x);
+
+type s = struct {x: bool^10; y:  bool};
+
+-- Noeud principal.
+node clock(a: bool; b: bool) returns (c: bool; d: bool when c);
+var
+  z: bool;
+--  z2: bool;
+  x: bool when z;
+--  y: bool when x;
+--  e : bool when b;
+
+let 
+--  c = clock2(a, (b or b) when a) or (true->a); 
+--  d = clock2(a, b when a) when c;
+
+--  y = clock2(a, b when a) when x; -- ko ?
+
+--  (z, x) = clock3(current(z));
+--  (z, x) = clock3(current(z when z2));
+  (z, x) = clock3(z);-- ok
+
+  
+  (c, d) = clock4(a, b when a);
+--  z = clock5(a, b when a,  e when a);
+--  z2 = clock5(a, b when a,  e when b when c);
+tel
+
+
+extern node clock5(x :  bool; y:  bool when x; z: bool when y) returns (a: bool);
diff --git a/src/test/should_work/demo/declaration.lus b/src/test/should_work/demo/declaration.lus
index ebeeb1cb..a44568be 100644
--- a/src/test/should_work/demo/declaration.lus
+++ b/src/test/should_work/demo/declaration.lus
@@ -44,4 +44,6 @@ var
   c1: real;
 let
   b1 = a1 / c1;
+-- R1: fix that non-def local
+  c1 = 1.0;
 tel;
diff --git a/src/test/should_work/fab_test/morel.lus b/src/test/should_work/fab_test/morel.lus
index b6cb570d..eb65e9fe 100644
--- a/src/test/should_work/fab_test/morel.lus
+++ b/src/test/should_work/fab_test/morel.lus
@@ -16,7 +16,7 @@ let
 	b1, b2, b3 = (tabb[0], tabb[1], tabb[2]) ;
 	i1, i2, i3 = (tabi[0][0]+tabi[0][1], tabi[1][0]+tabi[1][1], tabi[2][0]+tabi[2][1]);
 
---	tabb[0] = b;
+	tabb[0] = b;
         tabb[1..2] = [true, false] ;
 
 	tabi[2] = mcmorel(i) ;
diff --git a/src/test/should_work/lionel/Gyroscope.lus b/src/test/should_work/lionel/Gyroscope.lus
index 8d76b4b5..555f1e68 100644
--- a/src/test/should_work/lionel/Gyroscope.lus
+++ b/src/test/should_work/lionel/Gyroscope.lus
@@ -33,12 +33,16 @@ tel
 node assumeSum (accu_in : real; elt_in : real) returns (assumeOK : bool);
 var varBidon : real;
 let
+-- R1: fix that non-def local
+  varBidon = 1.0;
   assumeOK = varBidon < elt_in;
 tel
 
 node guaranteeSum (accu_in : real; elt_in : real; accu_out : real) returns (guaranteeOK : bool);
 var otherVarBidon : real;
 let
+-- R1: fix that non-def local
+  otherVarBidon = 1.0;
   guaranteeOK = elt_in + otherVarBidon < accu_out;
 tel
 
diff --git a/src/test/should_work/lionel/ProduitBool/produitBool.lus b/src/test/should_work/lionel/ProduitBool/produitBool.lus
index 08b24096..1c63ba59 100644
--- a/src/test/should_work/lionel/ProduitBool/produitBool.lus
+++ b/src/test/should_work/lionel/ProduitBool/produitBool.lus
@@ -104,6 +104,9 @@ let
   ligne = if multiplicande=false
           then multiplicande ^ (2*size)
           else shift(acc_in);
+
+-- R1: fix that non-def output
+  acc_out= acc_in;
 tel
 
 
diff --git a/src/test/should_work/packEnvTest/contractForElementSelectionInArray/packageTableau.lus b/src/test/should_work/packEnvTest/contractForElementSelectionInArray/packageTableau.lus
index 84730f71..1fad9fe2 100644
--- a/src/test/should_work/packEnvTest/contractForElementSelectionInArray/packageTableau.lus
+++ b/src/test/should_work/packEnvTest/contractForElementSelectionInArray/packageTableau.lus
@@ -74,6 +74,7 @@ node _isElementOf_(e : elementType; t : arrayType) returns (iselementof : bool);
 var acc_out : T_isElementOf_;
 let
   acc_out = red<<iterated_isElementOf_, size>>(T_isElementOf_{eltToSearch = e; iselementof = false}, t);
+  iselementof = acc_out.iselementof;
 tel
 
 
diff --git a/src/test/test.res.exp b/src/test/test.res.exp
index 8fa143a9..3f22b15b 100644
--- a/src/test/test.res.exp
+++ b/src/test/test.res.exp
@@ -2960,7 +2960,7 @@ Opening file /home/jahier/lus2lic/src/test/should_work/Pascal/left.lus
 type left::truc = left::truc {a : bool^100; b : int};
 node left::toto(x:bool) returns (t:left::truc^3);
 let
-   t[0].a[0..98 step 2][48..0 step -2] = true^25;
+   t[0].a[0..98 step 2][0..48 step 2] = true^25;
    t[0].a[0..98 step 2][1..49 step 2] = false^25;
    t[0].a[1..99 step 2][0] = true;
    t[0].a[1..99 step 2][1] = true;
@@ -3772,34 +3772,42 @@ tel
 ----------------------------------------------------------------------
 ====> ../lus2lic -vl 2 --compile-all-items should_work/clock/clock.lus
 Opening file /home/jahier/lus2lic/src/test/should_work/clock/clock.lus
-extern node clock::clock3(u:bool) returns (toto:bool; y:bool when toto);
+type clock::s = clock::s {x : bool^10; y : bool};
 
-extern node clock::clock4(
-	u:bool;
-	v:bool when u) 
+extern node clock::clock3(
+	clock3_u:bool) 
 returns (
-	x:bool;
-	y:bool when x);
+	clock3_toto:bool;
+	clock3_y:bool when clock3_toto);
 
-extern node clock::clock5(
-	x:bool;
-	y:bool when x;
-	z:bool when y) 
+extern node clock::clock4(
+	clock4_u:bool;
+	clock4_v:bool when clock4_u) 
 returns (
-	a:bool);
+	clock4_x:bool;
+	clock4_y:bool when clock4_x);
 node clock::clock(a:bool; b:bool) returns (c:bool; d:bool when c);
 var
    z:bool;
    x:bool when z;
-   y:bool when x;
-   e:bool when b;
 let
    (z, x) = clock::clock3(z);
    (c, d) = clock::clock4(a, b when a);
-   z = clock::clock5(a, b when a, e when b when a);
 tel
 -- end of node clock::clock
-extern node clock::clock2(u:bool; v:bool when u) returns (y:bool);
+
+extern node clock::clock2(
+	clock2_u:bool;
+	clock2_v:bool when clock2_u) 
+returns (
+	clock2_y:bool);
+
+extern node clock::clock5(
+	x:bool;
+	y:bool when x;
+	z:bool when y) 
+returns (
+	a:bool);
 
 ----------------------------------------------------------------------
 ====> ../lus2lic -vl 2 --compile-all-items should_work/demo/Gyroscope2.lus
@@ -4412,6 +4420,7 @@ var
    c1:real;
 let
    b1 = (a1 / c1);
+   c1 = 1.0;
 tel
 -- end of node declaration::n5
 
@@ -5141,6 +5150,7 @@ let
    (b1, b2, b3) = (tabb[0], tabb[1], tabb[2]);
     (i1, i2, i3) = ((tabi[0][0] + tabi[0][1]), (tabi[1][0] + tabi[1][1]),
 	 (tabi[2][0] + tabi[2][1]));
+   tabb[0] = b;
    tabb[1..2] = [true, false];
    tabi[2] = morel::mcmorel(i);
    tabi[0..1] = [[10, 100], [1000, 10000]];
@@ -6593,6 +6603,7 @@ returns (
 var
    varBidon:real;
 let
+   varBidon = 1.0;
    assumeOK = (varBidon < elt_in);
 tel
 -- end of node Gyroscope::assumeSum
@@ -6808,6 +6819,7 @@ returns (
 var
    otherVarBidon:real;
 let
+   otherVarBidon = 1.0;
    guaranteeOK = ((elt_in + otherVarBidon) < accu_out);
 tel
 -- end of node Gyroscope::guaranteeSum
@@ -6936,6 +6948,7 @@ returns (
 let
     ligne =  if ((multiplicande = false)) then (multiplicande^20) else
 	 (produitBool::shift(acc_in));
+   acc_out = acc_in;
 tel
 -- end of node produitBool::PLC
 
@@ -8419,6 +8432,7 @@ var
 let
     acc_out = red<<node intArray::iterated_isElementOf_, const
 	 10>>(T_isElementOf_{eltToSearch=e;iselementof=false}, t);
+   iselementof = acc_out.iselementof;
 tel
 -- end of node intArray::_isElementOf_
 type intArray::forSortingAlgo = intArray::forSortingAlgo {previousElement : int; sortedUpToHere : bool};
diff --git a/src/uniqueOutput.ml b/src/uniqueOutput.ml
new file mode 100644
index 00000000..8c322759
--- /dev/null
+++ b/src/uniqueOutput.ml
@@ -0,0 +1,334 @@
+
+
+open CompiledData
+open Lxm
+open Errors
+
+(* given a list of (output) [var_info_eff] [vl], and a list of
+   [left_eff] [lel], we want to check that each variable is defined
+   exactly once by the [left_eff].  To do that, we first transform
+   [vl] into a list of variable atoms. 
+*)
+type atom = string
+(*   | Var   of (var_info_eff) *)
+(*   | Field of (atom * Ident.t) *)
+(*   | Array of (atom * int) *)
+
+let rec (var_info_eff_to_atoms: var_info_eff -> atom list) = 
+  fun v -> 
+    type_eff_to_atoms (Ident.to_string v.var_name_eff) v.var_type_eff
+
+and make_int_list acc i = if i < 0 then acc else make_int_list (i::acc) (i-1)
+
+and slice_info_to_int_list si i =
+  if (
+      (si.se_step > 0 && i > si.se_last)
+    ||
+      (si.se_step < 0 && i < si.se_last)
+  ) 
+  then 
+    [] 
+  else
+    i::(slice_info_to_int_list si (i + si.se_step))
+
+
+and (type_eff_to_atoms : atom -> type_eff -> atom list) =
+  fun str type_eff ->
+    let res = 
+      match type_eff with
+	| Bool_type_eff
+	| Int_type_eff
+	| Real_type_eff
+	| Any 
+	| Overload  
+	| External_type_eff _
+	| Enum_type_eff(_,_) -> [str]
+	| Array_type_eff(te,i) -> 
+	    List.flatten
+	      (List.map
+		 (fun i -> type_eff_to_atoms (str ^ "[" ^(string_of_int i)^"]") te)
+		 (make_int_list [] (i-1)))
+	      
+	| Struct_type_eff(name, fl) -> 
+	    List.flatten
+	      (List.map
+		 (fun (id,(te,_)) -> 
+		    type_eff_to_atoms (str ^ "." ^(Ident.to_string id)) te
+		 )
+		 fl)
+    in  
+      res
+
+(* Generates the string corresponding to the [left_eff].  It returns
+   a list of strings because of the slices.  Indeed, when generating
+   the string for the [left_eff] corresponding to "expr[2..3].a", we
+   actually want to generate 2 strings:
+
+   - "expr[2].a", and
+   - "expr[3].a"
+
+   le pb, c'est que pour "t[1..10][2..4]", je veux pas générer
+   - "t[1][2]", etc., 
+   mais "t[3]", "t[4]", "t[5]" ! arg... il me faut faire quelque chose
+   pour les tranches de tranches.
+   
+
+   meme chose pour "T[1..4 step 2][1]" en fait (qui vaut t[3])
+
+   il faudrait que je normalise tout ca avant. Il y a plein de facon de dire
+   la même chose.
+
+   -> rendre le step positif
+   -> mise a plat des tranches de tranches
+   -> mise a plat d'une tranche suivis d'un acces à un tableau 
+
+
+*)
+and (left_eff_to_string : left_eff -> atom list) = 
+  fun le -> 
+    let res = 
+      match le with
+	| LeftVarEff  (v,_) -> [Ident.to_string v.var_name_eff]
+	| LeftFieldEff(le,id,te) -> 
+	    let strl = left_eff_to_string le in
+	      List.map (fun str -> str^"."^(Ident.to_string id)) strl
+	| LeftArrayEff(le,i,te)  -> 
+	    let strl = left_eff_to_string le in
+	      List.map (fun str -> (str ^ "[" ^ (string_of_int i) ^ "]")) strl
+		
+	| LeftSliceEff(LeftSliceEff(le,si1,te1),si2,te2) -> 
+	    assert false
+	| LeftSliceEff(le,si,te) -> 
+	    let strl = left_eff_to_string le in
+	      List.flatten
+		(List.map
+		   (fun i -> List.map 
+		      (fun str -> (str^"["^(string_of_int i) ^ "]")) 
+		      strl)
+		   (slice_info_to_int_list si si.se_first)
+		)
+    in
+      res
+
+and (left_eff_to_atoms : left_eff * Lxm.t -> (atom * Lxm.t) list) =
+  fun (le,lxm) ->
+    let res = 
+      match le with
+	| LeftVarEff  (v,lxm) -> List.map (fun a -> a,lxm) (var_info_eff_to_atoms v)
+
+	| LeftArrayEff(LeftSliceEff(le1,si1,te1),l,te2) ->
+	    (* le1[i..j step k][l] = le1[i + k*l] *)
+	    let (i,j,k) = 
+	      if si1.se_step > 0 
+	      then (si1.se_first, si1.se_last,si1.se_step) 
+	      else (si1.se_last, si1.se_first, - si1.se_step) 
+	    in
+	    let new_l = i + l * k in
+	      left_eff_to_atoms (LeftArrayEff(le1, new_l, te2), lxm)
+
+	| LeftSliceEff(LeftSliceEff(le1,si1,te1),si2,te2) ->
+	    (* we need we interpret on-the-fly slices of slices... 
+	       le1[i1..j1 step k1][i2..j2 step k2] = 
+	              le1[   i1+i2*k1 
+	                  .. i1+(j2+i2*(k1-1))*k2
+	                step k1*k2 ]
+	       if k1 and k2 are positive.
+
+	       k1<0, k2>0
+
+	       what happens if one (or both) are negative ?
+
+	    *)
+	    let (i1,j1,k1) = (si1.se_first, si1.se_last,si1.se_step) in
+	    let (i2,j2,k2) = (si2.se_first, si2.se_last,si2.se_step) in
+	    let si12 = {
+	      se_first = i1+i2*k1;
+	      se_last  = i1+(j2+i2*(k1-1))*k2;
+	      se_step  = k1 * k2; (* bug si < 0 ! *)
+	      se_width = -1;
+	    }
+	    in
+	      left_eff_to_atoms(LeftSliceEff(le1, si12,te2), lxm)
+	| LeftFieldEff(le2,_,te)
+	| LeftArrayEff(le2,_,te)
+	| LeftSliceEff(le2,_,Array_type_eff(te,_)) ->	    
+	    let al = left_eff_to_string le in
+	      List.map (fun a -> a,lxm)
+		(List.flatten (List.map (fun a -> type_eff_to_atoms a te) al))
+    in 
+      res
+
+module StrSet = Set.Make(String)
+
+let (check_aux : Lxm.t -> var_info_eff list -> (left_eff * Lxm.t) list -> unit) =
+  fun lxm vl lel ->
+    let l1 = List.flatten (List.map var_info_eff_to_atoms vl) in
+    let l2 = List.flatten (List.map left_eff_to_atoms lel) in
+(*     let _ =  *)
+(*       print_string ("\noutputs to be defined: "); *)
+(*       List.iter (fun str -> print_string (str ^ ", ")) l1; *)
+(*       print_string ("\ndefined left eff: "); *)
+(*       List.iter (fun (str,_) -> print_string (str ^ ", ")) l2; *)
+(*       print_string "\n checking...\n"; *)
+(*       flush stdout *)
+(*     in *)
+    let set1 = List.fold_left (fun set x -> StrSet.add x set) StrSet.empty l1 in
+    let set2 =
+      List.fold_left
+	(fun set (elt,lxm) -> 
+	   if StrSet.mem elt set then StrSet.remove elt set else
+	     let msg =
+	       if StrSet.mem elt set1 then 
+		 "\n*** This variable is defined twice: " ^ elt
+	       else
+		 "\n*** This variable is undeclared: " ^ elt
+	     in
+	       raise (Compile_error(lxm, msg))
+	)
+	set1
+	l2
+    in
+      if not (StrSet.is_empty set2) then
+	let vars = (StrSet.fold (fun elt acc -> elt::acc) set2 []) in
+	let msg = 
+	  (if List.length vars = 1 then 
+	    "\n*** The following variable is undefined: "
+	  else
+	    "\n*** The following variables are undefined: ") ^
+	  (String.concat ", " vars)
+	in
+	  raise (Compile_error(lxm, msg))
+
+(* Check that each output is defined exactly once *)
+
+let (check : CompiledData.node_exp_eff -> Lxm.t -> unit) =
+  fun node lxm -> 
+    let ol  = match node.loclist_eff with
+	None -> node.outlist_eff 
+      | Some l -> node.outlist_eff @ l
+    in
+      match node.def_eff with  
+	| ExternEff 
+	| AbstractEff -> ()
+	| BodyEff{ eqs_eff = eql } -> 
+	    let lpll = 
+	      List.map 
+		(fun ({ it = (lel,_); src = lxm }) -> 
+		   List.map (fun le -> (le,lxm)) lel
+		) 
+		eql 
+	    in
+	    let (lpl:(left_eff * Lxm.t) list) = List.flatten lpll in
+	    
+	      check_aux lxm ol lpl
+
+
+(* Then, for each chunk, we search in [lel] a element [le] that
+   concerns v, and we compute the list of chunks that correspond to
+   the part of a that is not covered by [le]. That new list of chunks
+   is added to the list of chunks to be checked. And we continue
+   until there are no more chunks or no more [left_eff].
+   
+   In order to reduce the complexity of that algo, we first partition
+   the [lel] according to the variable they define.
+*)
+
+
+(* module VarMap = Map.Make(struct type t=var_info_eff let compare = compare end) *)
+(*  *)
+(* let (partition_var : left_eff list -> (left_eff list) VarMap.t) =  *)
+(*   fun l ->  *)
+(*     List.fold_left *)
+(*       (fun tab le ->  *)
+(* 	 let v = var_info_of_left_eff le in *)
+(* 	   try VarMap.add v (le::(VarMap.find v tab)) tab *)
+(* 	   with Not_found ->  VarMap.add v [le] tab *)
+(*       ) *)
+(*       VarMap.empty *)
+(*       l *)
+(*      *)
+(*  *)
+(* (* Hence, given a list of [left_eff] that all concerns v, it is less *)
+(*    expensive (we operate on smaller lists) to check that [v] is *)
+(*    completety and uniquely defined. *)
+(*  *)
+(*    The idea to perform that check is to, from a left_eff and from a var_info_eff, *)
+(*    generates the list of atomic variables they defined. e.g., an array of *)
+(*    size 10 will generated 10 atomic variables. Then, we just have to *)
+(*    compare the list that comes from the left_eff, and the one that comes from *)
+(*    the output variables. *)
+(*    *)
+(* *) *)
+(*  *)
+(* type atom = *)
+(*   | Var of  *)
+(*   | Field of *)
+(* let ( *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(*  *)
+(* let (check_one_chunk : chunk -> left_eff -> chunk list) = *)
+(*   fun c le -> match c,le with *)
+(*   | Var v -> ( *)
+(*       match le with *)
+(* 	| LeftVarEff  (_,_) -> [] *)
+(* 	| LeftFieldEff(le,id,Struct_type_eff(_,fl)) ->  *)
+(* 	    let fl = List.filter (fun f -> f <> id) fl in *)
+(* 	      List.map (fun (id, (te,_)) -> ) fl *)
+(* 	| LeftArrayEff(le,i,_) ->  *)
+(* 	| LeftSliceEff(le,si,_) ->  *)
+(*     ) *)
+(*  *)
+(*   | Field(c,id),        LeftFieldEff(le,id,_) ->  *)
+(*   | Array(c,i),         LeftArrayEff(le,i,_) ->  *)
+(*   | Slice(c, low, high),LeftSliceEff(le,si,_) ->  *)
+(*      ddd *)
+(*  *)
+(*  *)
+(* let (reconstruct : var_info_eff -> chunk list ->  *)
+(*  *)
+(*  *)
+(*  *)
+(* let (check_one_var : var_info_eff -> left_eff_list -> unit) = *)
+(*   fun v lel ->  *)
+(*     let rec (aux : chunk list -> left_eff_list -> unit) = *)
+(*       fun cl lel ->  *)
+(* 	match cl with *)
+(* 	  | [] -> if lel <> [] then failwith "output variable defined twice" *)
+(* 	  | x::cl -> let new_chunks = check_one_chunk x lel *)
+(* 	    in *)
+(* 	      aux [Var v] lel *)
+(*  *)
+(* let (check_one_chunk : chunk -> left_eff list -> chunk list) = *)
+(*   fun al le ->  *)
+(*     (* checks that le is used in [lel]: *)
+(*        Removes the part that is used, but it migth add some chunks *) *)
+(*     match le with *)
+(*   | LeftVarEff(v,_) -> ( *)
+(*       let (al1, al2) = List.partition (fun a -> a = Var(v)) al in *)
+(*       match al1 with *)
+(* 	| [] -> failwith "output variable undefined" *)
+(* 	| _::_ -> failwith "output variable defined twice" *)
+(* 	| [_] -> al2 *)
+(*     ) *)
+(*   | LeftFieldEff(le,id,_) ->  ( *)
+(*       let (al1, al2) = List.partition (fun a -> a = Field(_,id)) al in *)
+(*       match al1 with *)
+(* 	| [] -> failwith "output variable undefined" *)
+(* 	| _::_ -> failwith "output variable defined twice" *)
+(* 	| [_] -> al2 *)
+(*     ) *)
+(*   | LeftArrayEff(le,i,_)  ->  *)
+(*   | LeftSliceEff(le, si,_) ->  *)
+(*  *)
+(* (* (* (*  *) *) *) *)
-- 
GitLab