From 5b98398a7783a5702467d5fd8e2c5f6c2ef66aa2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A9lio=20Brun?= <lelio.brun@isae-supaero.fr>
Date: Thu, 29 Jul 2021 16:02:24 +0200
Subject: [PATCH] first version working with stateless contracts

---
 src/backends/Ada/ada_backend.ml     | 12 ++--
 src/backends/C/c_backend_common.ml  | 24 ++++----
 src/backends/C/c_backend_common.mli |  1 +
 src/backends/C/c_backend_header.ml  | 69 ++++++++++-----------
 src/backends/C/c_backend_spec.ml    | 81 +++++++++++++++++++++----
 src/backends/C/c_backend_src.ml     | 18 +++++-
 src/backends/C/c_backend_src.mli    |  2 +
 src/backends/EMF/EMF_backend.ml     | 14 +++--
 src/clocks.ml                       |  5 +-
 src/compiler_common.ml              | 55 ++++++++---------
 src/corelang.ml                     |  8 ++-
 src/corelang.mli                    |  1 +
 src/lustre_types.ml                 |  8 ++-
 src/lustre_types.mli                |  8 ++-
 src/machine_code.ml                 | 21 ++++++-
 src/machine_code_common.ml          | 11 +++-
 src/machine_code_types.mli          |  3 +-
 src/normalization.ml                | 94 +++++++++++++++++------------
 src/normalization.mli               |  2 +-
 src/optimize_machine.ml             |  2 +-
 src/parsers/parser_lustre.mly       |  3 +-
 src/printers.ml                     | 92 ++++++++++++++--------------
 src/sortProg.ml                     |  2 +-
 src/spec_types.ml                   |  1 +
 src/spec_types.mli                  |  1 +
 src/types.ml                        |  5 +-
 src/typing.ml                       |  5 +-
 27 files changed, 343 insertions(+), 205 deletions(-)

diff --git a/src/backends/Ada/ada_backend.ml b/src/backends/Ada/ada_backend.ml
index 065ffa71..a94b1b12 100644
--- a/src/backends/Ada/ada_backend.ml
+++ b/src/backends/Ada/ada_backend.ml
@@ -91,11 +91,13 @@ let extract_contract machines m =
     let guarantees =
       match machine_spec.mspec.mnode_spec with
       | Some (Contract contract) ->
-        assert (contract.consts = []);
-        assert (contract.locals = []);
-        assert (contract.stmts = []);
-        assert (contract.assume = []);
-        List.map extract_ident contract.guarantees
+        (* assert (contract.consts = []);
+         * assert (contract.locals = []);
+         * assert (contract.stmts = []);
+         * assert (contract.assume = []);
+         * List.map extract_ident contract.guarantees *)
+        (* TODO *)
+        assert false
       | _ ->
         assert false
     in
diff --git a/src/backends/C/c_backend_common.ml b/src/backends/C/c_backend_common.ml
index ea86dbbb..b3d00c13 100644
--- a/src/backends/C/c_backend_common.ml
+++ b/src/backends/C/c_backend_common.ml
@@ -98,6 +98,7 @@ let mk_call_var_decl loc id =
     var_type = Type_predef.type_arrow (Types.new_var ()) (Types.new_var ());
     var_clock = Clocks.new_var true;
     var_loc = loc;
+    var_is_contract = false;
   }
 
 (* counter for loop variable creation *)
@@ -269,14 +270,15 @@ let pp_basic_c_type ?(pp_c_basic_type_desc = pp_c_basic_type_desc) ?var_opt fmt
   | _ ->
     fprintf fmt "%s" (pp_c_basic_type_desc t)
 
-let pp_c_type ?pp_c_basic_type_desc ?var_opt var_id fmt t =
+let pp_c_type ?(var_is_contract=false) ?pp_c_basic_type_desc ?var_opt var_id fmt t =
   let rec aux t pp_suffix =
     if is_basic_c_type t then
       fprintf
         fmt
-        "%a %s%a"
+        "%a %s%s%a"
         (pp_basic_c_type ?pp_c_basic_type_desc ?var_opt)
         t
+        (if var_is_contract then "\\ghost " else "")
         var_id
         pp_suffix
         ()
@@ -431,9 +433,10 @@ let pp_c_decl_input_var fmt id =
    the case for generics *)
 let pp_c_decl_output_var fmt id =
   if (not !Options.ansi) && Types.is_address_type id.var_type then
-    pp_c_type ~var_opt:id id.var_id fmt id.var_type
+    pp_c_type ~var_is_contract:id.var_is_contract ~var_opt:id id.var_id fmt id.var_type
   else
     pp_c_type
+      ~var_is_contract:id.var_is_contract
       ~var_opt:id
       (sprintf "(*%s)" id.var_id)
       fmt
@@ -882,12 +885,10 @@ module Protos (Mod : MODIFIERS_GHOST_PROTO) = struct
       "@[<v>void %a (@[<v>%a%a%a *%s@])%a@]"
       pp_machine_step_name
       name
-      (pp_comma_list
-         ~pp_eol:pp_print_comma
-         ~pp_epilogue:pp_print_cut
-         pp_c_decl_input_var)
+      (pp_comma_list pp_c_decl_input_var)
       inputs
       (pp_comma_list
+         ~pp_prologue:pp_print_comma
          ~pp_eol:pp_print_comma
          ~pp_epilogue:pp_print_cut
          pp_c_decl_output_var)
@@ -928,12 +929,11 @@ module Protos (Mod : MODIFIERS_GHOST_PROTO) = struct
       "void %a (@[<v>%a%a@])"
       pp_machine_step_name
       name
-      (pp_comma_list
-         ~pp_eol:pp_print_comma
-         ~pp_epilogue:pp_print_cut
-         pp_c_decl_input_var)
+      (pp_comma_list pp_c_decl_input_var)
       inputs
-      (pp_comma_list pp_c_decl_output_var)
+      (pp_comma_list
+         ~pp_prologue:pp_print_comma
+         pp_c_decl_output_var)
       outputs
 end
 
diff --git a/src/backends/C/c_backend_common.mli b/src/backends/C/c_backend_common.mli
index a5a934ed..6243b45d 100644
--- a/src/backends/C/c_backend_common.mli
+++ b/src/backends/C/c_backend_common.mli
@@ -77,6 +77,7 @@ val pp_assign :
   unit
 
 val pp_c_type :
+  ?var_is_contract:bool ->
   ?pp_c_basic_type_desc:(Types.t -> string) ->
   ?var_opt:var_decl ->
   ident ->
diff --git a/src/backends/C/c_backend_header.ml b/src/backends/C/c_backend_header.ml
index f926e84d..e6b9363f 100644
--- a/src/backends/C/c_backend_header.ml
+++ b/src/backends/C/c_backend_header.ml
@@ -119,40 +119,41 @@ functor
       let inode = imported_node_of_top tdecl in
       (*Mod.print_machine_decl_prefix fmt m;*)
       let prototype = inode.nodei_id, inode.nodei_inputs, inode.nodei_outputs in
-      if inode.nodei_prototype = Some "C" then
-        if inode.nodei_stateless then
-          fprintf fmt "extern %a;" pp_stateless_C_prototype prototype
-        else (
-          (* TODO: raise proper error *)
-          Format.eprintf "internal error: pp_machine_decl_top_decl_from_header";
-          assert false)
-      else if inode.nodei_stateless then
-        fprintf fmt "extern %a;" Protos.pp_stateless_prototype prototype
-      else
-        let static_inputs =
-          List.filter (fun v -> v.var_dec_const) inode.nodei_inputs
-        in
-        let used name =
-          List.exists
-            (fun v -> v.var_id = name)
-            (inode.nodei_inputs @ inode.nodei_outputs)
-        in
-        let self = mk_new_name used "self" in
-        let mem = mk_new_name used "mem" in
-        let static_prototype = inode.nodei_id, static_inputs in
-        fprintf
-          fmt
-          "extern %a;@,extern %a;@,extern %a;@,extern %a;@,extern %a;"
-          (Protos.pp_set_reset_prototype self mem)
-          static_prototype
-          (Protos.pp_clear_reset_prototype self mem)
-          static_prototype
-          (Protos.pp_init_prototype self)
-          static_prototype
-          (Protos.pp_clear_prototype self)
-          static_prototype
-          (Protos.pp_step_prototype self mem)
-          prototype
+      if not inode.nodei_iscontract then
+        if inode.nodei_prototype = Some "C" then
+          if inode.nodei_stateless then
+            fprintf fmt "extern %a;" pp_stateless_C_prototype prototype
+          else (
+            (* TODO: raise proper error *)
+            Format.eprintf "internal error: pp_machine_decl_top_decl_from_header";
+            assert false)
+        else if inode.nodei_stateless then
+          fprintf fmt "extern %a;" Protos.pp_stateless_prototype prototype
+        else
+          let static_inputs =
+            List.filter (fun v -> v.var_dec_const) inode.nodei_inputs
+          in
+          let used name =
+            List.exists
+              (fun v -> v.var_id = name)
+              (inode.nodei_inputs @ inode.nodei_outputs)
+          in
+          let self = mk_new_name used "self" in
+          let mem = mk_new_name used "mem" in
+          let static_prototype = inode.nodei_id, static_inputs in
+          fprintf
+            fmt
+            "extern %a;@,extern %a;@,extern %a;@,extern %a;@,extern %a;"
+            (Protos.pp_set_reset_prototype self mem)
+            static_prototype
+            (Protos.pp_clear_reset_prototype self mem)
+            static_prototype
+            (Protos.pp_init_prototype self)
+            static_prototype
+            (Protos.pp_clear_prototype self)
+            static_prototype
+            (Protos.pp_step_prototype self mem)
+            prototype
 
     let pp_const_top_decl fmt tdecl =
       let cdecl = const_of_top tdecl in
diff --git a/src/backends/C/c_backend_spec.ml b/src/backends/C/c_backend_spec.ml
index ace5f218..bc226541 100644
--- a/src/backends/C/c_backend_spec.ml
+++ b/src/backends/C/c_backend_spec.ml
@@ -35,13 +35,19 @@ let pp_acsl_basic_type_desc t_desc =
   else assert false
 (* Not a basic C type. Do not handle arrays or pointers *)
 
-let pp_acsl pp fmt = fprintf fmt "@[<v>/*%@ @[<v>%a@]@,*/@]" pp
+let pp_acsl ?(ghost=false) pp fmt x =
+  let op = if ghost then "" else "*" in
+  let cl = if ghost then "@" else "*" in
+  fprintf fmt "@[<v>/%s%@ @[<v>%a@]@,%s/@]" op pp x cl
 
-let pp_acsl_cut pp fmt = fprintf fmt "%a@," (pp_acsl pp)
+let pp_acsl_cut ?ghost pp fmt = fprintf fmt "%a@," (pp_acsl ?ghost pp)
 
 let pp_acsl_line pp fmt = fprintf fmt "//%@ @[<h>%a@]" pp
 
-let pp_acsl_line' pp fmt = fprintf fmt "/*%@ @[<h>%a@] */" pp
+let pp_acsl_line' ?(ghost=false) pp fmt x =
+  let op = if ghost then "" else "*" in
+  let cl = if ghost then "@" else "*" in
+  fprintf fmt "/%s%@ @[<h>%a@] %s/" op pp x cl
 
 let pp_acsl_line'_cut pp fmt = fprintf fmt "%a@," (pp_acsl_line' pp)
 
@@ -101,6 +107,9 @@ let pp_stdout fmt () = pp_print_string fmt "stdout"
 
 let pp_at pp_v fmt (v, l) = fprintf fmt "\\at(%a, %s)" pp_v v l
 
+let find_machine f =
+  List.find (fun m -> m.mname.node_id = f)
+
 let instances machines m =
   let open List in
   let grow paths i td mems =
@@ -114,7 +123,7 @@ let instances machines m =
     map
       (fun (i, (td, _)) ->
         try
-          let m = find (fun m -> m.mname.node_id = node_name td) machines in
+          let m = find_machine (node_name td) machines in
           aux (grow paths i td m.mmemory) m
         with Not_found -> grow paths i td [])
       m.minstances
@@ -161,14 +170,14 @@ let powerset_instances paths =
 let pp_separated pp_self pp_mem pp_ptr fmt (self, mem, paths, ptrs) =
   fprintf
     fmt
-    "\\separated(@[<v>%a, %a@;%a@;%a@])"
+    "\\separated(@[<v>%a, %a%a%a@])"
     pp_self
     self
     pp_mem
     mem
-    (pp_comma_list ~pp_prologue:pp_print_comma' (pp_instance pp_self self))
+    (pp_comma_list ~pp_prologue:pp_print_comma (pp_instance pp_self self))
     paths
-    (pp_comma_list ~pp_prologue:pp_print_comma' pp_ptr)
+    (pp_comma_list ~pp_prologue:pp_print_comma pp_ptr)
     ptrs
 
 let pp_separated' self mem fmt (paths, ptrs) =
@@ -575,6 +584,9 @@ module PrintSpec = struct
           (pp_and (pp_spec ResetOut) (pp_spec ResetIn))
           fmt
           ((f, mk_mem_reset m), (rc, tr))
+      | Value v ->
+        pp_c_val m mem_in (pp_c_var_read ~test_output:false m) fmt v
+
     in
     pp_spec mode
 end
@@ -948,6 +960,12 @@ module SrcMod = struct
       fmt
       ()
 
+  let pp_node_spec m fmt = function
+    | Contract c ->
+      PrintSpec.pp_spec PrintSpec.TransitionMode m fmt c
+    | NodeSpec f ->
+      pp_print_string fmt f
+
   let pp_step_spec fmt machines self mem m =
     let name = m.mname.node_id in
     let insts = instances machines m in
@@ -960,25 +978,37 @@ module SrcMod = struct
     in
     let inputs = m.mstep.step_inputs in
     let outputs = m.mstep.step_outputs in
+    let pp_if_outputs pp =
+      if outputs = [] then pp_print_nothing else pp
+    in
+    (* prevent printing an ensures clause with contract name *)
+    let spec =
+      match m.mspec.mnode_spec with
+      | Some (NodeSpec _) -> None
+      | s -> s
+    in
     pp_acsl_cut
+      ~ghost:m.mis_contract
       (fun fmt () ->
         if fst (get_stateless_status m) then
           fprintf
             fmt
-            "%a@,%a@,%a@,%a"
-            (pp_requires (pp_valid pp_var_decl))
+            "%a@,%a@,%a@,%a@,%a"
+            (pp_if_outputs (pp_requires (pp_valid pp_var_decl)))
             outputs
-            (pp_requires pp_separated'')
+            (pp_if_outputs (pp_requires pp_separated''))
             outputs
             (pp_assigns pp_ptr_decl)
             outputs
             (pp_ensures (pp_transition_aux' m))
             (name, inputs @ outputs, "", "")
+            (pp_print_option (pp_ensures (pp_node_spec m)))
+            spec
         else
           fprintf
             fmt
-            "%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a"
-            (pp_requires (pp_valid pp_var_decl))
+            "%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a@,%a"
+            (pp_if_outputs (pp_requires (pp_valid pp_var_decl)))
             outputs
             (pp_requires pp_mem_valid')
             (name, self)
@@ -992,6 +1022,8 @@ module SrcMod = struct
                (pp_transition_aux m (pp_old pp_ptr) pp_ptr (fun fmt v ->
                     (if is_output m v then pp_ptr_decl else pp_var_decl) fmt v)))
             (name, inputs @ outputs, mem, mem)
+            (pp_print_option (pp_ensures (pp_node_spec m)))
+            spec
             (pp_assigns pp_ptr_decl)
             outputs
             (pp_assigns (pp_reg self))
@@ -1039,6 +1071,7 @@ module SrcMod = struct
       ()
 
   let pp_step_instr_spec m self mem fmt instr =
+    let ghost = m.mis_contract in
     fprintf
       fmt
       "%a%a"
@@ -1047,7 +1080,7 @@ module SrcMod = struct
       (pp_print_list
          ~pp_open_box:pp_open_vbox0
          ~pp_prologue:pp_print_cut
-         (pp_acsl_line' (pp_assert (PrintSpec.pp_spec (InstrMode self) m))))
+         (pp_acsl_line' ~ghost (pp_assert (PrintSpec.pp_spec (InstrMode self) m))))
       instr.instr_spec
 
   let pp_ghost_parameter mem fmt inst =
@@ -1059,6 +1092,28 @@ module SrcMod = struct
         [ (inst, fun fmt inst -> pp_ref pp_indirect' fmt (mem, inst)) ]
       | None ->
         [ mem, pp_print_string ])
+
+  let pp_contract fmt machines _self m =
+    match m.mspec.mnode_spec with
+    | Some (NodeSpec f) ->
+      let m_f = find_machine f machines in
+      pp_acsl_cut
+        (pp_ghost
+           (fun fmt () ->
+              fprintf
+                fmt
+                "@;<0 2>@[<v>%a%a(%a%a);@]"
+                (pp_print_list ~pp_open_box:pp_open_vbox0 ~pp_sep:pp_print_semicolon ~pp_eol:pp_print_semicolon (pp_c_decl_local_var m))
+                m_f.mstep.step_outputs
+                pp_machine_step_name
+                m_f.mname.node_id
+                (pp_comma_list ~pp_eol:pp_print_comma (pp_c_var_read m))
+                m_f.mstep.step_inputs
+                (pp_comma_list (pp_c_var_write m))
+                m_f.mstep.step_outputs))
+        fmt ()
+    | _ -> ()
+
 end
 
 module MainMod = struct
diff --git a/src/backends/C/c_backend_src.ml b/src/backends/C/c_backend_src.ml
index b1428331..f3dbce18 100644
--- a/src/backends/C/c_backend_src.ml
+++ b/src/backends/C/c_backend_src.ml
@@ -34,6 +34,8 @@ module type MODIFIERS_SRC = sig
     machine_t -> ident -> ident -> formatter -> instr_t -> unit
 
   val pp_ghost_parameter : ident -> formatter -> ident option -> unit
+
+  val pp_contract : formatter -> machine_t list -> ident -> machine_t -> unit
 end
 
 module EmptyMod = struct
@@ -50,6 +52,8 @@ module EmptyMod = struct
   let pp_step_instr_spec _ _ _ _ _ = ()
 
   let pp_ghost_parameter _ _ _ = ()
+
+  let pp_contract _ _ _ _ = ()
 end
 
 module Main (Mod : MODIFIERS_SRC) = struct
@@ -537,7 +541,8 @@ module Main (Mod : MODIFIERS_SRC) = struct
       (pp_c_val m self (pp_c_var_read m))
       check
 
-  let pp_print_function ~pp_prototype ~prototype ?(pp_spec = pp_print_nothing)
+  let pp_print_function ~pp_prototype ~prototype ?(is_contract = false)
+      ?(pp_spec = pp_print_nothing)
       ?(pp_local = pp_print_nothing) ?(base_locals = [])
       ?(pp_array_mem = pp_print_nothing) ?(array_mems = [])
       ?(pp_init_mpfr_local = pp_print_nothing)
@@ -547,7 +552,8 @@ module Main (Mod : MODIFIERS_SRC) = struct
       ?(pp_instr = fun fmt _ -> pp_print_nothing fmt ()) ?(instrs = []) fmt =
     fprintf
       fmt
-      "%a@[<v 2>%a {@,%a%a%a%a%a%a%areturn;@]@,}"
+      "%t%a@[<v 2>%a {@,%a%a%a%a%a%a%areturn;@]@,}%t"
+      (fun fmt -> if is_contract then fprintf fmt "@[<v 2>/*%@ ghost@;")
       pp_spec
       ()
       pp_prototype
@@ -583,6 +589,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
       (mpfr_vars mpfr_locals) (* extra *)
       pp_extra
       ()
+      (fun fmt -> if is_contract then fprintf fmt "@]@;*/")
 
   let node_of_machine m =
     {
@@ -594,9 +601,11 @@ module Main (Mod : MODIFIERS_SRC) = struct
 
   let pp_stateless_code machines dependencies fmt m =
     let self = "__ERROR__" in
+    let is_contract = m.mis_contract in
     if not (!Options.ansi && is_generic_node (node_of_machine m)) then
       (* C99 code *)
       pp_print_function
+        ~is_contract
         ~pp_spec:(fun fmt () -> Mod.pp_step_spec fmt machines self self m)
         ~pp_prototype:Protos.pp_stateless_prototype
         ~prototype:(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
@@ -609,6 +618,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
         ~checks:m.mstep.step_checks
         ~pp_instr:(pp_machine_instr dependencies m self self)
         ~instrs:m.mstep.step_instrs
+        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self m)
         fmt
     else
       (* C90 code *)
@@ -625,6 +635,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
           m.mname.node_gencalls
       in
       pp_print_function
+        ~is_contract
         ~pp_prototype:Protos.pp_stateless_prototype
         ~prototype:
           ( m.mname.node_id,
@@ -639,6 +650,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
         ~checks:m.mstep.step_checks
         ~pp_instr:(pp_machine_instr dependencies m self self)
         ~instrs:m.mstep.step_instrs
+        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self m)
         fmt
 
   let pp_clear_reset_code dependencies self mem fmt m =
@@ -730,6 +742,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
         ~checks:m.mstep.step_checks
         ~pp_instr:(pp_machine_instr dependencies m self mem)
         ~instrs:m.mstep.step_instrs
+        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self m)
         fmt
     else
       (* C90 code *)
@@ -761,6 +774,7 @@ module Main (Mod : MODIFIERS_SRC) = struct
         ~checks:m.mstep.step_checks
         ~pp_instr:(pp_machine_instr dependencies m self mem)
         ~instrs:m.mstep.step_instrs
+        ~pp_extra:(fun fmt () -> Mod.pp_contract fmt machines self m)
         fmt
 
   (********************************************************************************************)
diff --git a/src/backends/C/c_backend_src.mli b/src/backends/C/c_backend_src.mli
index a51a0beb..2eb4add1 100644
--- a/src/backends/C/c_backend_src.mli
+++ b/src/backends/C/c_backend_src.mli
@@ -20,6 +20,8 @@ module type MODIFIERS_SRC = sig
     machine_t -> ident -> ident -> formatter -> instr_t -> unit
 
   val pp_ghost_parameter : ident -> formatter -> ident option -> unit
+
+  val pp_contract : formatter -> machine_t list -> ident -> machine_t -> unit
 end
 
 module EmptyMod : MODIFIERS_SRC
diff --git a/src/backends/EMF/EMF_backend.ml b/src/backends/EMF/EMF_backend.ml
index db2a361d..a605cd13 100644
--- a/src/backends/EMF/EMF_backend.ml
+++ b/src/backends/EMF/EMF_backend.ml
@@ -438,10 +438,13 @@ let pp_emf_spec fmt spec =
    *   pp_emf_vars_decl spec.locals;
    * fprintf fmt "\"stmts\": [%a],@ "
    *   pp_emf_stmts spec.stmts; *)
-  fprintf fmt "\"assume\": [%a],@ " pp_emf_eexprs spec.assume;
-  fprintf fmt "\"guarantees\": [%a],@ " pp_emf_eexprs spec.guarantees;
-  fprintf fmt "\"modes\": [%a]@ " pp_emf_spec_modes spec.modes;
-  (* fprintf fmt "\"imports\": [%a]@ "
+
+  (* TODO *)
+  (* fprintf fmt "\"assume\": [%a],@ " pp_emf_eexprs spec.assume;
+   * fprintf fmt "\"guarantees\": [%a],@ " pp_emf_eexprs spec.guarantees;
+   * fprintf fmt "\"modes\": [%a]@ " pp_emf_spec_modes spec.modes; *)
+
+   (* fprintf fmt "\"imports\": [%a]@ "
    *   pp_emf_spec_imports spec.imports; *)
   fprintf fmt "@] }"
 
@@ -483,7 +486,8 @@ let pp_machine fmt m =
   (match m.mspec.mnode_spec with
    | None -> ()
    | Some (Contract c) ->
-     assert (c.locals = [] && c.consts = [] && c.stmts = [] && c.imports = []);
+     (* TODO *)
+     (* assert (c.locals = [] && c.consts = [] && c.stmts = [] && c.imports = []); *)
      fprintf fmt "\"spec\": %a,@ " pp_emf_spec c
    | Some (NodeSpec id) -> fprintf fmt "\"contract\": \"%s\",@ " id);
   fprintf fmt "\"annots\": {@[<v 0> %a@]@ }"
diff --git a/src/clocks.ml b/src/clocks.ml
index 6a04ed1d..d90a8492 100644
--- a/src/clocks.ml
+++ b/src/clocks.ml
@@ -204,8 +204,9 @@ let split_arrow ck =
     failwith "Internal error: not an arrow clock"
 
 (** Returns the clock corresponding to a clock list. *)
-let clock_of_clock_list ckl =
-  if List.length ckl > 1 then new_ck (Ctuple ckl) true else List.hd ckl
+let clock_of_clock_list = function
+  | [ck] -> ck
+  | ckl -> new_ck (Ctuple ckl) true
 
 let clock_list_of_clock ck =
   match (repr ck).cdesc with Ctuple cl -> cl | _ -> [ ck ]
diff --git a/src/compiler_common.ml b/src/compiler_common.ml
index 89a68947..2c087aef 100644
--- a/src/compiler_common.ml
+++ b/src/compiler_common.ml
@@ -289,7 +289,7 @@ let resolve_contracts prog =
     in
 
     (* Format.eprintf "Process contract new node for node %s@." id; *)
-    let stmts, locals, c =
+    let node_stmts, node_locals, c =
       match spec with
       | None | Some (NodeSpec _) ->
         assert false
@@ -308,32 +308,33 @@ let resolve_contracts prog =
             false)
         (accu_contracts @ prog)
     in
-    let new_nd_id = mk_new_name used (id ^ "_coco") in
-    let new_nd =
-      mktop_decl
-        c.spec_loc
-        top.top_decl_owner
-        top.top_decl_itf
-        (Node
-           {
-             node_id = new_nd_id;
-             node_type = Types.new_var ();
-             node_clock = Clocks.new_var true;
-             node_inputs = inputs;
-             node_outputs = outputs;
-             node_locals = locals;
-             node_gencalls = [];
-             node_checks = [];
-             node_asserts = [];
-             node_stmts = stmts;
-             node_dec_stateless = false;
-             node_stateless = None;
-             node_spec = Some (Contract c);
-             node_annot = [];
-             node_iscontract = true;
-           })
-    in
-    new_nd
+    let nd = {
+      node_id = mk_new_name used (id ^ "_contract");
+      node_type = Types.new_var ();
+      node_clock = Clocks.new_var true;
+      node_inputs = inputs @ outputs;
+      node_outputs = [];
+      node_locals;
+      node_gencalls = [];
+      node_checks = [];
+      node_asserts = [];
+      node_stmts;
+      node_dec_stateless = false;
+      node_stateless = None;
+      node_spec = Some (Contract c);
+      node_annot = [];
+      node_iscontract = true;
+    } in
+    (* let stateless = Stateless.compute_node nd in *)
+    mktop_decl
+      c.spec_loc
+      top.top_decl_owner
+      top.top_decl_itf
+      (Node nd)
+         (* { nd with
+          *   node_dec_stateless = stateless;
+          *   node_stateless = Some stateless;
+          * }) *)
   in
   (* Processing nodes in order. Should have been sorted by now
 
diff --git a/src/corelang.ml b/src/corelang.ml
index b20dd867..2c546608 100644
--- a/src/corelang.ml
+++ b/src/corelang.ml
@@ -53,7 +53,7 @@ let mktyp loc d = { ty_dec_desc = d; ty_dec_loc = loc }
 
 let mkclock loc d = { ck_dec_desc = d; ck_dec_loc = loc }
 
-let mkvar_decl loc ?(orig = false)
+let mkvar_decl loc ?(var_is_contract=false) ?(orig = false)
     (id, ty_dec, ck_dec, is_const, value, parentid) =
   assert (value = None || is_const);
   {
@@ -67,6 +67,7 @@ let mkvar_decl loc ?(orig = false)
     var_type = Types.new_var ();
     var_clock = Clocks.new_var true;
     var_loc = loc;
+    var_is_contract
   }
 
 let dummy_var_decl name typ =
@@ -81,6 +82,7 @@ let dummy_var_decl name typ =
     var_type = typ;
     var_clock = Clocks.new_ck Clocks.Cvar true;
     var_loc = Location.dummy;
+    var_is_contract = false;
   }
 
 let mkexpr loc d =
@@ -106,6 +108,7 @@ let var_decl_of_const ?(parentid = None) c =
     var_type = c.const_type;
     var_clock = Clocks.new_var false;
     var_loc = c.const_loc;
+    var_is_contract = false;
   }
 
 let mk_new_name used id =
@@ -845,6 +848,7 @@ let get_node_interface nd =
     (* nodei_annot = nd.node_annot; *)
     nodei_prototype = None;
     nodei_in_lib = [];
+    nodei_iscontract = nd.node_iscontract;
   }
 
 (************************************************************************)
@@ -1267,6 +1271,7 @@ let mk_internal_node id =
          (* nodei_annot = []; *)
          nodei_prototype = None;
          nodei_in_lib = [];
+         nodei_iscontract = false;
        })
 
 let add_internal_funs () =
@@ -1540,6 +1545,7 @@ let mk_fresh_var (parentid, ctx_env) loc ty ck =
         var_type = ty;
         var_clock = ck;
         var_loc = loc;
+        var_is_contract = false;
       }
   in
   aux ()
diff --git a/src/corelang.mli b/src/corelang.mli
index 2bd3923a..8fa4fedf 100644
--- a/src/corelang.mli
+++ b/src/corelang.mli
@@ -37,6 +37,7 @@ val mkclock : Location.t -> clock_dec_desc -> clock_dec
 
 val mkvar_decl :
   Location.t ->
+  ?var_is_contract:bool ->
   ?orig:bool ->
   ident
   * type_dec
diff --git a/src/lustre_types.ml b/src/lustre_types.ml
index 824193cc..3f8b8371 100644
--- a/src/lustre_types.ml
+++ b/src/lustre_types.ml
@@ -59,6 +59,7 @@ type var_decl = {
   mutable var_type : Types.t;
   mutable var_clock : Clocks.t;
   var_loc : Location.t;
+  var_is_contract: bool;
 }
 (* The tag of an expression is a unique identifier used to distinguish different
    instances of the same node *)
@@ -161,7 +162,7 @@ type contract_desc = {
   spec_loc : Location.t;
 }
 
-type node_spec_t = Contract of contract_desc | NodeSpec of ident
+type 'a node_spec_t = Contract of 'a | NodeSpec of ident
 
 type node_desc = {
   node_id : ident;
@@ -176,7 +177,7 @@ type node_desc = {
   node_stmts : statement list;
   mutable node_dec_stateless : bool;
   mutable node_stateless : bool option;
-  node_spec : node_spec_t option;
+  node_spec : contract_desc node_spec_t option;
   node_annot : expr_annot list;
   node_iscontract : bool;
 }
@@ -188,10 +189,11 @@ type imported_node_desc = {
   nodei_inputs : var_decl list;
   nodei_outputs : var_decl list;
   nodei_stateless : bool;
-  nodei_spec : node_spec_t option;
+  nodei_spec : contract_desc node_spec_t option;
   (* nodei_annot: expr_annot list; *)
   nodei_prototype : string option;
   nodei_in_lib : string list;
+  nodei_iscontract : bool;
 }
 
 type const_desc = {
diff --git a/src/lustre_types.mli b/src/lustre_types.mli
index 07b760b4..1ad1a88f 100644
--- a/src/lustre_types.mli
+++ b/src/lustre_types.mli
@@ -48,6 +48,7 @@ type var_decl = {
   mutable var_type : Types.t;
   mutable var_clock : Clocks.t;
   var_loc : Location.t;
+  var_is_contract: bool;
 }
 (* The tag of an expression is a unique identifier used to distinguish different
    instances of the same node *)
@@ -150,7 +151,7 @@ type contract_desc = {
   spec_loc : Location.t;
 }
 
-type node_spec_t = Contract of contract_desc | NodeSpec of ident
+type 'a node_spec_t = Contract of 'a | NodeSpec of ident
 
 type node_desc = {
   node_id : ident;
@@ -165,7 +166,7 @@ type node_desc = {
   node_stmts : statement list;
   mutable node_dec_stateless : bool;
   mutable node_stateless : bool option;
-  node_spec : node_spec_t option;
+  node_spec : contract_desc node_spec_t option;
   node_annot : expr_annot list;
   node_iscontract : bool;
 }
@@ -177,10 +178,11 @@ type imported_node_desc = {
   nodei_inputs : var_decl list;
   nodei_outputs : var_decl list;
   nodei_stateless : bool;
-  nodei_spec : node_spec_t option;
+  nodei_spec : contract_desc node_spec_t option;
   (* nodei_annot: expr_annot list; *)
   nodei_prototype : string option;
   nodei_in_lib : string list;
+  nodei_iscontract : bool;
 }
 
 type const_desc = {
diff --git a/src/machine_code.ml b/src/machine_code.ml
index b7c4ac4f..77f52136 100644
--- a/src/machine_code.ml
+++ b/src/machine_code.ml
@@ -507,6 +507,23 @@ let transition_toplevel nd i =
     tinst_footprint = IMap.empty;
   }
 
+let translate_eexpr env e =
+  List.fold_right (fun (qt, xs) f -> match qt with
+      | Lustre_types.Exists -> Exists (xs, f)
+      | Lustre_types.Forall -> Forall (xs, f))
+    e.eexpr_quantifiers
+    (Value (translate_expr env e.eexpr_qfexpr))
+
+let translate_contract env c =
+  Imply (And (List.map (translate_eexpr env) c.Lustre_types.assume),
+         And (List.map (translate_eexpr env) c.Lustre_types.guarantees))
+
+let translate_spec env = function
+  | Contract c ->
+    Contract (translate_contract env c)
+  | NodeSpec s ->
+    NodeSpec s
+
 let translate_decl nd sch =
   (* Format.eprintf "Translating node %s@." nd.node_id; *)
   (* Extracting eqs, variables ..  *)
@@ -591,6 +608,7 @@ let translate_decl nd sch =
         @ [ mk_transition ~i:0 nd.node_id (vdecls_to_vals nd.node_inputs) ])
       MClearReset
   in
+  let mnode_spec = Utils.option_map (translate_spec env) nd.node_spec in
   {
     mname = nd;
     mmemory = VSet.elements mems;
@@ -624,9 +642,10 @@ let translate_decl nd sch =
        been processed already. Either one of the other machine is a cocospec
        node, or the current one is a cocospec node. Contract do not contain any
        statement or import. *)
-    mspec = { mnode_spec = nd.node_spec; mtransitions; mmemory_packs };
+    mspec = { mnode_spec; mtransitions; mmemory_packs };
     mannot = nd.node_annot;
     msch = Some sch;
+    mis_contract = nd.node_iscontract
   }
 
 (** takes the global declarations and the scheduling associated to each node *)
diff --git a/src/machine_code_common.ml b/src/machine_code_common.ml
index 420c04f9..3f0d6f7d 100644
--- a/src/machine_code_common.ml
+++ b/src/machine_code_common.ml
@@ -158,6 +158,9 @@ module PrintSpec = struct
         fprintf fmt "StateVarPack<%a>" pp_reg r
       | ExistsMem (_f, a, b) ->
         fprintf fmt "@[<hv 2>∃ MEM,@ %a@]" pp_spec (And [ a; b ])
+      | Value v ->
+        pp_val m fmt v
+
     in
     pp_spec
 end
@@ -310,6 +313,10 @@ let pp_transitions m fmt =
   | _ ->
     fprintf fmt "@[<v 2>transitions:@ %a@]" (pp_print_list (pp_transition m))
 
+let pp_mspec m fmt spec =
+  fprintf fmt "@[<v>contract %a;]"
+    (PrintSpec.pp_spec m) spec
+
 let pp_machine fmt m =
   fprintf
     fmt
@@ -334,7 +341,7 @@ let pp_machine fmt m =
       | Some (NodeSpec id) ->
         fprintf fmt "cocospec: %s" id
       | Some (Contract spec) ->
-        Printers.pp_spec fmt spec)
+        pp_mspec m fmt spec)
     (pp_memory_packs m)
     m.mspec.mmemory_packs
     (pp_transitions m)
@@ -444,6 +451,7 @@ let arrow_machine =
     mspec = { mnode_spec = None; mtransitions = []; mmemory_packs = [] };
     mannot = [];
     msch = None;
+    mis_contract = false
   }
 
 let empty_desc =
@@ -486,6 +494,7 @@ let empty_machine =
     mspec = { mnode_spec = None; mtransitions = []; mmemory_packs = [] };
     mannot = [];
     msch = None;
+    mis_contract = false
   }
 
 let new_instance =
diff --git a/src/machine_code_types.mli b/src/machine_code_types.mli
index 7f2ecfaa..25d8e732 100644
--- a/src/machine_code_types.mli
+++ b/src/machine_code_types.mli
@@ -58,7 +58,7 @@ type mc_transition_t = value_t transition_t
 type mc_memory_pack_t = value_t memory_pack_t
 
 type machine_spec = {
-  mnode_spec : node_spec_t option;
+  mnode_spec : mc_formula_t node_spec_t option;
   mtransitions : mc_transition_t list;
   mmemory_packs : mc_memory_pack_t list;
 }
@@ -79,4 +79,5 @@ type machine_t = {
   mspec : machine_spec;
   mannot : expr_annot list;
   msch : Scheduling_type.schedule_report option; (* Equations scheduling *)
+  mis_contract: bool
 }
diff --git a/src/normalization.ml b/src/normalization.ml
index 2226e942..7e2b3aff 100644
--- a/src/normalization.ml
+++ b/src/normalization.ml
@@ -507,18 +507,18 @@ let normalize_eq_split norm_ctx defvars eq =
 let normalize_pred_eexpr norm_ctx (def, vars) ee =
   assert (ee.eexpr_quantifiers = []);
   (* We do not normalize quantifiers yet. This is for very far future. *)
-  (* don't do anything is eexpr is just a variable *)
-  let skip =
-    match ee.eexpr_qfexpr.expr_desc with
-    | Expr_ident _ | Expr_const _ -> true
-    | _ -> false
-  in
-  if skip then ee, (def, vars)
-  else
+  (* (\* don't do anything if eexpr is just a variable *\)
+   * let skip =
+   *   match ee.eexpr_qfexpr.expr_desc with
+   *   | Expr_ident _ | Expr_const _ -> true
+   *   | _ -> false
+   * in
+   * if skip then None, ee, (def, vars)
+   * else *)
     (* New output variable *)
     let output_id = "spec" ^ string_of_int ee.eexpr_tag in
     let output_var =
-      mkvar_decl ee.eexpr_loc
+      mkvar_decl ~var_is_contract:true ee.eexpr_loc
         ( output_id,
           mktyp ee.eexpr_loc Tydec_bool,
           (* It is a predicate, hence a bool *)
@@ -527,6 +527,8 @@ let normalize_pred_eexpr norm_ctx (def, vars) ee =
           None,
           None )
     in
+    (* It is a predicate, hence a bool *)
+    output_var.var_type <- Type_predef.type_bool;
     let output_expr = expr_of_vdecl output_var in
     (* Rebuilding an eexpr with a silly expression, just a variable *)
     let ee' = { ee with eexpr_qfexpr = output_expr } in
@@ -550,7 +552,7 @@ let normalize_pred_eexpr norm_ctx (def, vars) ee =
     let defs, vars =
       List.fold_left (normalize_eq_split norm_ctx) (def, vars) [ eq ]
     in
-    let vars = output_var :: vars in
+    (* let vars = output_var :: vars in *)
 
     (* let todefine =
        List.fold_left
@@ -575,7 +577,7 @@ let normalize_pred_eexpr norm_ctx (def, vars) ee =
     (*Format.eprintf "normalized eqs %a@.@?" 
       (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs;  *)
          *)
-      ee', (defs, vars)
+      output_var, ee', (defs, vars)
     with Types.Error (loc, err) as exc ->
       eprintf "Typing error for eexpr %a: %a%a%a@." Printers.pp_eexpr ee
         Types.pp_error err
@@ -666,30 +668,33 @@ let normalize_spec parentid (in_vars, out_vars, l_vars) s =
     (* Format.eprintf "ProcPred: vars: %a@." Printers.pp_vars (snd defvars); *)
     let res =
       List.fold_right
-        (fun ee (accu, defvars) ->
-          let ee', defvars = normalize_pred_eexpr norm_ctx defvars ee in
-          ee' :: accu, defvars)
-        l ([], defvars)
+        (fun ee (outputs, accu, defvars) ->
+          let x, ee', defvars = normalize_pred_eexpr norm_ctx defvars ee in
+          x :: outputs, ee' :: accu, defvars)
+        l ([], [], defvars)
     in
     (* Format.eprintf "ProcStmt: %a@." Printers.pp_node_eqs (fst (snd res));
      * Format.eprintf "ProcPred: vars: %a@." Printers.pp_vars (snd (snd res)); *)
     res
   in
 
-  let assume', defsvars = process_predicates s.assume defsvars in
-  let guarantees', defsvars = process_predicates s.guarantees defsvars in
-  let modes', (defs, vars) =
+  let outs_asm, assume', defsvars = process_predicates s.assume defsvars in
+  let outs_grt, guarantees', defsvars = process_predicates s.guarantees defsvars in
+  let outs, modes', (defs, vars) =
     List.fold_right
-      (fun m (accu_m, defsvars) ->
-        let require', defsvars = process_predicates m.require defsvars in
-        let ensure', defsvars = process_predicates m.ensure defsvars in
-        { m with require = require'; ensure = ensure' } :: accu_m, defsvars)
-      s.modes ([], defsvars)
+      (fun m (outs, accu_m, defsvars) ->
+        let outs_req, require', defsvars = process_predicates m.require defsvars in
+        let outs_ens, ensure', defsvars = process_predicates m.ensure defsvars in
+        outs_req @ outs_ens @ outs,
+        { m with require = require'; ensure = ensure' } :: accu_m,
+        defsvars)
+      s.modes (outs_asm @ outs_grt, [], defsvars)
   in
 
   let new_locals = List.filter not_is_orig_var vars in
   (* removing inouts and initial locals ones *)
   ( new_locals,
+    outs,
     defs,
     {
       s with
@@ -725,7 +730,7 @@ let normalize_spec parentid (in_vars, out_vars, l_vars) s =
     - new equations
     -
 *)
-let normalize_node node =
+let normalize_node ?(first=true) node =
   reset_cpt_fresh ();
   let orig_vars = node.node_inputs @ node.node_outputs @ node.node_locals in
   let not_is_orig_var v = List.for_all (( != ) v) orig_vars in
@@ -741,29 +746,29 @@ let normalize_node node =
   let eqs, auts = get_node_eqs node in
   if auts != [] then assert false;
   (* Automata should be expanded by now. *)
-  let spec, new_vars, eqs =
+  let node_spec, new_vars, new_outs, eqs =
     (* Update mutable fields of eexpr to perform normalization of
        specification.
 
        Careful: we do not normalize annotations, since they can have the form
        x = (a, b, c) *)
     match node.node_spec with
-    | None | Some (NodeSpec _) -> node.node_spec, [], eqs
+    | None | Some (NodeSpec _) -> node.node_spec, [], [], eqs
     | Some (Contract s) ->
-        let new_locals, new_stmts, s' =
+        let new_locals, new_outs, new_stmts, s' =
           normalize_spec node.node_id
             (node.node_inputs, node.node_outputs, node.node_locals)
             s
         in
         (* Format.eprintf "Normalization bounded new locals: %a@." Printers.pp_vars new_locals;
          * Format.eprintf "Normalization bounded stmts: %a@." Printers.pp_node_eqs new_stmts; *)
-        Some (Contract s'), new_locals, new_stmts @ eqs
+        Some (Contract s'), new_locals, new_outs, new_stmts @ eqs
   in
   let defs, vars =
     List.fold_left (normalize_eq norm_ctx) ([], new_vars @ orig_vars) eqs
   in
   (* Normalize the asserts *)
-  let vars, assert_defs, asserts =
+  let vars, assert_defs, node_asserts =
     List.fold_left
       (fun (vars, def_accu, assert_accu) assert_ ->
         let assert_expr = assert_.assert_expr in
@@ -786,7 +791,7 @@ let normalize_node node =
 
   (* we filter out inout
      vars and initial locals ones *)
-  let all_locals = node.node_locals @ new_locals in
+  let node_locals = node.node_locals @ new_locals in
 
   (* we add again, at the
      beginning of the list the
@@ -802,7 +807,7 @@ let normalize_node node =
   let new_annots =
     if !Options.traces then
       let diff_vars =
-        List.filter (fun v -> not (List.mem v node.node_locals)) all_locals
+        List.filter (fun v -> not (List.mem v node.node_locals)) node_locals
       in
       let norm_traceability =
         {
@@ -841,7 +846,7 @@ let normalize_node node =
     else node.node_annot
   in
 
-  let new_annots =
+  let node_annot =
     List.fold_left
       (fun annots v ->
         if Machine_types.is_active && Machine_types.is_exportable v then (
@@ -862,14 +867,23 @@ let normalize_node node =
       new_annots new_locals
   in
 
+  let node_inputs, node_outputs =
+    if node.node_iscontract && first then
+      node.node_inputs @ node.node_outputs, new_outs
+    else
+      node.node_inputs, node.node_outputs
+  in
+
   let node =
     {
       node with
-      node_locals = all_locals;
+      node_inputs;
+      node_outputs;
+      node_locals;
       node_stmts = List.map (fun eq -> Eq eq) (defs @ assert_defs);
-      node_asserts = asserts;
-      node_annot = new_annots;
-      node_spec = spec;
+      node_asserts;
+      node_annot;
+      node_spec
     }
   in
   (*Printers.pp_node Format.err_formatter node;*)
@@ -881,10 +895,10 @@ let normalize_inode nd =
   | None | Some (NodeSpec _) -> nd
   | Some (Contract _) -> assert false
 
-let normalize_decl (decl : top_decl) : top_decl =
+let normalize_decl ?first (decl : top_decl) : top_decl =
   match decl.top_decl_desc with
   | Node nd ->
-      let decl' = { decl with top_decl_desc = Node (normalize_node nd) } in
+      let decl' = { decl with top_decl_desc = Node (normalize_node ?first nd) } in
       update_node nd.node_id decl';
       decl'
   | ImportedNode nd ->
@@ -895,12 +909,12 @@ let normalize_decl (decl : top_decl) : top_decl =
       decl'
   | Include _ | Open _ | Const _ | TypeDef _ -> decl
 
-let normalize_prog p decls =
+let normalize_prog ?first p decls =
   (* Backend specific configurations for normalization *)
   params := p;
 
   (* Main algorithm: iterates over nodes *)
-  List.map normalize_decl decls
+  List.map (normalize_decl ?first) decls
 
 (* Fake interface for outside uses *)
 let mk_expr_alias_opt opt (parentid, ctx_vars) (defs, vars) expr =
diff --git a/src/normalization.mli b/src/normalization.mli
index 80503773..43a75c90 100644
--- a/src/normalization.mli
+++ b/src/normalization.mli
@@ -14,4 +14,4 @@ val mk_expr_alias_opt :
   expr ->
   (eq list * var_decl list) * expr
 
-val normalize_prog : param_t -> program_t -> program_t
+val normalize_prog : ?first:bool -> param_t -> program_t -> program_t
diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml
index 7fe096b6..f9d32b40 100644
--- a/src/optimize_machine.ml
+++ b/src/optimize_machine.ml
@@ -952,7 +952,7 @@ let optimize params prog node_schs machine_code =
         else
           let prog = elim_prog_variables prog removed_table in
           (* Mini stage1 *)
-          let prog = Normalization.normalize_prog params prog in
+          let prog = Normalization.normalize_prog ~first:false params prog in
           let prog = SortProg.sort_nodes_locals prog in
           (* Mini stage2: note that we do not protect against alg. loop since
              this should have been handled before *)
diff --git a/src/parsers/parser_lustre.mly b/src/parsers/parser_lustre.mly
index 0964ee6e..8c86a0f3 100644
--- a/src/parsers/parser_lustre.mly
+++ b/src/parsers/parser_lustre.mly
@@ -191,7 +191,8 @@ top_decl_header:
                                 nodei_stateless;
                                 nodei_spec;
                                 nodei_prototype;
-                                nodei_in_lib
+                                nodei_in_lib;
+                                nodei_iscontract = false;
                            })
     in
     pop_node ();
diff --git a/src/printers.ml b/src/printers.ml
index 597c4231..15bae926 100644
--- a/src/printers.ml
+++ b/src/printers.ml
@@ -495,49 +495,47 @@ let pp_spec_stmt fmt stmt =
 let pp_spec fmt spec =
   (* const are prefixed with const in pp_var and with nothing for regular
      variables. We adapt the call to produce the appropriate output. *)
-  pp_print_list
-    (fun fmt v ->
-      fprintf fmt "%a = %t;" pp_var v (fun fmt ->
-          match v.var_dec_value with
-          | None ->
-            assert false
-          | Some e ->
-            pp_expr fmt e))
-    fmt
-    spec.consts;
+  fprintf fmt "@[<v>%a%a%a%a%a%a@]"
+    (pp_print_list
+       (fun fmt v ->
+          fprintf fmt "%a = %t;" pp_var v (fun fmt ->
+              match v.var_dec_value with
+              | None ->
+                assert false
+              | Some e ->
+                pp_expr fmt e)))
+    spec.consts
 
-  pp_print_list (fun fmt s -> pp_spec_stmt fmt s) fmt spec.stmts;
-  pp_print_list
-    (fun fmt r -> fprintf fmt "assume %a;" pp_eexpr r)
-    fmt
-    spec.assume;
-  pp_print_list
-    (fun fmt r -> fprintf fmt "guarantee %a;" pp_eexpr r)
-    fmt
-    spec.guarantees;
-  pp_print_list
-    (fun fmt mode ->
-      fprintf
-        fmt
-        "mode %s (@[<v 0>%a@ %a@]);"
-        mode.mode_id
-        (pp_print_list (fun fmt r -> fprintf fmt "require %a;" pp_eexpr r))
-        mode.require
-        (pp_print_list (fun fmt r -> fprintf fmt "ensure %a;" pp_eexpr r))
-        mode.ensure)
-    fmt
-    spec.modes;
-  pp_print_list
-    (fun fmt import ->
-      fprintf
-        fmt
-        "import %s (%a) returns (%a);"
-        import.import_nodeid
-        pp_expr
-        import.inputs
-        pp_expr
-        import.outputs)
-    fmt
+    (pp_print_list ~pp_prologue:pp_print_cut pp_spec_stmt) spec.stmts
+
+    (pp_print_list ~pp_prologue:pp_print_cut (fun fmt -> fprintf fmt "assume %a;" pp_eexpr))
+    spec.assume
+
+    (pp_print_list ~pp_prologue:pp_print_cut (fun fmt -> fprintf fmt "guarantee %a;" pp_eexpr))
+    spec.guarantees
+
+    (pp_print_list ~pp_prologue:pp_print_cut
+       (fun fmt mode ->
+          fprintf
+            fmt
+            "mode %s (@[<v 0>%a@ %a@]);"
+            mode.mode_id
+            (pp_print_list (fun fmt r -> fprintf fmt "require %a;" pp_eexpr r))
+            mode.require
+            (pp_print_list (fun fmt r -> fprintf fmt "ensure %a;" pp_eexpr r))
+            mode.ensure))
+    spec.modes
+
+    (pp_print_list ~pp_prologue:pp_print_cut
+       (fun fmt import ->
+          fprintf
+            fmt
+            "import %s (%a) returns (%a);"
+            import.import_nodeid
+            pp_expr
+            import.inputs
+            pp_expr
+            import.outputs))
     spec.imports
 
 (* Project the contract node as a pure contract: local memories are pushed back
@@ -754,18 +752,18 @@ let pp_prog pp_decl fmt prog =
 let pp_short_decl fmt decl =
   match decl.top_decl_desc with
   | Node nd ->
-    fprintf fmt "%a %s@ " pp_node_vs_function nd nd.node_id
+    fprintf fmt "%a %s" pp_node_vs_function nd nd.node_id
   | ImportedNode ind ->
     fprintf fmt "imported node %s" ind.nodei_id
   | Const c ->
-    fprintf fmt "const %a@ " pp_const_decl c
+    fprintf fmt "const %a" pp_const_decl c
   | Include s ->
     fprintf fmt "include \"%s\"" s
   | Open (local, s) ->
-    if local then fprintf fmt "#open \"%s\"@ " s
-    else fprintf fmt "#open <%s>@ " s
+    if local then fprintf fmt "#open \"%s\"" s
+    else fprintf fmt "#open <%s>" s
   | TypeDef tdef ->
-    fprintf fmt "type %s;@ " tdef.tydef_id
+    fprintf fmt "type %s" tdef.tydef_id
 
 let pp_prog_short = pp_prog pp_short_decl
 
diff --git a/src/sortProg.ml b/src/sortProg.ml
index 2a386c6a..9c41dca1 100644
--- a/src/sortProg.ml
+++ b/src/sortProg.ml
@@ -53,7 +53,7 @@ let sort prog =
       Format.fprintf
         fmt
         "@ @[<v 2>.. ordered list of declarations:@ %a@]@ "
-        (Format.pp_print_list Printers.pp_short_decl)
+        Format.(pp_print_list ~pp_open_box:pp_open_vbox0 Printers.pp_short_decl)
         sorted);
   not_nodes @ sorted
 
diff --git a/src/spec_types.ml b/src/spec_types.ml
index e39974cf..8eb61540 100644
--- a/src/spec_types.ml
+++ b/src/spec_types.ml
@@ -56,6 +56,7 @@ type 'a formula_t =
   | Predicate : 'a predicate_t -> 'a formula_t
   | StateVarPack of register_t
   | ExistsMem of ident * 'a formula_t * 'a formula_t
+  | Value of 'a
 
 (* type 'a simulation_t = {
  *   sname: node_desc;
diff --git a/src/spec_types.mli b/src/spec_types.mli
index c557a720..5edb4568 100644
--- a/src/spec_types.mli
+++ b/src/spec_types.mli
@@ -49,6 +49,7 @@ type 'a formula_t =
   | Predicate : 'a predicate_t -> 'a formula_t
   | StateVarPack of register_t
   | ExistsMem of ident * 'a formula_t * 'a formula_t
+  | Value of 'a
 
 type 'a transition_t = {
   tname : node_desc;
diff --git a/src/types.ml b/src/types.ml
index de500870..6cfb6b19 100644
--- a/src/types.ml
+++ b/src/types.ml
@@ -589,8 +589,9 @@ module Make (BasicT : BASIC_TYPES) = struct
       assert false
 
   (** Returns the type corresponding to a type list. *)
-  let type_of_type_list tyl =
-    if List.length tyl > 1 then new_ty (Ttuple tyl) else List.hd tyl
+  let type_of_type_list = function
+    | [t] -> t
+    | tyl -> new_ty (Ttuple tyl)
 
   let rec type_list_of_type ty =
     match (repr ty).tdesc with
diff --git a/src/typing.ml b/src/typing.ml
index 74003319..ba7c0877 100644
--- a/src/typing.ml
+++ b/src/typing.ml
@@ -1047,8 +1047,9 @@ struct
    *     assert false *)
 
   let type_prog env decls =
-    try List.fold_left type_top_decl env decls
-    with Failure _ as exc -> raise exc
+    (* try *)
+      List.fold_left type_top_decl env decls
+    (* with Failure _ as exc -> raise exc *)
 
   (* Once the Lustre program is fully typed, we must get back to the original
      description of dimensions, with constant parameters, instead of unifiable
-- 
GitLab