From ad4774b0ab1728d9b99aba1c40b7d770eb955fb5 Mon Sep 17 00:00:00 2001
From: ploc <ploc@garoche.net>
Date: Wed, 14 Mar 2018 16:07:48 -0700
Subject: [PATCH] - Normalization parameters (alias and unfold_array) are now
 provided as parameter - program type renamed as program_t - Initiating the
 lustrev tool with dependencies to z3 and seal.

---
 Makefile.in                                   |   6 +-
 configure.ac                                  |  54 +++++-
 src/Makefile.in                               |  10 +-
 src/_tags.in                                  |  10 +-
 src/algebraicLoop.ml                          |   5 +-
 src/backends/backends.ml                      |  25 +++
 src/compiler_stages.ml                        |  10 +-
 src/corelang.mli                              |  18 +-
 src/lustreSpec.ml                             |   2 +-
 src/main_lustre_compiler.ml                   |   4 +-
 src/main_lustre_testgen.ml                    |   6 +-
 src/main_lustre_verifier.ml                   | 135 +++++++++++++
 src/normalization.ml                          |  62 +++---
 src/options_management.ml                     |  11 ++
 src/pluginList.ml.in                          |   2 +-
 src/pluginType.ml                             |   2 +-
 src/plugins.ml                                |  14 +-
 src/plugins/salsa/salsa_plugin.ml             |   2 +-
 src/plugins/scopes/scopes.ml                  |   2 +-
 src/tools/seal_verifier.ml                    |  13 ++
 .../semantics/cPS_lustre_generator.ml         |   2 +-
 .../stateflow/semantics/cPS_transformer.ml    |   4 +-
 src/tools/stateflow/sf_sem.ml                 |   5 +-
 src/tools/zustre_verifier.ml                  | 181 ++++++++++++++++++
 src/verifierList.ml.in                        |   6 +
 src/verifierType.ml                           |  20 ++
 src/verifiers.ml                              |  48 +++++
 27 files changed, 579 insertions(+), 80 deletions(-)
 create mode 100644 src/main_lustre_verifier.ml
 create mode 100644 src/tools/seal_verifier.ml
 create mode 100644 src/tools/zustre_verifier.ml
 create mode 100644 src/verifierList.ml.in
 create mode 100644 src/verifierType.ml
 create mode 100644 src/verifiers.ml

diff --git a/Makefile.in b/Makefile.in
index fe82f551..d26bfde0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -8,7 +8,7 @@ LUSI_LIBS=include/lustrec_math.lusi include/simulink_math_fcn.lusi include/conv.
 LUSI_MPFR_LIB=include/mpfr_lustre.lusi
 LOCAL_BINDIR=bin
 LOCAL_DOCDIR=doc/manual
-BIN_TARGETS = lustrec lustret @lustresf_target@
+BIN_TARGETS = lustrec lustret lustrev @lustresf_target@
 
 DEFAULT_TEST_TARGET=COMPIL_LUS\|MAKE\|BIN\|DIFF
 DEFAULT_EXCLUDE_TEST=LUSTRET
@@ -23,6 +23,10 @@ lustret:
 	@echo Compiling binary lustret
 	@make -C src lustret
 
+lustrev:
+	@echo Compiling binary lustrev
+	@make -C src lustrev
+
 @lustresf@
 
 configure: configure.ac
diff --git a/configure.ac b/configure.ac
index c918eba7..5a253935 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,7 +55,7 @@ dnl AC_MSG_RESULT(Hourrah: ocamlfind found!)
 
 # Checks for libraries.
 # OCamlgraph
-AC_MSG_CHECKING(ocaml libraries required)
+AC_MSG_CHECKING(ocaml libraries required (ocamlgraph cmdliner fmt logs num)) 
 AS_IF([ocamlfind query ocamlgraph cmdliner fmt logs num >/dev/null 2>&1],
     [],[AC_MSG_ERROR(A few ocaml library required. opam install ocamlgraph cmdliner fmt logs num should solve the issue)],
 )
@@ -67,6 +67,36 @@ AS_IF([ocamlfind query yojson >/dev/null 2>&1],
     [yojson=yes; AC_MSG_RESULT(yes)],[yojson=no; AC_MSG_WARN(Yojson required for lustresf. opam install yojson should solve the issue)],
 )
 
+# Seal
+AC_MSG_CHECKING(seal library (optional))
+AS_IF([ocamlfind query seal >/dev/null 2>&1],
+    [seal=yes; AC_MSG_RESULT(yes)],[seal=no; AC_MSG_RESULT(no)],
+)
+AS_IF([test "x$seal" = "xyes"], [
+   AC_SUBST(LUSTREV_SEAL, "(module Seal_verifier.Verifier : VerifierType.S);")
+   AC_SUBST(LUSTREV_SEAL_TAG, "<**/*>: package(seal)")
+])
+
+# z3
+AC_MSG_CHECKING(z3 library (optional))
+AS_IF([ocamlfind query z3 >/dev/null 2>&1],
+    [z3=yes; AC_MSG_RESULT(yes)],[seal=no; AC_MSG_RESULT(no)],
+)
+AS_IF([test "x$z3" = "xyes"], [
+   AC_SUBST(LUSTREV_ZUSTRE, "(module Zustre_verifier.Verifier : VerifierType.S);")
+   AC_SUBST(LUSTREV_Z3_TAG, "<**/*>: package(z3)")
+])
+
+# Tiny
+AC_MSG_CHECKING(tiny library (optional))
+AS_IF([ocamlfind query tiny >/dev/null 2>&1],
+    [tiny=yes; AC_MSG_RESULT(yes)],[tiny=no; AC_MSG_RESULT(no)],
+)
+AS_IF([test "x$tiny" = "xyes"], [
+   AC_SUBST(LUSTREV_TINY, "(module Tiny_verifier.Verifier : VerifierType.S);")
+   AC_SUBST(LUSTREV_TINY_TAG, "<**/*>: package(tiny)")
+])
+
 # Salsa
 AC_ARG_ENABLE(salsa, [AS_HELP_STRING([--disable-salsa],
               [disable Salsa plugin. Enabled by default if available.])])
@@ -79,7 +109,7 @@ AS_IF([ocamlfind query salsa >/dev/null 2>&1],
 
 AS_IF([test "x$enable_salsa" != "xno"], [
   if (test "x$salsa" = xyes ); then
-   AC_SUBST(SALSA, "(module Salsa_plugin.Plugin : PluginType.PluginType);")
+   AC_SUBST(SALSA, "(module Salsa_plugin.Plugin : PluginType.S);")
    AC_SUBST(SALSA_TAG, "<**/*.native> or <plugins/salsa/*.cm?> : package(salsa)")
   fi
 ])
@@ -156,6 +186,7 @@ AC_CONFIG_FILES([Makefile
 		 src/Makefile
 		 src/version.ml
 		 src/pluginList.ml
+		 src/verifierList.ml
 		 src/_tags
 		 src/ocaml_utils.ml
 		 ])
@@ -190,6 +221,25 @@ AC_MSG_NOTICE(********    Plugins    ********)
         AC_MSG_NOTICE([lustresf not available])
       fi
   fi
+AC_MSG_NOTICE(********   Verifiers    ********)
+
+  if (test "x$seal" = "xyes"); then
+      AC_MSG_NOTICE([Seal   enabled])
+  else
+      AC_MSG_NOTICE([Seal   disabled. Require Seal library])
+  fi
+
+  if (test "x$z3" = xyes); then
+      AC_MSG_NOTICE([Zustre enabled])
+  else
+      AC_MSG_NOTICE([Zustre disabled. Require Z3 ocaml library])
+  fi
+
+  if (test "x$tiny" = xyes); then
+      AC_MSG_NOTICE([Tiny   enabled])
+  else
+      AC_MSG_NOTICE([Tiny   disabled. Require Tiny library])
+  fi
 
 AC_MSG_NOTICE(****** Regression Tests  ******)
 if (test "x$valid_test_path" = xfalse); then
diff --git a/src/Makefile.in b/src/Makefile.in
index 59e3ce97..57be0099 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -10,7 +10,7 @@ LUSI_LIBS=include/math.lusi include/conv.lusi
 LOCAL_BINDIR=../bin
 LOCAL_DOCDIR=../doc/manual
 
-all: lustrec lustret
+all: lustrec lustret lustrev
 
 lustrec:
 	@echo Compiling binary lustrec
@@ -24,6 +24,12 @@ lustret:
 	@mkdir -p $(LOCAL_BINDIR)
 	@mv _build/main_lustre_testgen.native $(LOCAL_BINDIR)/lustret
 
+lustrev:
+	@echo Compiling binary lustrev
+	@$(OCAMLBUILD) main_lustre_verifier.native
+	@mkdir -p $(LOCAL_BINDIR)
+	@mv _build/main_lustre_verifier.native $(LOCAL_BINDIR)/lustrev
+
 @lustresf_src@
 
 doc:
@@ -47,4 +53,4 @@ dist-clean: clean
 install:
 	make -C .. install
 
-.PHONY: compile-lusi doc dot lustrec lustret lustrec.odocl clean install dist-clean tests
+.PHONY: compile-lusi doc dot lustrec lustret lustrev lustrec.odocl clean install dist-clean tests
diff --git a/src/_tags.in b/src/_tags.in
index 7e6e8b8d..d91fd0d0 100644
--- a/src/_tags.in
+++ b/src/_tags.in
@@ -10,6 +10,7 @@ true: bin_annot, color(always)
 "plugins/scopes": include
 "plugins/mpfr": include
 "features/machine_types": include
+"tools": include
 "tools/stateflow": include
 "tools/stateflow/common": include
 "tools/stateflow/semantics": include
@@ -23,9 +24,7 @@ true: bin_annot, color(always)
 # packages
 <**/*.native>                   : package(ocamlgraph)
 <**/*.native>                   : use_str
-<**/main_lustre_compiler.native>: use_unix
-<**/main_lustre_testgen.native> : use_unix
-<**/sf_sem.native>              : use_unix
+<**/*.native>                   : use_unix
 <**/*.native>                   : package(num)
 <**/*.ml>                       : package(logs)
 <**/*.native>                   : package(logs)
@@ -45,6 +44,11 @@ true: bin_annot, color(always)
 # Plugin dependencies
 @SALSA_TAG@
 
+# Available solvers
+@LUSTREV_SEAL_TAG@
+@LUSTREV_TINY_TAG@
+@LUSTREV_Z3_TAG@
+
 # Local Variables:
 # mode: conf
 # End:
diff --git a/src/algebraicLoop.ml b/src/algebraicLoop.ml
index 36ca3590..66cc1f8d 100644
--- a/src/algebraicLoop.ml
+++ b/src/algebraicLoop.ml
@@ -157,7 +157,8 @@ let fast_stages_processing prog =
   (* Clock calculus *)
   let _ (*computed_clocks_env*) = Compiler_common.clock_decls clock_env prog in
   (* Normalization *)
-  let prog = Normalization.normalize_prog ~backend:!Options.output prog in
+  let params = Backends.get_normalization_params () in
+  let prog = Normalization.normalize_prog params prog in
   (* Mini stage 2 : Scheduling *)
   let res = Scheduling.schedule_prog prog in
   Options.verbose_level := !Options.verbose_level + 2;
@@ -272,7 +273,7 @@ let rec solving_node max_inlines prog nd existing_al partitions =
     Alarms contain the list of inlining performed or advised for each node. 
     This could be provided as a feedback to the user.
 *)
-let clean_al prog : program * bool * report =
+let clean_al prog : program_t * bool * report =
   let max_inlines = !Options.al_nb_max in
 (* We iterate over each node *)
   let _, prog, al_list =
diff --git a/src/backends/backends.ml b/src/backends/backends.ml
index 1fe68038..b0d4f817 100644
--- a/src/backends/backends.ml
+++ b/src/backends/backends.ml
@@ -16,6 +16,31 @@ let is_functional () =
   | "horn" | "lustre" | "acsl" | "emf" -> true
   | _ -> false
 
+                             
+(* Special treatment of arrows in lustre backend. We want to keep them *)
+let unfold_arrow () =
+  match !Options.output with
+  | "lustre" -> false
+  | _ -> true
+
+(* Forcing ite normalization *)
+let alias_ite () =
+  match !Options.output with
+  | "emf" -> true
+  | _ -> false
+
+(* Forcing basic functions normalization *)
+let alias_internal_fun () =
+  match !Options.output with
+  | "emf" -> true
+  | _ -> false
+
+let get_normalization_params () = {
+    Normalization.unfold_arrow_active = unfold_arrow ();
+    force_alias_ite = alias_ite ();
+    force_alias_internal_fun = alias_internal_fun ();
+  }
+
 
 (* Local Variables: *)
 (* compile-command: "make -k -C .." *)
diff --git a/src/compiler_stages.ml b/src/compiler_stages.ml
index dfc92c78..40e8945b 100644
--- a/src/compiler_stages.ml
+++ b/src/compiler_stages.ml
@@ -3,7 +3,7 @@ open Utils
 open Compiler_common
 open LustreSpec
 
-exception StopPhase1 of program
+exception StopPhase1 of program_t
 
 let dynamic_checks () =
   match !Options.output, !Options.spec with
@@ -22,7 +22,7 @@ let compile_source_to_header prog computed_types_env computed_clocks_env dirname
       begin
 	Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating compiled header file %s@," header_name);
 	Lusic.write_lusic false (Lusic.extract_header dirname basename prog) destname lusic_ext;
-	Lusic.print_lusic_to_h destname lusic_ext
+	if !Options.output = "C" then Lusic.print_lusic_to_h destname lusic_ext
       end
     else
       let lusic = Lusic.read_lusic destname lusic_ext in
@@ -31,7 +31,7 @@ let compile_source_to_header prog computed_types_env computed_clocks_env dirname
 	  Log.report ~level:1 (fun fmt -> fprintf fmt ".. generating compiled header file %s@," header_name);
        	  Lusic.write_lusic false (Lusic.extract_header dirname basename prog) destname lusic_ext;
 	  (*List.iter (fun top_decl -> Format.eprintf "lusic: %a@." Printers.pp_decl top_decl) lusic.Lusic.contents;*)
-	  Lusic.print_lusic_to_h destname lusic_ext
+	  if !Options.output = "C" then Lusic.print_lusic_to_h destname lusic_ext
 	end
       else
 	begin
@@ -47,7 +47,7 @@ let compile_source_to_header prog computed_types_env computed_clocks_env dirname
 
 
 (* From prog to prog *)
-let stage1 prog dirname basename =
+let stage1 params prog dirname basename =
   (* Updating parent node information for variables *)
   Compiler_common.update_vdecl_parents_prog prog;
 
@@ -175,7 +175,7 @@ let stage1 prog dirname basename =
 
   (* Normalization phase *)
   Log.report ~level:1 (fun fmt -> fprintf fmt ".. normalization@,");
-  let prog = Normalization.normalize_prog ~backend:!Options.output prog in
+  let prog = Normalization.normalize_prog params prog in
   Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog);
 
   let prog =
diff --git a/src/corelang.mli b/src/corelang.mli
index da1f8161..70418e57 100755
--- a/src/corelang.mli
+++ b/src/corelang.mli
@@ -110,9 +110,9 @@ val expr_to_eexpr: expr -> eexpr
 
 val add_internal_funs: unit -> unit
 
-val pp_prog_type : Format.formatter -> program -> unit
+val pp_prog_type : Format.formatter -> program_t -> unit
 
-val pp_prog_clock : Format.formatter -> program -> unit
+val pp_prog_clock : Format.formatter -> program_t -> unit
 
 val const_of_top: top_decl -> const_desc
 val node_of_top: top_decl -> node_desc
@@ -120,12 +120,12 @@ val imported_node_of_top: top_decl -> imported_node_desc
 val typedef_of_top: top_decl -> typedef_desc
 val dependency_of_top: top_decl -> (bool * ident)
 
-val get_nodes : program -> top_decl list
-val get_imported_nodes : program -> top_decl list
-val get_consts : program -> top_decl list
-val get_typedefs: program -> top_decl list
-val get_dependencies : program -> top_decl list
-(* val prog_unfold_consts: program -> program *)
+val get_nodes : program_t -> top_decl list
+val get_imported_nodes : program_t -> top_decl list
+val get_consts : program_t -> top_decl list
+val get_typedefs: program_t -> top_decl list
+val get_dependencies : program_t -> top_decl list
+(* val prog_unfold_consts: program_t -> program_t *)
 
 val rename_static: (ident -> Dimension.dim_expr) -> type_dec_desc -> type_dec_desc
 val rename_carrier: (ident -> ident) -> clock_dec_desc -> clock_dec_desc
@@ -142,7 +142,7 @@ val rename_eq : (ident -> ident) -> (ident -> ident) -> eq -> eq
 (** val rename_aut f_node f_var aut *)
 val rename_aut : (ident -> ident) -> (ident -> ident) -> automata_desc -> automata_desc
 (** rename_prog f_node f_var prog *)
-val rename_prog: (ident -> ident) -> (ident -> ident) -> (ident -> ident) -> program -> program
+val rename_prog: (ident -> ident) -> (ident -> ident) -> (ident -> ident) -> program_t -> program_t
 
 val substitute_expr: var_decl list -> eq list -> expr -> expr
 
diff --git a/src/lustreSpec.ml b/src/lustreSpec.ml
index e6f5ab2d..4fb08d08 100644
--- a/src/lustreSpec.ml
+++ b/src/lustreSpec.ml
@@ -211,7 +211,7 @@ type top_decl =
      top_decl_itf: bool;                (* header or source file ? *)
      top_decl_loc: Location.t}          (* the location where it is defined *)
 
-type program = top_decl list
+type program_t = top_decl list
 
 type dep_t = Dep of
     bool
diff --git a/src/main_lustre_compiler.ml b/src/main_lustre_compiler.ml
index 51af25f9..715b29ac 100644
--- a/src/main_lustre_compiler.ml
+++ b/src/main_lustre_compiler.ml
@@ -71,10 +71,12 @@ let rec compile_source dirname basename extension =
     else
       prog
   in
+  let params = Backends.get_normalization_params () in
+
   let prog, dependencies = 
     Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 2>.. Phase 1 : Normalisation@,");
     try 
-      Compiler_stages.stage1 prog dirname basename
+      Compiler_stages.stage1 params prog dirname basename
     with Compiler_stages.StopPhase1 prog -> (
       if !Options.lusi then
 	begin
diff --git a/src/main_lustre_testgen.ml b/src/main_lustre_testgen.ml
index c872f2c4..aa247146 100644
--- a/src/main_lustre_testgen.ml
+++ b/src/main_lustre_testgen.ml
@@ -45,7 +45,8 @@ let testgen_source dirname basename extension =
 
   (* Parsing source *)
   let prog = parse_source source_name in
-  let prog, dependencies = Compiler_stages.stage1 prog dirname basename in
+  let params = Backends.get_normalization_params () in
+  let prog, dependencies = Compiler_stages.stage1 params prog dirname basename in
 
   (* Two cases
      - generation of coverage conditions
@@ -73,7 +74,8 @@ let testgen_source dirname basename extension =
        (2) produced as EMF
     *)
     Options.output := "emf";
-    let prog_mcdc = Normalization.normalize_prog ~backend:"emf" prog_mcdc in
+    let params = Backends.get_normalization_params () in
+    let prog_mcdc = Normalization.normalize_prog params prog_mcdc in
     let machine_code = Compiler_stages.stage2 prog_mcdc in
     let source_emf = source_file ^ ".emf" in 
     let source_out = open_out source_emf in
diff --git a/src/main_lustre_verifier.ml b/src/main_lustre_verifier.ml
new file mode 100644
index 00000000..23f7eae2
--- /dev/null
+++ b/src/main_lustre_verifier.ml
@@ -0,0 +1,135 @@
+(********************************************************************)
+(*                                                                  *)
+(*  The LustreC compiler toolset   /  The LustreC Development Team  *)
+(*  Copyright 2012 -    --   ONERA - CNRS - INPT                    *)
+(*                                                                  *)
+(*  LustreC is free software, distributed WITHOUT ANY WARRANTY      *)
+(*  under the terms of the GNU Lesser General Public License        *)
+(*  version 2.1.                                                    *)
+(*                                                                  *)
+(********************************************************************)
+
+open Format
+open Log
+open Compiler_common
+
+open Utils
+open LustreSpec
+ 
+
+let usage = "Usage: lustrev [options] \x1b[4msource file\x1b[0m"
+
+let extensions = [".ec"; ".lus"; ".lusi"]
+
+
+(* verify a .lus source file 
+
+we have multiple "backends"
+- zustre: linked to z3/spacer. Shall preserve the structure and rely on contracts. Produces both a lustre model with new properties, maybe as a lusi with lustre contract, and a JSON summarizing the results and providing tests cases or counter examples if any
+
+- seal: linked to seal. Require global inline and main node
+  focuses only on the selected node (the main)
+  map the machine code into SEAL datastructure and compute invariants
+  - provides the node and its information (typical point of interest for taylor expansion, range for inputs, existing invariants, computation error for the node content)
+  - simplification of program through taylor expansion
+  - scaling when provided with typical ranges (not required to be sound for the moment)
+  - computation of lyapunov invariants
+  - returns an annotated node with invariants and a JSON to explain computation
+  - could also returns plots
+
+- tiny: linked to tiny library to perform floating point analyses
+  shall be provided with ranges for inputs or local variables (memories)
+  
+*)
+let rec verify dirname basename extension =
+  let source_name = dirname ^ "/" ^ basename ^ extension in
+
+  Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 0>");
+
+  (* Parsing source *)
+  let prog = parse_source source_name in
+
+  (* Checking which solver is active *)
+  let verifier = Verifiers.get_active () in
+  let module Verifier = (val verifier : VerifierType.S) in
+
+  
+  (* Normalizing it *)
+  let prog, dependencies = 
+    Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 2>.. Phase 1 : Normalisation@,");
+    try
+      let params = Verifier.get_normalization_params () in
+      Compiler_stages.stage1 params prog dirname basename
+    with Compiler_stages.StopPhase1 prog -> (
+        assert false
+    )
+  in
+  Log.report ~level:1 (fun fmt -> fprintf fmt "@]@,");
+  Log.report ~level:3 (fun fmt -> fprintf fmt ".. Normalized program:@ %a@ "Printers.pp_prog prog);
+
+  Log.report ~level:1 (fun fmt -> fprintf fmt "@[<v 2>.. Phase 2 : Machines generation@,");
+
+  let machine_code = 
+    Compiler_stages.stage2 prog 
+  in
+
+  Log.report ~level:1 (fun fmt -> fprintf fmt "@]@ ");
+  Log.report ~level:3 (fun fmt -> fprintf fmt ".. Generated machines:@ %a@ "Machine_code.pp_machines machine_code);
+
+  if Scopes.Plugin.show_scopes () then
+    begin
+      let all_scopes = Scopes.compute_scopes prog !Options.main_node in
+      (* Printing scopes *)
+      if !Options.verbose_level >= 1 then
+	Format.printf "Possible scopes are:@   ";
+      Format.printf "@[<v>%a@ @]@ @?" Scopes.print_scopes all_scopes;
+      exit 0
+	
+    end;
+
+  let machine_code = Plugins.refine_machine_code prog machine_code in
+
+  assert (dependencies = []); (* Do not handle deps yet *)
+  Verifier.run basename prog machine_code;
+  begin
+    Log.report ~level:1 (fun fmt -> fprintf fmt ".. done !@ @]@.");
+    (* We stop the process here *)
+    exit 0
+  end
+
+
+let anonymous filename =
+  let ok_ext, ext = List.fold_left
+    (fun (ok, ext) ext' ->
+      if not ok && Filename.check_suffix filename ext' then
+	true, ext'
+      else
+	ok, ext)
+    (false, "") extensions in
+  if ok_ext then
+    let dirname = Filename.dirname filename in
+    let basename = Filename.chop_suffix (Filename.basename filename) ext in
+    verify dirname basename ext
+  else
+    raise (Arg.Bad ("Can only compile *.lusi, *.lus or *.ec files"))
+
+let _ =
+  Global.initialize ();
+  Corelang.add_internal_funs ();
+  try
+    Printexc.record_backtrace true;
+
+    let options = Options_management.lustrev_options @ (Verifiers.options ()) in
+    
+    Arg.parse options anonymous usage
+  with
+  | Parse.Error _
+  | Types.Error (_,_) | Clocks.Error (_,_) -> exit 1
+  | Corelang.Error (_ (* loc *), kind) (*| Task_set.Error _*) -> exit (Error.return_code kind)
+  (* | Causality.Error _  -> exit (Error.return_code Error.AlgebraicLoop) *)
+  | Sys_error msg -> (eprintf "Failure: %s@." msg); exit 1
+  | exc -> (track_exception (); raise exc) 
+
+(* Local Variables: *)
+(* compile-command:"make -C .." *)
+(* End: *)
diff --git a/src/normalization.ml b/src/normalization.ml
index ef6048fd..3b0ac65c 100644
--- a/src/normalization.ml
+++ b/src/normalization.ml
@@ -29,10 +29,19 @@ open Format
       definitions.
 *)
 
-(* Two global variables *)
-let unfold_arrow_active = ref true
-let force_alias_ite = ref false
-let force_alias_internal_fun = ref false
+type param_t =
+  {
+    unfold_arrow_active: bool;
+    force_alias_ite: bool;
+    force_alias_internal_fun: bool;
+  }
+
+let params = ref
+               {
+                 unfold_arrow_active = false;
+                 force_alias_ite = false;
+                 force_alias_internal_fun =false;
+               }
 
   
 let expr_true loc ck =
@@ -230,7 +239,7 @@ let rec normalize_expr ?(alias=true) ?(alias_basic=false) node offsets defvars e
      in
      defvars, mk_norm_expr offsets expr (Expr_appl (id, expr_of_expr_list args.expr_loc norm_args, None))
   | Expr_appl (id, args, None) when Basic_library.is_expr_internal_fun expr
-      && not (!force_alias_internal_fun || alias_basic) ->
+      && not (!params.force_alias_internal_fun || alias_basic) ->
      let defvars, norm_args = normalize_expr ~alias:true node offsets defvars args in
      defvars, mk_norm_expr offsets expr (Expr_appl (id, norm_args, None))
   | Expr_appl (id, args, r) ->
@@ -248,10 +257,10 @@ let rec normalize_expr ?(alias=true) ?(alias_basic=false) node offsets defvars e
        let defvars, norm_expr = normalize_expr node [] defvars norm_expr in
        normalize_expr ~alias:alias node offsets defvars norm_expr
      else
-       mk_expr_alias_opt (alias && (!force_alias_internal_fun || alias_basic
+       mk_expr_alias_opt (alias && (!params.force_alias_internal_fun || alias_basic
 				    || not (Basic_library.is_expr_internal_fun expr)))
 	 node defvars norm_expr
-  | Expr_arrow (e1,e2) when !unfold_arrow_active && not (is_expr_once expr) ->
+  | Expr_arrow (e1,e2) when !params.unfold_arrow_active && not (is_expr_once expr) ->
      (* Here we differ from Colaco paper: arrows are pushed to the top *)
      normalize_expr ~alias:alias node offsets defvars (unfold_arrow expr)
   | Expr_arrow (e1,e2) ->
@@ -328,7 +337,7 @@ and normalize_cond_expr ?(alias=true) node offsets defvars expr =
   | Expr_merge (c, hl) ->
      let defvars, norm_hl = normalize_branches node offsets defvars hl in
      defvars, mk_norm_expr offsets expr (Expr_merge (c, norm_hl))
-  | _ when !force_alias_ite ->
+  | _ when !params.force_alias_ite ->
      (* Forcing alias creation for then/else expressions *)
      let defvars, norm_expr =
        normalize_expr ~alias:alias node offsets defvars expr
@@ -506,34 +515,15 @@ let normalize_decl decl =
     decl'
   | Open _ | ImportedNode _ | Const _ | TypeDef _ -> decl
 
-let normalize_prog ?(backend="C") decls =
-  let old_unfold_arrow_active = !unfold_arrow_active in
-  let old_force_alias_ite = !force_alias_ite in
-  let old_force_alias_internal_fun = !force_alias_internal_fun in
-  
+let normalize_prog p decls =
   (* Backend specific configurations for normalization *)
-  let _ =
-    match backend with
-    | "lustre" ->
-    (* Special treatment of arrows in lustre backend. We want to keep them *)
-       unfold_arrow_active := false;
-    | "emf" -> (
-       (* Forcing ite normalization *)
-      force_alias_ite := true;
-      force_alias_internal_fun := true;
-    )
-    | _ -> () (* No fancy options for other backends *)
-  in
+  params := p;
 
   (* Main algorithm: iterates over nodes *)
-  let res = List.map normalize_decl decls in
-  
-  (* Restoring previous settings *)
-  unfold_arrow_active := old_unfold_arrow_active;
-  force_alias_ite := old_force_alias_ite;
-  force_alias_internal_fun := old_force_alias_internal_fun;
-  res
-  
-  (* Local Variables: *)
-(* compile-command:"make -C .." *)
-(* End: *)
+  List.map normalize_decl decls
+
+    
+           (* Local Variables: *)
+           (* compile-command:"make -C .." *)
+           (* End: *)
+    
diff --git a/src/options_management.ml b/src/options_management.ml
index bdda79c7..2a13ae16 100644
--- a/src/options_management.ml
+++ b/src/options_management.ml
@@ -135,10 +135,21 @@ let lustret_options =
     "-no-mutation-suffix", Arg.Set no_mutation_suffix, "does not rename node with the _mutant suffix"
   ]
 
+let lustrev_options =
+   common_options @
+  [ 
+   "-inline", Arg.Unit (fun () -> global_inline := true; const_unfold := true), "inlines all node calls (require a main node). Implies constant unfolding";
+    "-O", Arg.Set_int optimization, "changes optimization \x1b[4mlevel\x1b[0m <default: 2>";
+]
+
+  
 let plugin_opt (name, activate, options) =
   ( "-" ^ name , Arg.Unit activate, "activate plugin " ^ name ) ::
     (List.map (fun (opt, act, desc) -> "-" ^ name ^ opt, act, desc) options)
  
+let verifier_opt (name, activate, options) =
+  ( "-" ^ name , Arg.Unit activate, "run verifier " ^ name ) ::
+    (List.map (fun (opt, act, desc) -> "-" ^ name ^ opt, act, desc) options)
 
 let get_witness_dir filename =
   (* Make sure the directory exists *)
diff --git a/src/pluginList.ml.in b/src/pluginList.ml.in
index e9aa0b53..6efbd219 100644
--- a/src/pluginList.ml.in
+++ b/src/pluginList.ml.in
@@ -1,5 +1,5 @@
 let plugins =
   [
-    (module Scopes.Plugin : PluginType.PluginType);
+    (module Scopes.Plugin : PluginType.S);
     @SALSA@
   ]
diff --git a/src/pluginType.ml b/src/pluginType.ml
index 5f76b708..84b82bfe 100644
--- a/src/pluginType.ml
+++ b/src/pluginType.ml
@@ -1,4 +1,4 @@
-module type PluginType =
+module type S =
 sig
   val name: string
   val activate: unit -> unit
diff --git a/src/plugins.ml b/src/plugins.ml
index c110ee13..1d0e55c0 100644
--- a/src/plugins.ml
+++ b/src/plugins.ml
@@ -7,32 +7,32 @@ let options () =
   List.flatten (
     List.map Options_management.plugin_opt (
       List.map (fun m ->
-	let module M = (val m : PluginType.PluginType) in
+	let module M = (val m : PluginType.S) in
 	(M.name, M.activate, M.options)
       ) plugins
     ))
 
 let check_force_stateful () =
   List.exists (fun m ->
-	let module M = (val m : PluginType.PluginType) in
+	let module M = (val m : PluginType.S) in
 	M.check_force_stateful ()
   ) plugins
 
 let refine_machine_code prog machine_code =
   List.fold_left (fun accu m ->
-    let module M = (val m : PluginType.PluginType) in
+    let module M = (val m : PluginType.S) in
     M.refine_machine_code prog accu
   ) machine_code plugins
 
 
 let c_backend_main_loop_body_prefix basename mname fmt () = 
-  List.iter (fun (m: (module PluginType.PluginType)) -> 
-    let module M = (val m : PluginType.PluginType) in
+  List.iter (fun (m: (module PluginType.S)) -> 
+    let module M = (val m : PluginType.S) in
     M.c_backend_main_loop_body_prefix basename mname fmt ()) plugins
 
 let c_backend_main_loop_body_suffix fmt () = 
-  List.iter (fun (m: (module PluginType.PluginType)) -> 
-    let module M = (val m : PluginType.PluginType) in
+  List.iter (fun (m: (module PluginType.S)) -> 
+    let module M = (val m : PluginType.S) in
     M.c_backend_main_loop_body_suffix fmt ()) plugins
 
 (* Specific treatment of annotations when inlining, specific of declared plugins *)
diff --git a/src/plugins/salsa/salsa_plugin.ml b/src/plugins/salsa/salsa_plugin.ml
index eed8bf6e..7f575845 100644
--- a/src/plugins/salsa/salsa_plugin.ml
+++ b/src/plugins/salsa/salsa_plugin.ml
@@ -39,4 +39,4 @@ module Plugin =
       machine_code
   
   
- end: PluginType.PluginType)
+ end: PluginType.S)
diff --git a/src/plugins/scopes/scopes.ml b/src/plugins/scopes/scopes.ml
index df009347..58396442 100644
--- a/src/plugins/scopes/scopes.ml
+++ b/src/plugins/scopes/scopes.ml
@@ -239,7 +239,7 @@ let update_machine machine =
 
 module Plugin : (
   sig
-    include PluginType.PluginType
+    include PluginType.S
     val show_scopes: unit -> bool
     end) =
 struct
diff --git a/src/tools/seal_verifier.ml b/src/tools/seal_verifier.ml
new file mode 100644
index 00000000..22a19fc9
--- /dev/null
+++ b/src/tools/seal_verifier.ml
@@ -0,0 +1,13 @@
+let active = ref false
+
+module Verifier =
+  (struct
+    include VerifierType.Default
+    let name = "seal"
+    let options = []
+    let activate () = active := true
+    let is_active () = !active
+    let run basename prog machines = ()
+                    
+  end: VerifierType.S)
+    
diff --git a/src/tools/stateflow/semantics/cPS_lustre_generator.ml b/src/tools/stateflow/semantics/cPS_lustre_generator.ml
index 06088873..891bb983 100644
--- a/src/tools/stateflow/semantics/cPS_lustre_generator.ml
+++ b/src/tools/stateflow/semantics/cPS_lustre_generator.ml
@@ -321,7 +321,7 @@ struct
     in tr 
     
   let mkcomponent :
-  type c. c call_t -> c -> t -> LustreSpec.program =
+  type c. c call_t -> c -> t -> LustreSpec.program_t =
     fun call args ->
       fun tr ->
 	reset_loc ();
diff --git a/src/tools/stateflow/semantics/cPS_transformer.ml b/src/tools/stateflow/semantics/cPS_transformer.ml
index d47dfc4e..3199d6be 100644
--- a/src/tools/stateflow/semantics/cPS_transformer.ml
+++ b/src/tools/stateflow/semantics/cPS_transformer.ml
@@ -78,8 +78,8 @@ sig
   val eval_act : (module ThetaType with type t = t) -> act_t -> t
   val eval_cond : cond_t -> t -> t -> t
   (* val mktransformer : t -> unit *)
-  val mkprincipal : t -> LustreSpec.program
-  val mkcomponent : 'c call_t -> 'c -> t -> LustreSpec.program
+  val mkprincipal : t -> LustreSpec.program_t
+  val mkcomponent : 'c call_t -> 'c -> t -> LustreSpec.program_t
 end
 
 module type ComparableTransformerType =
diff --git a/src/tools/stateflow/sf_sem.ml b/src/tools/stateflow/sf_sem.ml
index 0f7bd182..bcc10983 100644
--- a/src/tools/stateflow/sf_sem.ml
+++ b/src/tools/stateflow/sf_sem.ml
@@ -80,8 +80,9 @@ let _ =
      let auto_out = open_out auto_file in
      let auto_fmt = Format.formatter_of_out_channel auto_out in
      Format.fprintf auto_fmt "%a@." Printers.pp_prog prog;
-     
-     let prog, deps = Compiler_stages.stage1 prog "" "" in
+
+     let params = Backends.get_normalization_params () in
+     let prog, deps = Compiler_stages.stage1 params prog "" "" in
 
      Format.printf "%a@." Printers.pp_prog prog;
      let noauto_file = "sf_gen_test_noauto.lus" in (* Could be changed *)
diff --git a/src/tools/zustre_verifier.ml b/src/tools/zustre_verifier.ml
new file mode 100644
index 00000000..31e0de9b
--- /dev/null
+++ b/src/tools/zustre_verifier.ml
@@ -0,0 +1,181 @@
+open LustreSpec
+open Machine_code
+open Format
+open Horn_backend_common
+open Horn_backend
+   
+let active = ref false
+let ctx = ref (Z3.mk_context [])
+
+let bool_sort = Z3.Boolean.mk_sort !ctx
+let int_sort = Z3.Arithmetic.Integer.mk_sort !ctx
+let real_sort = Z3.Arithmetic.Real.mk_sort !ctx
+
+let const_sorts = Hashtbl.create 13
+let get_const_sort ty_name =
+  Hashtbl.find const_sorts ty_name
+
+let decl_sorts () =
+  Hashtbl.iter (fun typ decl ->
+    match typ with
+    | Tydec_const var ->
+      (match decl.top_decl_desc with
+      | TypeDef tdef -> (
+	match tdef.tydef_desc with
+	| Tydec_enum tl ->
+	  let new_sort = Z3.Enumeration.mk_sort_s !ctx var tl in
+          Hashtbl.add const_sorts var new_sort
+	| _ -> assert false
+      )
+      | _ -> assert false
+      )
+    | _        -> ()) Corelang.type_table
+
+
+let rec type_to_sort t =
+  if Types.is_bool_type t  then bool_sort else
+    if Types.is_int_type t then int_sort else 
+  if Types.is_real_type t then real_sort else 
+  match (Types.repr t).Types.tdesc with
+  | Types.Tconst ty       -> get_const_sort ty
+  | Types.Tclock t        -> type_to_sort t
+  | Types.Tarray(dim,ty)   -> Z3.Z3Array.mk_sort !ctx int_sort (type_to_sort ty)
+  | Types.Tstatic(d, ty)-> type_to_sort ty
+  | Types.Tarrow _
+  | _                     -> Format.eprintf "internal error: pp_type %a@."
+                               Types.print_ty t; assert false
+
+  
+let decl_var id =
+  Z3.FuncDecl.mk_func_decl_s !ctx id.var_id [] (type_to_sort id.var_type)
+
+let decl_machine machines m =
+  if m.Machine_code.mname.node_id = Machine_code.arrow_id then
+    (* We don't print arrow function *)
+    ()
+  else
+    begin
+      let _ = List.map decl_var 
+      	(
+	  (inout_vars machines m)@
+	    (rename_current_list (full_memory_vars machines m)) @
+	    (rename_mid_list (full_memory_vars machines m)) @
+	    (rename_next_list (full_memory_vars machines m)) @
+	    (rename_machine_list m.mname.node_id m.mstep.step_locals)
+	)
+      in
+      ()
+     (*
+      if is_stateless m then
+	begin
+	  (* Declaring single predicate *)
+	  fprintf fmt "(declare-rel %a (%a))@."
+	    pp_machine_stateless_name m.mname.node_id
+	    (Utils.fprintf_list ~sep:" " pp_type)
+	    (List.map (fun v -> v.var_type) (inout_vars machines m));
+
+          match m.mstep.step_asserts with
+	  | [] ->
+	     begin
+
+	       (* Rule for single predicate *)
+	       fprintf fmt "; Stateless step rule @.";
+	       fprintf fmt "@[<v 2>(rule (=> @ ";
+	       ignore (pp_machine_instrs machines ([] (* No reset info for stateless nodes *) )  m fmt m.mstep.step_instrs);
+	       fprintf fmt "@ (%a @[<v 0>%a)@]@]@.))@.@."
+		 pp_machine_stateless_name m.mname.node_id
+		 (Utils.fprintf_list ~sep:" " (pp_horn_var m)) (inout_vars machines m);
+	     end
+	  | assertsl ->
+	     begin
+	       let pp_val = pp_horn_val ~is_lhs:true m.mname.node_id (pp_horn_var m) in
+	       
+	       fprintf fmt "; Stateless step rule with Assertions @.";
+	       (*Rule for step*)
+	       fprintf fmt "@[<v 2>(rule (=> @ (and @ ";
+	       ignore (pp_machine_instrs machines [] m fmt m.mstep.step_instrs);
+	       fprintf fmt "@. %a)@ (%a @[<v 0>%a)@]@]@.))@.@." (pp_conj pp_val) assertsl
+		 pp_machine_stateless_name m.mname.node_id
+		 (Utils.fprintf_list ~sep:" " (pp_horn_var m)) (step_vars machines m);
+	  
+	     end
+	       
+	end
+      else
+	begin
+	  (* Declaring predicate *)
+	  fprintf fmt "(declare-rel %a (%a))@."
+	    pp_machine_reset_name m.mname.node_id
+	    (Utils.fprintf_list ~sep:" " pp_type)
+	    (List.map (fun v -> v.var_type) (reset_vars machines m));
+
+	  fprintf fmt "(declare-rel %a (%a))@."
+	    pp_machine_step_name m.mname.node_id
+	    (Utils.fprintf_list ~sep:" " pp_type)
+	    (List.map (fun v -> v.var_type) (step_vars machines m));
+
+	  pp_print_newline fmt ();
+
+	  (* Rule for reset *)
+	  fprintf fmt "@[<v 2>(rule (=> @ %a@ (%a @[<v 0>%a)@]@]@.))@.@."
+	    (pp_machine_reset machines) m 
+	    pp_machine_reset_name m.mname.node_id
+	    (Utils.fprintf_list ~sep:"@ " (pp_horn_var m)) (reset_vars machines m);
+
+          match m.mstep.step_asserts with
+	  | [] ->
+	     begin
+	       fprintf fmt "; Step rule @.";
+	       (* Rule for step*)
+	       fprintf fmt "@[<v 2>(rule (=> @ ";
+	       ignore (pp_machine_instrs machines [] m fmt m.mstep.step_instrs);
+	       fprintf fmt "@ (%a @[<v 0>%a)@]@]@.))@.@."
+		 pp_machine_step_name m.mname.node_id
+		 (Utils.fprintf_list ~sep:"@ " (pp_horn_var m)) (step_vars machines m);
+	     end
+	  | assertsl -> 
+	     begin
+	       let pp_val = pp_horn_val ~is_lhs:true m.mname.node_id (pp_horn_var m) in
+	       (* print_string pp_val; *)
+	       fprintf fmt "; Step rule with Assertions @.";
+	       
+	       (*Rule for step*)
+	       fprintf fmt "@[<v 2>(rule (=> @ (and @ ";
+	       ignore (pp_machine_instrs machines [] m fmt m.mstep.step_instrs);
+	       fprintf fmt "@. %a)@ (%a @[<v 0>%a)@]@]@.))@.@." (pp_conj pp_val) assertsl
+		 pp_machine_step_name m.mname.node_id
+		 (Utils.fprintf_list ~sep:" " (pp_horn_var m)) (step_vars machines m);
+	     end
+	       
+     	       
+	end
+      *)  end
+
+           
+module Verifier =
+  (struct
+    include VerifierType.Default
+    let name = "zustre"
+    let options = []
+    let activate () = (
+        active := true;
+        Options.output := "horn";
+      )
+    let is_active () = !active
+
+    let get_normalization_params () =
+      (* make sure the output is "Horn" *)
+      assert(!Options.output = "horn");
+      Backends.get_normalization_params ()
+
+    let run basename prog machines =
+      let machines = Machine_code.arrow_machine::machines in
+      let machines = preprocess machines in
+      decl_sorts ();
+      List.iter (decl_machine machines) (List.rev machines);
+
+      
+      ()
+
+  end: VerifierType.S)
+    
diff --git a/src/verifierList.ml.in b/src/verifierList.ml.in
new file mode 100644
index 00000000..322949a2
--- /dev/null
+++ b/src/verifierList.ml.in
@@ -0,0 +1,6 @@
+let verifiers =
+  [
+    @LUSTREV_SEAL@
+    @LUSTREV_ZUSTRE@
+    @LUSTREV_TINY@
+  ]
diff --git a/src/verifierType.ml b/src/verifierType.ml
new file mode 100644
index 00000000..6f2f56d1
--- /dev/null
+++ b/src/verifierType.ml
@@ -0,0 +1,20 @@
+module type S =
+sig
+  val name: string
+  val activate: unit -> unit
+  val is_active: unit -> bool
+  val options: (string * Arg.spec * string) list
+  val get_normalization_params: unit -> Normalization.param_t
+  val run: string -> LustreSpec.program_t -> Machine_code.machine_t list -> unit 
+end
+
+module Default =
+  struct
+
+    let get_normalization_params () = {
+    Normalization.unfold_arrow_active = true;
+    force_alias_ite = false;
+    force_alias_internal_fun = false;
+  }
+
+  end
diff --git a/src/verifiers.ml b/src/verifiers.ml
new file mode 100644
index 00000000..3ad61be5
--- /dev/null
+++ b/src/verifiers.ml
@@ -0,0 +1,48 @@
+open LustreSpec
+
+open VerifierList
+
+let active = ref None
+           
+let options () = 
+  List.flatten (
+    List.map Options_management.verifier_opt (
+      List.map (fun m ->
+	let module M = (val m : VerifierType.S) in
+	(M.name, M.activate, M.options)
+      ) verifiers
+    ))
+  
+let verifier_list verifiers =
+  List.fold_left (fun acc m ->
+      let module M =  (val m : VerifierType.S) in
+      (if acc = "" then "" else acc ^ ", ") ^ M.name
+    ) "" verifiers
+  
+let get_active () =
+  match !active with
+  | None ->
+     begin
+       (* check that a single one is active and register it *)
+       let found =
+         List.fold_left (fun found m ->
+             let module M =  (val m : VerifierType.S) in
+             if M.is_active () then
+               m::found
+             else
+               found
+           ) [] verifiers
+       in
+       match found with
+       | [] -> raise (Sys_error ("Please select one verifier in " ^ verifier_list verifiers))
+       | [m] -> active := Some m; m
+       | _ -> raise (Sys_error ("Too many selected verifiers: " ^ verifier_list found))
+     end
+
+  | Some m -> m
+
+
+                
+                (* Local Variables: *)
+                (* compile-command:"make -C .." *)
+                (* End: *)
-- 
GitLab