From 3e1d20e05c22094981f9dc271b015ffa498c97ed Mon Sep 17 00:00:00 2001
From: ploc <ploc@garoche.net>
Date: Wed, 15 Nov 2017 00:12:57 -0800
Subject: [PATCH] [MCDC] Solved some issues and transformed the code from
 iterators to fold

---
 src/corelang.ml            |  67 ++++-----
 src/corelang.mli           |   2 +-
 src/main_lustre_testgen.ml |  12 +-
 src/pathConditions.ml      | 278 ++++++++++++++++++++++++++-----------
 4 files changed, 241 insertions(+), 118 deletions(-)

diff --git a/src/corelang.ml b/src/corelang.ml
index 694ba1b5..3f335713 100755
--- a/src/corelang.ml
+++ b/src/corelang.ml
@@ -894,45 +894,46 @@ let rec substitute_expr vars_to_replace defs e =
 	  ed
 
   }
-(* FAUT IL RETIRER ?
   
  let rec expr_to_eexpr  expr =
    { eexpr_tag = expr.expr_tag;
-     eexpr_desc = expr_desc_to_eexpr_desc expr.expr_desc;
+     eexpr_qfexpr = expr;
+     eexpr_quantifiers = [];
      eexpr_type = expr.expr_type;
      eexpr_clock = expr.expr_clock;
-     eexpr_loc = expr.expr_loc
+     eexpr_loc = expr.expr_loc;
+     eexpr_normalized = None
    }
- and expr_desc_to_eexpr_desc expr_desc =
-   let conv = expr_to_eexpr in
-   match expr_desc with
-   | Expr_const c -> EExpr_const (match c with
-     | Const_int x -> EConst_int x 
-     | Const_real x -> EConst_real x 
-     | Const_float x -> EConst_float x 
-     | Const_tag x -> EConst_tag x 
-     | _ -> assert false
-
-   )
-   | Expr_ident i -> EExpr_ident i
-   | Expr_tuple el -> EExpr_tuple (List.map conv el)
-
-   | Expr_arrow (e1, e2)-> EExpr_arrow (conv e1, conv e2) 
-   | Expr_fby (e1, e2) -> EExpr_fby (conv e1, conv e2)
-   | Expr_pre e' -> EExpr_pre (conv e')
-   | Expr_appl (i, e', i') -> 
-     EExpr_appl 
-       (i, conv e', match i' with None -> None | Some(id, _) -> Some id)
-
-   | Expr_when _
-   | Expr_merge _ -> assert false
-   | Expr_array _ 
-   | Expr_access _ 
-   | Expr_power _  -> assert false
-   | Expr_ite (c, t, e) -> assert false 
-   | _ -> assert false
-
-     *)
+ (* and expr_desc_to_eexpr_desc expr_desc = *)
+ (*   let conv = expr_to_eexpr in *)
+ (*   match expr_desc with *)
+ (*   | Expr_const c -> EExpr_const (match c with *)
+ (*     | Const_int x -> EConst_int x  *)
+ (*     | Const_real x -> EConst_real x  *)
+ (*     | Const_float x -> EConst_float x  *)
+ (*     | Const_tag x -> EConst_tag x  *)
+ (*     | _ -> assert false *)
+
+ (*   ) *)
+ (*   | Expr_ident i -> EExpr_ident i *)
+ (*   | Expr_tuple el -> EExpr_tuple (List.map conv el) *)
+
+ (*   | Expr_arrow (e1, e2)-> EExpr_arrow (conv e1, conv e2)  *)
+ (*   | Expr_fby (e1, e2) -> EExpr_fby (conv e1, conv e2) *)
+ (*   | Expr_pre e' -> EExpr_pre (conv e') *)
+ (*   | Expr_appl (i, e', i') ->  *)
+ (*     EExpr_appl  *)
+ (*       (i, conv e', match i' with None -> None | Some(id, _) -> Some id) *)
+
+ (*   | Expr_when _ *)
+ (*   | Expr_merge _ -> assert false *)
+ (*   | Expr_array _  *)
+ (*   | Expr_access _  *)
+ (*   | Expr_power _  -> assert false *)
+ (*   | Expr_ite (c, t, e) -> assert false  *)
+ (*   | _ -> assert false *)
+      
+     
 let rec get_expr_calls nodes e =
   let get_calls = get_expr_calls nodes in
   match e.expr_desc with
diff --git a/src/corelang.mli b/src/corelang.mli
index 20bb6786..ea020ab9 100755
--- a/src/corelang.mli
+++ b/src/corelang.mli
@@ -98,7 +98,7 @@ val call_of_expr: expr -> (ident * expr list * expr option)
 val expr_of_dimension: Dimension.dim_expr -> expr
 val dimension_of_expr: expr -> Dimension.dim_expr
 val dimension_of_const: Location.t -> constant -> Dimension.dim_expr
-
+val expr_to_eexpr: expr -> eexpr
 (* REMOVED, pushed in utils.ml   val new_tag : unit -> tag *)
 
 val add_internal_funs: unit -> unit
diff --git a/src/main_lustre_testgen.ml b/src/main_lustre_testgen.ml
index 85b4feac..e9d39e1b 100644
--- a/src/main_lustre_testgen.ml
+++ b/src/main_lustre_testgen.ml
@@ -54,7 +54,17 @@ let testgen_source dirname basename extension =
   *)
   
   if !Options.gen_mcdc then (
-    PathConditions.mcdc prog;
+    let prog_mcdc = PathConditions.mcdc prog in
+  let _, type_env, _ = import_dependencies prog_mcdc in
+
+    let _ = type_decls type_env prog_mcdc in
+
+    let destname = !Options.dest_dir ^ "/" ^ basename in
+    let source_file = destname ^ ".mcdc.lus" in (* Could be changed *)
+    let source_out = open_out source_file in
+    let fmt = formatter_of_out_channel source_out in
+    Printers.pp_prog fmt prog_mcdc;
+    Format.fprintf fmt "@.@?";
     exit 0
   ) ;
 
diff --git a/src/pathConditions.ml b/src/pathConditions.ml
index b97a0608..49882401 100644
--- a/src/pathConditions.ml
+++ b/src/pathConditions.ml
@@ -7,35 +7,45 @@ module IdSet = Set.Make (struct type t = expr * int let compare = compare end)
 
 let inout_vars = ref [] 
 
-let print_tautology_var fmt v =
-  match (Types.repr v.var_type).Types.tdesc with
-  | Types.Tbool -> Format.fprintf fmt "(%s or not %s)" v.var_id v.var_id
-  | Types.Tint -> Format.fprintf fmt "(%s > 0 or %s <= 0)" v.var_id v.var_id
-  | Types.Treal -> Format.fprintf fmt "(%s > 0 or %s <= 0)" v.var_id v.var_id
-  | _ -> Format.fprintf fmt "(true)"
+(* This was used to add inout variables in the final signature. May have to be
+   reactivated later *)
+  
+(* let print_tautology_var fmt v = *)
+(*   match (Types.repr v.var_type).Types.tdesc with *)
+(*   | Types.Tbool -> Format.fprintf fmt "(%s or not %s)" v.var_id v.var_id *)
+(*   | Types.Tint -> Format.fprintf fmt "(%s > 0 or %s <= 0)" v.var_id v.var_id *)
+(*   | Types.Treal -> Format.fprintf fmt "(%s > 0 or %s <= 0)" v.var_id v.var_id *)
+(*   | _ -> Format.fprintf fmt "(true)" *)
 
-let print_path arg = match !inout_vars with
-  | [] -> Format.printf "%t@." arg  
-  | l -> Format.printf "%t and %a@." arg (Utils.fprintf_list ~sep:" and " (fun fmt elem -> print_tautology_var fmt elem)) l
+(* let print_path arg = match !inout_vars with *)
+(*   | [] -> Format.printf "%t@." arg   *)
+(*   | l -> Format.printf "%t and %a@." arg (Utils.fprintf_list ~sep:" and " (fun fmt elem -> print_tautology_var fmt elem)) l *)
 
 let rel_op = ["="; "!="; "<"; "<="; ">" ; ">=" ]
 
-let rec print_pre fmt nb_pre =
-  if nb_pre <= 0 then () 
-  else (
-    Format.fprintf fmt "pre ";
-    print_pre fmt (nb_pre-1)
-  )
+(* Used when we were printing the expression directly. Now we are constructing
+   them as regular expressions.
+
+   let rec print_pre fmt nb_pre = if nb_pre <= 0 then () else ( Format.fprintf
+   fmt "pre "; print_pre fmt (nb_pre-1) )
+*)
+  
+let rec mk_pre n e =
+  if n <= 0 then
+    e
+  else
+    mkexpr e.expr_loc (Expr_pre e)
+   
 (*
-let combine2 f sub1 sub2 = 
-    let elem_e1 = List.fold_right IdSet.add (List.map fst sub1) IdSet.empty in
-    let elem_e2 = List.fold_right IdSet.add (List.map fst sub2) IdSet.empty in
-    let common = IdSet.inter elem_e1 elem_e2 in
-    let sub1_filtered = List.filter (fun (v, _) -> not (IdSet.mem v common)) sub1 in
-    let sub2_filtered = List.filter (fun (v, _) -> not (IdSet.mem v common)) sub2 in
-    (List.map (fun (v, negv) -> (v, f negv e2)) sub1_filtered) @
-      (List.map (fun (v, negv) -> (v, f e1 negv)) sub2_filtered) @
-      (List.map (fun v -> (v, {expr with expr_desc = Expr_arrow(List.assoc v sub1, List.assoc v sub2)}) (IdSet.elements common))      )
+   let combine2 f sub1 sub2 = 
+   let elem_e1 = List.fold_right IdSet.add (List.map fst sub1) IdSet.empty in
+   let elem_e2 = List.fold_right IdSet.add (List.map fst sub2) IdSet.empty in
+   let common = IdSet.inter elem_e1 elem_e2 in
+   let sub1_filtered = List.filter (fun (v, _) -> not (IdSet.mem v common)) sub1 in
+   let sub2_filtered = List.filter (fun (v, _) -> not (IdSet.mem v common)) sub2 in
+   (List.map (fun (v, negv) -> (v, f negv e2)) sub1_filtered) @
+   (List.map (fun (v, negv) -> (v, f e1 negv)) sub2_filtered) @
+   (List.map (fun v -> (v, {expr with expr_desc = Expr_arrow(List.assoc v sub1, List.assoc v sub2)}) (IdSet.elements common))      )
 *)
 
 let rec select (v: expr * int) (active: bool list) (modified: ((expr * int) * expr) list list) (orig: expr list) =
@@ -53,107 +63,209 @@ let combine (f: expr list -> expr ) subs orig : ((expr * int) * expr) list  =
     v, f (select v active_subs subs orig)
   ) (IdSet.elements all)
 
-let rec compute_neg_expr cpt_pre expr = 
+
+(* In a previous version, the printer was introducing fake description, ie
+   tautologies, over inout variables to make sure they were not suppresed by
+   some other algorithms *)
+
+(* Takes the variable on which these coverage criteria will apply, as well as
+   the expression and its negated version. Returns the expr and the variable
+   expression, as well as the two new boolean expressions descibing the two
+   associated modes. *)
+let mcdc_var vi_as_expr expr expr_neg_vi =
+  let loc = expr.expr_loc in
+  let changed_expr = mkpredef_call loc "!=" [expr; expr_neg_vi] in
+  let not_vi_as_expr = mkpredef_call loc "not" [vi_as_expr] in
+  let expr1 = mkpredef_call loc "&&" [vi_as_expr; changed_expr] in
+  let expr2 = mkpredef_call loc "&&" [not_vi_as_expr; changed_expr] in
+  ((expr,vi_as_expr),[expr1;expr2])
+
+  (* Format.printf "%a@." Printers.pp_expr expr1;  *)
+  (* print_path (fun fmt -> Format.fprintf fmt "%a and (%a != %a)" *)
+  (*   Printers.pp_expr vi_as_expr *)
+  (*   Printers.pp_expr expr (\*v*\) *)
+  (*   Printers.pp_expr expr_neg_vi); *)
+  (* Format.printf "%a@." Printers.pp_expr expr2;  *)
+  (* print_path (fun fmt -> Format.fprintf fmt "(not %a) and (%a != %a)" *)
+  (*   Printers.pp_expr vi_as_expr *)
+  (*   Printers.pp_expr expr (\*v*\) *)
+  (*   Printers.pp_expr expr_neg_vi) *)
+    
+let rec compute_neg_expr cpt_pre (expr: LustreSpec.expr) =
+  let neg_list l = 
+    List.fold_right (fun e (vl,el) -> let vl', e' = compute_neg_expr cpt_pre e in (vl'@vl), e'::el) l ([], [])
+  in
   match expr.expr_desc with
   | Expr_tuple l -> 
-    let neg = List.map (compute_neg_expr cpt_pre) l in
-    combine (fun l' -> {expr with expr_desc = Expr_tuple l'}) neg l
-
+     let vl, neg = neg_list l in
+     vl, combine (fun l' -> {expr with expr_desc = Expr_tuple l'}) neg l
+       
   | Expr_ite (i,t,e) when (Types.repr t.expr_type).Types.tdesc = Types.Tbool -> (
     let list = [i; t; e] in
-    let neg = List.map (compute_neg_expr cpt_pre) list in
-    combine (fun l ->
+    let vl, neg = neg_list list in
+    vl, combine (fun l ->
       match l with
       | [i'; t'; e'] -> {expr with expr_desc = Expr_ite(i', t', e')}
       | _ -> assert false
     ) neg list
   )
   | Expr_ite (i,t,e) -> ( (* We return the guard as a new guard *)
-    gen_mcdc_cond_guard i;
+    let vl = gen_mcdc_cond_guard i in
     let list = [i; t; e] in
-    let neg = List.map (compute_neg_expr cpt_pre) list in
-    combine (fun l ->
+    let vl', neg = neg_list list in
+    vl@vl', combine (fun l ->
       match l with
       | [i'; t'; e'] -> {expr with expr_desc = Expr_ite(i', t', e')}
       | _ -> assert false
     ) neg list
   )
   | Expr_arrow (e1, e2) -> 
-    let e1' = compute_neg_expr cpt_pre e1 in
-    let e2' = compute_neg_expr cpt_pre e2 in
-    combine (fun l -> match l with
-    | [x;y] -> { expr with expr_desc = Expr_arrow (x, y) }
-    | _ -> assert false
-    ) [e1'; e2'] [e1; e2]
-  | Expr_pre e -> 
-    List.map 
-      (fun (v, negv) -> (v, { expr with expr_desc = Expr_pre negv } ))
-      (compute_neg_expr (cpt_pre+1) e)
+     let vl1, e1' = compute_neg_expr cpt_pre e1 in
+     let vl2, e2' = compute_neg_expr cpt_pre e2 in
+     vl1@vl2, combine (fun l -> match l with
+     | [x;y] -> { expr with expr_desc = Expr_arrow (x, y) }
+     | _ -> assert false
+     ) [e1'; e2'] [e1; e2]
+
+  | Expr_pre e ->
+     let vl, e' = compute_neg_expr (cpt_pre+1) e in
+     vl, List.map
+       (fun (v, negv) -> (v, { expr with expr_desc = Expr_pre negv } )) e'
 
   | Expr_appl (op_name, args, r) when List.mem op_name rel_op -> 
-    [(expr, cpt_pre), mkpredef_call expr.expr_loc "not" [expr]]
+     [], [(expr, cpt_pre), mkpredef_call expr.expr_loc "not" [expr]]
 
-  | Expr_appl (op_name, args, r) -> 
-    List.map 
-      (fun (v, negv) -> (v, { expr with expr_desc = Expr_appl (op_name, negv, r) } ))
-	(compute_neg_expr cpt_pre args)
+  | Expr_appl (op_name, args, r) ->
+     let vl, args' = compute_neg_expr cpt_pre args in
+     vl, List.map 
+       (fun (v, negv) -> (v, { expr with expr_desc = Expr_appl (op_name, negv, r) } ))
+       args'
 
   | Expr_ident _ when (Types.repr expr.expr_type).Types.tdesc = Types.Tbool ->
-    [(expr, cpt_pre), mkpredef_call expr.expr_loc "not" [expr]]
-  | _ -> []
-
-and  
- gen_mcdc_cond_var v expr =
-  report ~level:1 (fun fmt -> Format.fprintf fmt ".. Generating MC/DC cond for boolean flow %s and expression %a@." v Printers.pp_expr expr);
-  let leafs_n_neg_expr = compute_neg_expr 0 expr in
+     [], [(expr, cpt_pre), mkpredef_call expr.expr_loc "not" [expr]]
+  | _ -> [] (* empty vars *) , [] 
+and gen_mcdc_cond_var v expr =
+  report ~level:1 (fun fmt ->
+    Format.fprintf fmt ".. Generating MC/DC cond for boolean flow %s and expression %a@."
+      v
+      Printers.pp_expr expr);
+  let vl, leafs_n_neg_expr = compute_neg_expr 0 expr in
   if List.length leafs_n_neg_expr > 1 then (
-    List.iter (fun ((vi, nb_pre), expr_neg_vi) -> 
-      print_path (fun fmt -> Format.fprintf fmt "%a%a and (%s != %a)" print_pre nb_pre Printers.pp_expr vi v Printers.pp_expr expr_neg_vi);
-      print_path (fun fmt -> Format.fprintf fmt "(not %a%a) and (%s != %a)" print_pre nb_pre Printers.pp_expr vi v Printers.pp_expr expr_neg_vi)
-    ) leafs_n_neg_expr
+    List.fold_left (fun accu ((vi, nb_pre), expr_neg_vi) ->
+      (mcdc_var  (mk_pre nb_pre vi) expr expr_neg_vi)::accu
+    ) vl leafs_n_neg_expr
   )
+  else vl
 
 and gen_mcdc_cond_guard expr =
-  report ~level:1 (fun fmt -> Format.fprintf fmt".. Generating MC/DC cond for guard %a@." Printers.pp_expr expr);
-  let leafs_n_neg_expr = compute_neg_expr 0 expr in
+  report ~level:1 (fun fmt ->
+    Format.fprintf fmt".. Generating MC/DC cond for guard %a@."
+      Printers.pp_expr expr);
+  let vl, leafs_n_neg_expr = compute_neg_expr 0 expr in
   if List.length leafs_n_neg_expr > 1 then (
-    List.iter (fun ((vi, nb_pre), expr_neg_vi) -> 
-      print_path (fun fmt -> Format.fprintf fmt "%a%a and (%a != %a)" print_pre nb_pre Printers.pp_expr vi Printers.pp_expr expr Printers.pp_expr expr_neg_vi);
-      print_path (fun fmt -> Format.fprintf fmt  "(not %a%a) and (%a != %a)" print_pre nb_pre  Printers.pp_expr vi Printers.pp_expr expr Printers.pp_expr expr_neg_vi)
-   
- ) leafs_n_neg_expr
-  )
+    List.fold_left (fun accu ((vi, nb_pre), expr_neg_vi) ->
+      (mcdc_var  (mk_pre nb_pre vi) expr expr_neg_vi)::accu
+    ) vl leafs_n_neg_expr)
+  else
+    vl
   
 
 let rec mcdc_expr cpt_pre expr = 
   match expr.expr_desc with
-  | Expr_tuple l -> List.iter (mcdc_expr cpt_pre) l
-  | Expr_ite (i,t,e) -> (gen_mcdc_cond_guard i; List.iter (mcdc_expr cpt_pre) [t; e])
-  | Expr_arrow (e1, e2) -> List.iter (mcdc_expr cpt_pre) [e1; e2]
-  | Expr_pre e -> mcdc_expr (cpt_pre+1) e 
-  | Expr_appl (_, args, _) -> mcdc_expr cpt_pre args
-  | _ -> ()
+  | Expr_tuple l ->
+     let vl =
+       List.fold_right (fun e accu_v ->
+	 let vl = mcdc_expr cpt_pre e in
+	 (vl@accu_v))
+	 l
+	 []
+     in
+     vl
+  | Expr_ite (i,t,e) ->
+     let vl_i = gen_mcdc_cond_guard i in
+     let vl_t = mcdc_expr cpt_pre t in
+     let vl_e = mcdc_expr cpt_pre e in
+     vl_i@vl_t@vl_e
+  | Expr_arrow (e1, e2) ->
+     let vl1 = mcdc_expr cpt_pre e1 in
+     let vl2 = mcdc_expr cpt_pre e2 in
+     vl1@vl2
+  | Expr_pre e ->
+     let vl = mcdc_expr (cpt_pre+1) e in
+     vl
+  | Expr_appl (f, args, r) ->
+     let vl = mcdc_expr cpt_pre args in
+     vl
+  | _ -> []
 
 let mcdc_var_def v expr = 
   match (Types.repr expr.expr_type).Types.tdesc with
-  | Types.Tbool -> gen_mcdc_cond_var v expr
-  | _ -> mcdc_expr 0 expr
+  | Types.Tbool ->
+     let vl = gen_mcdc_cond_var v expr in
+     vl
+  | _ -> let vl = mcdc_expr 0 expr in
+	 vl
 
 let mcdc_node_eq eq =
-  match eq.eq_lhs, (Types.repr eq.eq_rhs.expr_type).Types.tdesc, eq.eq_rhs.expr_desc with
-  | [lhs], Types.Tbool, _ -> gen_mcdc_cond_var lhs eq.eq_rhs 
-  | _::_, Types.Ttuple tl, Expr_tuple rhs -> List.iter2 mcdc_var_def eq.eq_lhs rhs
-  | _ -> mcdc_expr 0 eq.eq_rhs 
+  let vl =
+    match eq.eq_lhs, (Types.repr eq.eq_rhs.expr_type).Types.tdesc, eq.eq_rhs.expr_desc with
+    | [lhs], Types.Tbool, _ ->  gen_mcdc_cond_var lhs eq.eq_rhs 
+    | _::_, Types.Ttuple tl, Expr_tuple rhs ->
+       (* We iterate trough pairs, but accumulate variables aside. The resulting
+	  expression shall remain a tuple defintion *)
+       let vl = List.fold_right2 (fun lhs rhs accu ->
+	 let v = mcdc_var_def lhs rhs in
+	 (* we don't care about the expression it. We focus on the coverage
+	    expressions in v *)
+	 v@accu
+       ) eq.eq_lhs rhs []
+       in
+       vl
+    | _ -> mcdc_expr 0 eq.eq_rhs 
+  in
+  vl
 
 let mcdc_node_stmt stmt =
   match stmt with
-  | Eq eq -> mcdc_node_eq eq
+  | Eq eq -> let vl = mcdc_node_eq eq in vl
   | Aut aut -> assert false
 
 let mcdc_top_decl td = 
   match td.top_decl_desc with
-  | Node nd -> List.iter mcdc_node_stmt nd.node_stmts
-  | _ -> ()
+  | Node nd ->
+     let new_coverage_exprs =
+       List.fold_right (
+	 fun s accu_v ->
+	   let vl' = mcdc_node_stmt s in
+	   vl'@accu_v
+       ) nd.node_stmts []
+     in
+     (* We add coverage vars as boolean internal flows. TODO *)
+     let fresh_cov_defs = List.flatten (List.map snd new_coverage_exprs) in
+     let nb_total = List.length fresh_cov_defs in
+     let fresh_cov_vars = List.mapi (fun i cov_expr ->
+       let loc = cov_expr.expr_loc in
+       Format.fprintf Format.str_formatter "__cov_%i_%i" i nb_total;
+       let cov_id = Format.flush_str_formatter () in
+       let cov_var = mkvar_decl loc
+	 (cov_id, mktyp loc Tydec_bool, mkclock loc Ckdec_any, false, None) in
+       let cov_def = Eq (mkeq loc ([cov_id], cov_expr)) in
+       cov_var, cov_def
+     ) fresh_cov_defs
+     in
+     let fresh_vars, fresh_eqs = List.split fresh_cov_vars in
+     let fresh_annots =
+       List.map
+	 (fun v -> {annots =  [["PROPERTY"], expr_to_eexpr (expr_of_vdecl v)]; annot_loc = td.top_decl_loc})
+	 fresh_vars in
+     Format.printf "We have %i coverage criteria for node %s@." nb_total nd.node_id;
+     (* And add them as annotations --%PROPERTY: var TODO *)
+     {td with top_decl_desc = Node {nd with
+       node_locals = nd.node_locals@fresh_vars;
+       node_stmts = nd.node_stmts@fresh_eqs;
+       node_annot = nd.node_annot@fresh_annots
+     }}
+  | _ -> td
 
 
 let mcdc prog =
@@ -170,7 +282,7 @@ let mcdc prog =
       match top.top_decl_desc with
       | Node nd -> nd.node_inputs @ nd.node_outputs
       | _ -> assert false);
-  List.iter mcdc_top_decl prog
+  List.map mcdc_top_decl prog
 
 (* Local Variables: *)
 (* compile-command:"make -C .." *)
-- 
GitLab