From 1fd3d00272e2289a411c2fafcb158e8643c31114 Mon Sep 17 00:00:00 2001
From: ploc <ploc@garoche.net>
Date: Thu, 21 Mar 2019 09:20:24 -0700
Subject: [PATCH] Cocospec: parsing, normalizing and processing machines for 
 contracts.

---
 src/causality.ml                       |   7 +-
 src/clock_calculus.ml                  |   1 +
 src/clocks.ml                          |   8 --
 src/compiler_common.ml                 | 108 ++++++++++---------
 src/compiler_stages.ml                 |   9 +-
 src/corelang.ml                        | 141 ++++++++++++++++---------
 src/corelang.mli                       |   9 +-
 src/lustre_types.ml                    |   1 +
 src/machine_code.ml                    |  18 +++-
 src/machine_code_common.ml             |   6 +-
 src/machine_code_types.ml              |   1 +
 src/normalization.ml                   |  35 +++---
 src/optimize_machine.ml                |  27 +++--
 src/parsers/lexerLustreSpec.mll        |   2 +-
 src/parsers/lexer_lustre.mll           |   2 +-
 src/parsers/parser_lustre.mly          |  12 +++
 src/plugins/salsa/machine_salsa_opt.ml |   6 +-
 src/printers.ml                        |  60 ++++++-----
 src/typing.ml                          |   7 +-
 19 files changed, 285 insertions(+), 175 deletions(-)

diff --git a/src/causality.ml b/src/causality.ml
index 97f65972..78be31e6 100644
--- a/src/causality.ml
+++ b/src/causality.ml
@@ -384,8 +384,13 @@ module NodeDep = struct
 		  )
 	       )
       	   in
+           let deps_spec = match nd.node_spec with
+             | None -> []
+             | Some (NodeSpec id) -> [id]
+             | Some (Contract c) -> []
+           in
 	   (*Format.eprintf "%a@.@?" (Utils.fprintf_list ~sep:"@." Format.pp_print_string) deps; *)
-	   add_edges [nd.node_id] (deps@deps_asserts) accu
+	   add_edges [nd.node_id] (deps@deps_asserts@deps_spec) accu
 	| _ -> assert false (* should not happen *)
 	   
       ) prog g in
diff --git a/src/clock_calculus.ml b/src/clock_calculus.ml
index 520704ef..2324b496 100644
--- a/src/clock_calculus.ml
+++ b/src/clock_calculus.ml
@@ -493,6 +493,7 @@ and clock_appl env f args clock_reset loc =
     clock_call env f args clock_reset loc
 
 and clock_call env f args clock_reset loc =
+  (* Format.eprintf "Clocking call %s@." f; *)
   let cfun = clock_ident false env f loc in
   let cins, couts = split_arrow cfun in
   let cins = clock_list_of_clock cins in
diff --git a/src/clocks.ml b/src/clocks.ml
index c148d482..9fc3ecaa 100644
--- a/src/clocks.ml
+++ b/src/clocks.ml
@@ -132,14 +132,6 @@ let rec carrier_repr =
   function {carrier_desc = Carry_link cr'} -> carrier_repr cr'
     | cr -> cr
 
-(** Splits [ck] into the [lhs,rhs] of an arrow clock. Expects an arrow clock
-    (ensured by language syntax) *)
-let split_arrow ck =
-  match (repr ck).cdesc with
-  | Carrow (cin,cout) -> cin,cout
-    (* Functions are not first order, I don't think the var case
-       needs to be considered here *)
-  | _ -> failwith "Internal error: not an arrow clock"
 
 let get_carrier_name ck =
  match (repr ck).cdesc with
diff --git a/src/compiler_common.ml b/src/compiler_common.ml
index 2e347c31..b145bbad 100644
--- a/src/compiler_common.ml
+++ b/src/compiler_common.ml
@@ -190,7 +190,8 @@ let check_compatibility (prog, computed_types_env, computed_clocks_env) (header,
 (* Process each node/imported node and introduce the associated contract node *)
 let resolve_contracts prog =
   (* Bind a fresh node with a new name according to existing nodes and freshly binded contract node. Clean the contract to remove the stmts  *)
-  let process_contract new_contracts prog c =
+  let process_contract new_contracts c =
+    Format.eprintf "Process contract@.";
     (* Resolve first the imports *)
     let stmts, locals, c =
       List.fold_left (
@@ -204,50 +205,55 @@ let resolve_contracts prog =
              Last the contracts elements are replaced with the renamed vars and merged with c contract.
            *)
           let name = import.import_nodeid in
-          assert false; (* TODO: we do not handle imports yet.  The
-                           algorithm is sketched below *)
-        (*
+          Format.eprintf "Process contract import %s@." name;
+          let loc = import.import_loc in
           try
-            let imp_nd = xxx in (* Get the contract node in prog *)
+            let imp_nd = get_node name new_contracts in (* Get the contract node in process contracts *)
             (* checking that it's actually a (processed) contract *)
-            let imp_c =
-              match imp_nd.node_spec with
-                Some (Contract imp_c) ->
-                 if imp_c.imports = [] then
-                   imp_c
-                 else
-                   assert false (* should be processed *)
-              | _ -> assert false (* should be a contract *)
-            in  
-            (* Preparing vars: renaming them *)
-            let imp_in = rename imp_nd.node_inputs in
-            let imp_out = rename imp_nd.node_outputs in
-            let imp_locals = rename imp_nd.node_locals in
-            let locals = imp_in@imp_out@imp_locals@locals in
-            (* Assinging in and out *)
-            let in_assigns =
-              xxx imp_in = import.inputs
+            let _ =
+              if not (is_node_contract imp_nd) then
+                assert false (* should be a contract *)
+              else
+                let imp_c = get_node_contract imp_nd in
+                if not (imp_c.imports = [] && imp_c.locals = [] && imp_c.consts = [] && imp_c.stmts = []) then
+                (  Format.eprintf "Invalid processed contract: %i %i %i %i@.@?" (List.length imp_c.imports) (List.length imp_c.locals) (List.length imp_c.consts) (List.length imp_c.stmts);
+                assert false (* should be processed *)
+                )
             in
-            let out_assigns =
-              xxx imp_out = import.outputs
+            let name_prefix x = "__" ^ name ^ "__" ^ x in
+            let imp_nd = rename_node (fun x -> x (* not changing node names *)) name_prefix imp_nd in
+            let imp_in = imp_nd.node_inputs in
+            let imp_out = imp_nd.node_outputs in
+            let imp_locals = imp_nd.node_locals in
+            let locals = imp_in@imp_out@imp_locals@locals in
+            let imp_c = get_node_contract imp_nd in
+            (* Assigning in and out *)
+            let mk_def vars_l e =
+              let lhs = List.map (fun v -> v.var_id) vars_l in
+              Eq (mkeq loc (lhs, e))
             in
-            let stmts = stmts @ (rename imp_nd.stmts) in
-            let imp_c = rename imp_c in
+            let in_assigns = mk_def imp_in import.inputs in
+            let out_assigns = mk_def imp_out import.outputs in
+            let stmts = in_assigns :: out_assigns :: imp_nd.node_stmts @ stmts in
             let c = merge_contracts c imp_c in
             stmts, locals, c 
-          with Not_found -> raise (Error.Unbound_symbol ("contract " ^ name))
+          with Not_found -> assert false; raise (Error (loc, (Error.Unbound_symbol ("contract " ^ name))))
 
-                            *)
+         
         ) ([], c.consts@c.locals, c) c.imports
     in
+    let stmts = stmts @ c.stmts in 
     (* Other contract elements will be normalized later *)
-    let c = { c with
+    let c = { c with (* we erase locals and stmts sinced they are now in the parent node *)
               locals = [];
               consts = [];
               stmts = [];
               imports = []
             }
     in
+    
+    (* Format.eprintf "Processed stmts: %a@." Printers.pp_node_stmts stmts;
+     * Format.eprintf "Processed locals: %a@." Printers.pp_vars locals; *)
     stmts, locals, c
     
   in
@@ -258,11 +264,14 @@ let resolve_contracts prog =
       | ImportedNode ind -> ind.nodei_id, ind.nodei_spec, ind.nodei_inputs, ind.nodei_outputs
       | _ -> assert false
     in
+    Format.eprintf "Process contract new node for node %s@." id;
+
     let stmts, locals, c =
       match spec with
       | None | Some (NodeSpec _) -> assert false
       | Some (Contract c) ->
-         process_contract accu_contracts prog c
+         (* Format.eprintf "Processing contract of node %s@." id; *)
+         process_contract accu_contracts c
     in
     (* Create a fresh name *)
     let used v = List.exists (fun top ->
@@ -279,23 +288,23 @@ let resolve_contracts prog =
         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
+        (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
   in
   (* Processing nodes in order. Should have been sorted by now
@@ -317,7 +326,8 @@ let resolve_contracts prog =
           match nd.node_spec with
           | None | Some (NodeSpec _) -> assert false
           | Some (Contract c) ->
-             let stmts, locals, c = process_contract accu_contracts prog c in
+             (* Format.eprintf "Processing top contract %s@." nd.node_id; *)
+             let stmts, locals, c = process_contract accu_contracts c in
              let nd =
                { nd with
                  node_locals = nd.node_locals @ locals;
@@ -337,7 +347,7 @@ let resolve_contracts prog =
           | Some (Contract c) -> (* A contract: processing it *)
              (* we bind a fresh node *)
              let new_nd = process_contract_new_node accu_contracts prog top in
-             Format.eprintf "Creating new contract node %s@." (node_name new_nd);
+             (* Format.eprintf "Creating new contract node %s@." (node_name new_nd); *)
              let nd = { nd with node_spec = (Some (NodeSpec (node_name new_nd))) } in
              new_nd::accu_contracts,
              { top with top_decl_desc = Node nd }::accu_nodes
diff --git a/src/compiler_stages.ml b/src/compiler_stages.ml
index 3c72b644..397c1494 100644
--- a/src/compiler_stages.ml
+++ b/src/compiler_stages.ml
@@ -77,9 +77,14 @@ let stage1 params prog dirname basename extension =
 
   (* Sorting nodes *)
   let prog = SortProg.sort prog in
-
+Format.eprintf "ok1@.";
   (* Consolidating contracts *)
   let prog = resolve_contracts prog in
+Format.eprintf "ok2@.";
+  let prog = SortProg.sort prog in
+Format.eprintf "ok3@.";
+  Log.report ~level:3 (fun fmt ->
+      Format.fprintf fmt "@[<v 0>Contracts resolved:@ %a@ @]@ " Printers.pp_prog prog);
   
   (* Perform inlining before any analysis *)
   let orig, prog =
@@ -322,7 +327,7 @@ let stage3 prog machine_code dependencies basename extension =
   | "emf", _ ->
      begin
        let destname = !Options.dest_dir ^ "/" ^ basename in
-       let source_file = destname ^ ".emf" in (* Could be changed *)
+       let source_file = destname ^ ".json" in (* Could be changed *)
        let source_out = open_out source_file in
        let fmt = formatter_of_out_channel source_out in
        EMF_backend.translate fmt basename prog machine_code;
diff --git a/src/corelang.ml b/src/corelang.ml
index 65e429d0..82f45f38 100644
--- a/src/corelang.ml
+++ b/src/corelang.ml
@@ -194,12 +194,13 @@ let mk_contract_var id is_const type_opt expr loc =
     let v = mkvar_decl loc (id, typ, mkclock loc Ckdec_any, is_const, None, None) in
     let eq = mkeq loc ([id], expr) in 
     { empty_contract with locals = [v]; stmts = [Eq eq]; spec_loc = loc; }
+let eexpr_add_name eexpr name =
+  {eexpr with eexpr_name = match name with "" -> None | _ -> Some name}
+let mk_contract_guarantees ?(name="") eexpr =
+  { empty_contract with guarantees = [eexpr_add_name eexpr name]; spec_loc = eexpr.eexpr_loc }
 
-let mk_contract_guarantees eexpr =
-  { empty_contract with guarantees = [eexpr]; spec_loc = eexpr.eexpr_loc }
-
-let mk_contract_assume eexpr =
-  { empty_contract with assume = [eexpr]; spec_loc = eexpr.eexpr_loc }
+let mk_contract_assume ?(name="") eexpr =
+  { empty_contract with assume = [eexpr_add_name eexpr name]; spec_loc = eexpr.eexpr_loc }
 
 let mk_contract_mode id rl el loc =
   { empty_contract with modes = [{ mode_id = id; require = rl; ensure = el; mode_loc = loc; }]; spec_loc = loc }
@@ -223,6 +224,7 @@ let mkeexpr loc expr =
   { eexpr_tag = Utils.new_tag ();
     eexpr_qfexpr = expr;
     eexpr_quantifiers = [];
+    eexpr_name = None;
     eexpr_type = Types.new_var ();
     eexpr_clock = Clocks.new_var true;
     eexpr_loc = loc }
@@ -324,16 +326,21 @@ let is_imported_node td =
   | ImportedNode nd -> true
   | _ -> assert false
 
+let is_node_contract nd =
+  match nd.node_spec with
+  | Some (Contract _) -> true
+  | _ -> false
+  
+let get_node_contract nd =
+  match nd.node_spec with
+  | Some (Contract c) -> c
+  | _ -> assert false
+  
 let is_contract td =
   match td.top_decl_desc with 
-  | Node nd -> (
-    match nd.node_spec with
-    | Some (Contract _) -> true
-    | _ -> false
-  )                     
+  | Node nd -> is_node_contract nd
   | _ -> false
 
-
 (* alias and type definition table *)
 
 let mktop = mktop_decl Location.dummy_loc !Options.dest_dir false
@@ -709,8 +716,36 @@ let get_node_interface nd =
  }
 
 (************************************************************************)
-(*        Renaming                                                      *)
+(*        Renaming / Copying                                                      *)
+
+let copy_var_decl vdecl =
+  mkvar_decl vdecl.var_loc ~orig:vdecl.var_orig (vdecl.var_id, vdecl.var_dec_type, vdecl.var_dec_clock, vdecl.var_dec_const, vdecl.var_dec_value, vdecl.var_parent_nodeid)
 
+let copy_const cdecl =
+  { cdecl with const_type = Types.new_var () }
+
+let copy_node nd =
+  { nd with
+    node_type     = Types.new_var ();
+    node_clock    = Clocks.new_var true;
+    node_inputs   = List.map copy_var_decl nd.node_inputs;
+    node_outputs  = List.map copy_var_decl nd.node_outputs;
+    node_locals   = List.map copy_var_decl nd.node_locals;
+    node_gencalls = [];
+    node_checks   = [];
+    node_stateless = None;
+  }
+
+let copy_top top =
+  match top.top_decl_desc with
+  | Node nd -> { top with top_decl_desc = Node (copy_node nd)  }
+  | Const c -> { top with top_decl_desc = Const (copy_const c) }
+  | _       -> top
+
+let copy_prog top_list =
+  List.map copy_top top_list
+
+  
 let rec rename_static rename cty =
  match cty with
  | Tydec_array (d, cty') -> Tydec_array (Dimension.expr_replace_expr rename d, rename_static rename cty')
@@ -768,17 +803,17 @@ let rec rename_carrier rename cck =
    | Expr_appl (i, e', i') -> 
      Expr_appl (f_node i, re e', Utils.option_map re i')
 
- let rename_dec_type f_node f_var t = assert false (*
+ let rename_dec_type f_node f_var t = t (* TODO : do we really want to rename a declared type ? 
 						     Types.rename_dim_type (Dimension.rename f_node f_var) t*)
 
- let rename_dec_clock f_node f_var c = assert false (* 
+ let rename_dec_clock f_node f_var c = c (* TODO : do we really want to rename a declared clock ? assert false  
 					  Clocks.rename_clock_expr f_var c*)
    
  let rename_var f_node f_var v = {
-   v with
+     (copy_var_decl v) with
      var_id = f_var v.var_id;
-     var_dec_type = rename_dec_type f_node f_var v.var_type;
-     var_dec_clock = rename_dec_clock f_node f_var v.var_clock
+     var_dec_type = rename_dec_type f_node f_var v.var_dec_type;
+     var_dec_clock = rename_dec_clock f_node f_var v.var_dec_clock
  } 
 
  let rename_vars f_node f_var = List.map (rename_var f_node f_var) 
@@ -822,17 +857,38 @@ and rename_eexpr f_node f_var ee =
      eexpr_qfexpr = rename_expr f_node f_var ee.eexpr_qfexpr;
      eexpr_quantifiers = List.map (fun (typ,vdecls) -> typ, rename_vars f_node f_var vdecls) ee.eexpr_quantifiers;
    }
- 
-     
+and rename_mode f_node f_var m =
+  let rename_ee = rename_eexpr f_node f_var in
+  {
+    m with
+    require = List.map rename_ee m.require;
+    ensure = List.map rename_ee m.ensure
+  }
      
+ let rename_import f_node f_var imp =
+   let rename_expr = rename_expr f_node f_var in
+   {
+     imp with
+     import_nodeid = f_node imp.import_nodeid;
+     inputs = rename_expr imp.inputs;
+     outputs =  rename_expr imp.outputs;
+   }
    
  let rename_node f_node f_var nd =
+   let f_var x = (* checking that this is actually a local variable *)
+     if List.exists (fun v -> v.var_id = x) (get_node_vars nd) then
+       f_var x
+     else
+       x
+   in
    let rename_var = rename_var f_node f_var in
+   let rename_vars = List.map rename_var in
    let rename_expr = rename_expr f_node f_var in
+   let rename_eexpr = rename_eexpr f_node f_var in
    let rename_stmts = rename_stmts f_node f_var in
-   let inputs = List.map rename_var nd.node_inputs in
-   let outputs = List.map rename_var nd.node_outputs in
-   let locals = List.map rename_var nd.node_locals in
+   let inputs = rename_vars nd.node_inputs in
+   let outputs = rename_vars nd.node_outputs in
+   let locals = rename_vars nd.node_locals in
    let gen_calls = List.map rename_expr nd.node_gencalls in
    let node_checks = List.map (Dimension.rename f_node f_var)  nd.node_checks in
    let node_asserts = List.map 
@@ -848,7 +904,19 @@ and rename_eexpr f_node f_var ee =
    in
    let spec = 
      Utils.option_map 
-       (fun s -> assert false; (*rename_node_annot f_node f_var s*) ) (* TODO: implement! *) 
+       (fun s -> match s with
+                   NodeSpec id -> NodeSpec (f_node id)
+                 | Contract c -> Contract {
+                     c with
+                     consts = rename_vars c.consts;
+                     locals = rename_vars c.locals;
+                     stmts = rename_stmts c.stmts;
+                     assume = List.map rename_eexpr c.assume;
+                     guarantees = List.map rename_eexpr c.guarantees;
+                     modes = List.map (rename_mode f_node f_var) c.modes;
+                     imports = List.map (rename_import f_node f_var) c.imports;
+                   }
+       )
        nd.node_spec 
    in
    let annot = rename_annots f_node f_var nd.node_annot in
@@ -1042,6 +1110,7 @@ let rec substitute_expr vars_to_replace defs e =
    { eexpr_tag = expr.expr_tag;
      eexpr_qfexpr = expr;
      eexpr_quantifiers = [];
+     eexpr_name = None;
      eexpr_type = expr.expr_type;
      eexpr_clock = expr.expr_clock;
      eexpr_loc = expr.expr_loc;
@@ -1176,32 +1245,6 @@ and node_has_arrows node =
 
 
 
-let copy_var_decl vdecl =
-  mkvar_decl vdecl.var_loc ~orig:vdecl.var_orig (vdecl.var_id, vdecl.var_dec_type, vdecl.var_dec_clock, vdecl.var_dec_const, vdecl.var_dec_value, vdecl.var_parent_nodeid)
-
-let copy_const cdecl =
-  { cdecl with const_type = Types.new_var () }
-
-let copy_node nd =
-  { nd with
-    node_type     = Types.new_var ();
-    node_clock    = Clocks.new_var true;
-    node_inputs   = List.map copy_var_decl nd.node_inputs;
-    node_outputs  = List.map copy_var_decl nd.node_outputs;
-    node_locals   = List.map copy_var_decl nd.node_locals;
-    node_gencalls = [];
-    node_checks   = [];
-    node_stateless = None;
-  }
-
-let copy_top top =
-  match top.top_decl_desc with
-  | Node nd -> { top with top_decl_desc = Node (copy_node nd)  }
-  | Const c -> { top with top_decl_desc = Const (copy_const c) }
-  | _       -> top
-
-let copy_prog top_list =
-  List.map copy_top top_list
 
 
 let rec expr_contains_expr expr_tag expr  =
diff --git a/src/corelang.mli b/src/corelang.mli
index 32a84264..bff17ca2 100644
--- a/src/corelang.mli
+++ b/src/corelang.mli
@@ -59,6 +59,8 @@ val update_node: ident -> top_decl -> unit
 val is_generic_node: top_decl -> bool
 val is_imported_node: top_decl -> bool
 val is_contract: top_decl -> bool
+val is_node_contract: node_desc -> bool
+val get_node_contract: node_desc -> contract_desc
   
 val consts_table: (ident, top_decl) Hashtbl.t
 val print_consts_table:  Format.formatter -> unit -> unit
@@ -154,8 +156,9 @@ val rename_expr : (ident -> ident) -> (ident -> ident) -> expr -> expr
 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 *)
+(** rename_prog f_node f_var f_const prog *)
 val rename_prog: (ident -> ident) -> (ident -> ident) -> (ident -> ident) -> program_t -> program_t
+val rename_node: (ident -> ident) -> (ident -> ident) -> node_desc -> node_desc
 
 val substitute_expr: var_decl list -> eq list -> expr -> expr
 
@@ -169,8 +172,8 @@ val copy_prog: top_decl list -> top_decl list
 val mkeexpr: Location.t ->  expr -> eexpr
 val empty_contract: contract_desc
 val mk_contract_var: ident -> bool -> type_dec option -> expr -> Location.t -> contract_desc
-val mk_contract_guarantees: eexpr -> contract_desc
-val mk_contract_assume: eexpr -> contract_desc
+val mk_contract_guarantees: ?name:string -> eexpr -> contract_desc
+val mk_contract_assume: ?name:string -> eexpr -> contract_desc
 val mk_contract_mode: ident -> eexpr list -> eexpr list -> Location.t -> contract_desc
 val mk_contract_import: ident -> expr -> expr -> Location.t -> contract_desc
 val merge_contracts:  contract_desc -> contract_desc -> contract_desc 
diff --git a/src/lustre_types.ml b/src/lustre_types.ml
index b1956644..58764678 100644
--- a/src/lustre_types.ml
+++ b/src/lustre_types.ml
@@ -116,6 +116,7 @@ and  eexpr =
     {eexpr_tag: tag;
      eexpr_qfexpr: expr;
      eexpr_quantifiers: (quantifier_type * var_decl list) list;
+     eexpr_name: string option;
      mutable eexpr_type: Types.type_expr;
      mutable eexpr_clock: Clocks.clock_expr;
      (* mutable eexpr_normalized: (var_decl * eq list * var_decl list) option; *)
diff --git a/src/machine_code.ml b/src/machine_code.ml
index 318c719d..81a52b78 100644
--- a/src/machine_code.ml
+++ b/src/machine_code.ml
@@ -46,9 +46,9 @@ let build_env locals non_locals =
     get_var = (fun id -> try
                   VSet.get id all
                 with Not_found -> (
-                  Format.eprintf "Impossible to find variable %s in set %a@.@?"
-                    id
-                    VSet.pp all;
+                  (* Format.eprintf "Impossible to find variable %s in set %a@.@?"
+                   *   id
+                   *   VSet.pp all; *)
                   raise Not_found
                 )
               )  
@@ -377,6 +377,7 @@ let translate_core sorted_eqs locals other_vars =
 
  
 let translate_decl nd sch =
+  (* Format.eprintf "Translating node %s@." nd.node_id; *)
   (* Extracting eqs, variables ..  *)
   let eqs, auts = get_node_eqs nd in
   assert (auts = []); (* Automata should be expanded by now *)
@@ -390,13 +391,22 @@ let translate_decl nd sch =
   let locals = VSet.of_list locals_list in
   let inout_vars = (VSet.of_list (nd.node_inputs @ nd.node_outputs)) in
   let env = build_env locals inout_vars  in 
+
+  (* Format.eprintf "Node content is %a@." Printers.pp_node nd; *)
   
   (* Computing main content *)
+  (* Format.eprintf "ok1@.@?"; *)
   let schedule = sch.Scheduling_type.schedule in
+  (* Format.eprintf "ok2@.@?"; *)
   let sorted_eqs = Scheduling.sort_equations_from_schedule eqs schedule in
-
+  (* Format.eprintf "ok3@.locals=%a@.inout:%a@?"
+   *   VSet.pp locals
+   *   VSet.pp inout_vars
+   * ; *)
+  
   let ctx, ctx0_s = translate_core (assert_instrs@sorted_eqs) locals inout_vars in
   
+  (* Format.eprintf "ok4@.@?"; *)
   
  
   let mmap = Utils.IMap.elements ctx.j in
diff --git a/src/machine_code_common.ml b/src/machine_code_common.ml
index 41f6a374..a58ec1b4 100644
--- a/src/machine_code_common.ml
+++ b/src/machine_code_common.ml
@@ -46,6 +46,7 @@ let rec  pp_instr m fmt i =
 	 pp_val g
 	 (Utils.fprintf_list ~sep:"@," pp_branch) hl
     | MComment s -> Format.pp_print_string fmt s
+    | MSpec s -> Format.pp_print_string fmt ("@" ^ s)
        
   in
   (* Annotation *)
@@ -122,7 +123,10 @@ let rec is_const_value v =
 
 (* Returns the declared stateless status and the computed one. *)
 let get_stateless_status m =
- (m.mname.node_dec_stateless, try Utils.desome m.mname.node_stateless with _ -> failwith ("stateless status of machine " ^ m.mname.node_id ^ " not computed"))
+  (m.mname.node_dec_stateless,
+   try
+     Utils.desome m.mname.node_stateless
+   with _ -> failwith ("stateless status of machine " ^ m.mname.node_id ^ " not computed"))
 
 let is_stateless m = m.minstances = [] && m.mmemory = []
 
diff --git a/src/machine_code_types.ml b/src/machine_code_types.ml
index 1283f396..e5ce4c4b 100644
--- a/src/machine_code_types.ml
+++ b/src/machine_code_types.ml
@@ -29,6 +29,7 @@ and instr_t_desc =
   | MStep of var_decl list * ident * value_t list
   | MBranch of value_t * (label * instr_t list) list
   | MComment of string
+  | MSpec of string 
 
 type step_t = {
     step_checks: (Location.t * value_t) list;
diff --git a/src/normalization.ml b/src/normalization.ml
index 71026215..079ec722 100644
--- a/src/normalization.ml
+++ b/src/normalization.ml
@@ -450,18 +450,21 @@ let normalize_pred_eexpr decls norm_ctx (def,vars) ee =
        inline possible calls within, normalize it and type/clock the
        result.  *)
     let eq = mkeq ee.eexpr_loc ([output_id], ee.eexpr_qfexpr) in
-    (* Inlining any calls *)
-    let nodes = get_nodes decls in
-    let calls = ISet.elements (get_expr_calls nodes ee.eexpr_qfexpr) in
-    let vars, eqs =
-      if calls = [] && not (eq_has_arrows eq) then
-        vars, [eq]    
-      else
-        assert false (* TODO *)
-    in
+
+
+    (* (\* Inlining any calls *\)
+     * let nodes = get_nodes decls in
+     * let calls = ISet.elements (get_expr_calls nodes ee.eexpr_qfexpr) in
+     * let vars, eqs =
+     *   if calls = [] && not (eq_has_arrows eq) then
+     *     vars, [eq]    
+     *   else
+     *     assert false (\* TODO *\)
+     * in *)
     
     (* Normalizing expr and eqs *)
-    let defs, vars = List.fold_left (normalize_eq_split norm_ctx) (def, vars) eqs in
+    let defs, vars = List.fold_left (normalize_eq_split norm_ctx) (def, vars) [eq] in
+    let vars = output_var :: vars in 
 (*    let todefine =
       List.fold_left
         (fun m x-> if List.exists (fun y-> x.var_id = y.var_id) (locals) then m else ISet.add x.var_id m)
@@ -557,6 +560,7 @@ let normalize_spec decls parentid (in_vars, out_vars, l_vars) s =
   (* Original set of variables actually visible from here: in/out and
      spec locals (no node locals) *)
   let orig_vars = in_vars @ out_vars @ s.locals in
+  (* Format.eprintf "NormSpec: init locals: %a@." Printers.pp_vars s.locals; *)
   let not_is_orig_var v =
     List.for_all ((!=) v) orig_vars in
   let norm_ctx = {
@@ -574,10 +578,15 @@ let normalize_spec decls parentid (in_vars, out_vars, l_vars) s =
   (* Iterate through predicates and normalize them on the go, creating
      fresh variables for any guarantees/assumes/require/ensure *)
   let process_predicates l defvars =
-    List.fold_right (fun ee (accu, defvars) ->
+    (* 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 decls norm_ctx defvars ee in
         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
 
   
@@ -595,7 +604,7 @@ let normalize_spec decls parentid (in_vars, out_vars, l_vars) s =
   let new_locals = List.filter not_is_orig_var vars in (* removing inouts and initial locals ones *)
   new_locals, defs,      
   {s with
-    locals = s.locals @ new_locals;
+    (* locals = s.locals @ new_locals; *)
     stmts = [];
     assume = assume';
     guarantees = guarantees';
@@ -663,6 +672,8 @@ let normalize_node decls node =
                     (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
     end
   in
diff --git a/src/optimize_machine.ml b/src/optimize_machine.ml
index df4fea07..61777be3 100644
--- a/src/optimize_machine.ml
+++ b/src/optimize_machine.ml
@@ -28,7 +28,7 @@ let pp_elim m fmt elim =
 let rec eliminate m elim instr =
   let e_expr = eliminate_expr m elim in
   match get_instr_desc instr with
-  | MComment _         -> instr
+  | MSpec _ | MComment _         -> instr
   | MLocalAssign (i,v) -> update_instr_desc instr (MLocalAssign (i, e_expr v))
   | MStateAssign (i,v) -> update_instr_desc instr (MStateAssign (i, e_expr v))
   | MReset i           -> instr
@@ -119,7 +119,7 @@ let rec simplify_instr_offset m instr =
     -> update_instr_desc instr (
       MBranch(simplify_expr_offset m cond, List.map (fun (l, il) -> l, simplify_instrs_offset m il) brl)
     )
-  | MComment _             -> instr
+  | MSpec _ | MComment _             -> instr
 
 and simplify_instrs_offset m instrs =
   List.map (simplify_instr_offset m) instrs
@@ -265,12 +265,19 @@ let instr_of_const top_const =
   let vdecl = { vdecl with var_type = const.const_type }
   in mkinstr (MLocalAssign (vdecl, mk_val (Cst const.const_value) vdecl.var_type))
 
+(* We do not perform this optimization on contract nodes since there
+   is not explicit dependence btw variables and their use in
+   contracts. *)
 let machines_unfold consts node_schs machines =
   List.fold_right (fun m (machines, removed) ->
-    let fanin = (IMap.find m.mname.node_id node_schs).Scheduling_type.fanin_table in
-    let elim_consts, _ = instrs_unfold m fanin IMap.empty (List.map instr_of_const consts) in
-    let (m, removed_m) =  machine_unfold fanin elim_consts m in
-    (m::machines, IMap.add m.mname.node_id removed_m removed)
+      let is_contract = match m.mspec with Some (Contract _) -> true | _ -> false in
+      if is_contract then
+        m::machines, removed
+      else
+        let fanin = (IMap.find m.mname.node_id node_schs).Scheduling_type.fanin_table in
+        let elim_consts, _ = instrs_unfold m fanin IMap.empty (List.map instr_of_const consts) in
+        let (m, removed_m) =  machine_unfold fanin elim_consts m in
+        (m::machines, IMap.add m.mname.node_id removed_m removed)
     )
     machines
     ([], IMap.empty)
@@ -468,7 +475,7 @@ let rec value_replace_var fvar value =
 
 let rec instr_replace_var fvar instr cont =
   match get_instr_desc instr with
-  | MComment _          -> instr_cons instr cont
+  | MSpec _ | MComment _          -> instr_cons instr cont
   | MLocalAssign (i, v) -> instr_cons (update_instr_desc instr (MLocalAssign (fvar i, value_replace_var fvar v))) cont
   | MStateAssign (i, v) -> instr_cons (update_instr_desc instr (MStateAssign (i, value_replace_var fvar v))) cont
   | MReset i            -> instr_cons instr cont
@@ -593,7 +600,9 @@ let optimize prog node_schs machine_code =
   in
   (* Optimize machine code *)
   let machine_code, removed_table = 
-    if !Options.optimization >= 2 && !Options.output <> "emf" (*&& !Options.output <> "horn"*) then
+    if !Options.optimization >= 2
+       && !Options.output <> "emf" (*&& !Options.output <> "horn"*)
+    then
       begin
 	Log.report ~level:1 (fun fmt -> Format.fprintf fmt 
 	  ".. machines optimization: const. inlining (partial eval. with const)@,");
@@ -620,7 +629,7 @@ let optimize prog node_schs machine_code =
   in
   
 
-    machine_code  
+   List.rev machine_code  
     
     
 (* Local Variables: *)
diff --git a/src/parsers/lexerLustreSpec.mll b/src/parsers/lexerLustreSpec.mll
index e4ef79b0..18c911ee 100644
--- a/src/parsers/lexerLustreSpec.mll
+++ b/src/parsers/lexerLustreSpec.mll
@@ -64,7 +64,7 @@ let keyword_table =
   "mode", MODE;
   "assume", ASSUME;
   "contract", CONTRACT;
-  "guarantees", GUARANTEES;
+  "guarantee", GUARANTEES;
   "exists", EXISTS;
   "forall", FORALL;
   "c_code", CCODE;
diff --git a/src/parsers/lexer_lustre.mll b/src/parsers/lexer_lustre.mll
index 5d81cff7..ad68e09b 100644
--- a/src/parsers/lexer_lustre.mll
+++ b/src/parsers/lexer_lustre.mll
@@ -69,7 +69,7 @@ let keyword_table =
   "mode", MODE;
   "assume", ASSUME;
   "contract", CONTRACT;
-  "guarantees", GUARANTEES;
+  "guarantee", GUARANTEES;
   "exists", EXISTS;
   "forall", FORALL;
  
diff --git a/src/parsers/parser_lustre.mly b/src/parsers/parser_lustre.mly
index 31323d7b..8ad04a4b 100644
--- a/src/parsers/parser_lustre.mly
+++ b/src/parsers/parser_lustre.mly
@@ -413,19 +413,31 @@ contract_content:
     { merge_contracts (mk_contract_var $2 false (Some(mktyp $4)) $6 (get_loc())) $8 }
 | ASSUME qexpr SCOL contract_content
     { merge_contracts (mk_contract_assume $2) $4 }
+| ASSUME STRING qexpr SCOL contract_content
+    { merge_contracts (mk_contract_assume ~name:$2 $3) $5 }
 | GUARANTEES qexpr SCOL contract_content	
     { merge_contracts (mk_contract_guarantees $2) $4 }
+| GUARANTEES STRING qexpr SCOL contract_content	
+    { merge_contracts (mk_contract_guarantees ~name:$2 $3) $5 }
 | MODE IDENT LPAR mode_content RPAR SCOL contract_content
 	{ merge_contracts (
 	  let r, e = $4 in 
 	  mk_contract_mode $2 r e (get_loc())) $7 }	
+| IMPORT IDENT LPAR tuple_expr RPAR RETURNS LPAR tuple_expr RPAR SCOL contract_content
+    { merge_contracts (mk_contract_import $2  (mkexpr (Expr_tuple (List.rev $4)))  (mkexpr (Expr_tuple (List.rev $8))) (get_loc())) $11 }
+| IMPORT IDENT LPAR expr RPAR RETURNS LPAR tuple_expr RPAR SCOL contract_content
+    { merge_contracts (mk_contract_import $2  $4  (mkexpr (Expr_tuple (List.rev $8))) (get_loc())) $11 }
+| IMPORT IDENT LPAR tuple_expr RPAR RETURNS LPAR expr RPAR SCOL contract_content
+    { merge_contracts (mk_contract_import $2  (mkexpr (Expr_tuple (List.rev $4)))  $8 (get_loc())) $11 }
 | IMPORT IDENT LPAR expr RPAR RETURNS LPAR expr RPAR SCOL contract_content
     { merge_contracts (mk_contract_import $2  $4  $8 (get_loc())) $11 }
 
 mode_content:
 { [], [] }
 | REQUIRE qexpr SCOL mode_content { let (r,e) = $4 in $2::r, e }
+| REQUIRE STRING qexpr SCOL mode_content { let (r,e) = $5 in {$3 with eexpr_name = Some $2}::r, e }
 | ENSURE qexpr SCOL mode_content { let (r,e) = $4 in r, $2::e }
+| ENSURE STRING qexpr SCOL mode_content { let (r,e) = $5 in r, {$3 with eexpr_name = Some $2}::e }
 
 /* WARNING: UNUSED RULES */
 tuple_qexpr:
diff --git a/src/plugins/salsa/machine_salsa_opt.ml b/src/plugins/salsa/machine_salsa_opt.ml
index 9cc0babc..e6ce5e28 100644
--- a/src/plugins/salsa/machine_salsa_opt.ml
+++ b/src/plugins/salsa/machine_salsa_opt.ml
@@ -61,7 +61,7 @@ let rec get_read_vars instrs =
     )
     | MReset _ 
     | MNoReset _ 
-    | MComment _ -> Vars.empty  
+    | MSpec _ | MComment _ -> Vars.empty  
   )
 
 let rec get_written_vars instrs =
@@ -79,7 +79,7 @@ let rec get_written_vars instrs =
     )
     | MReset _ 
     | MNoReset _ 
-    | MComment _ -> Vars.empty    
+      | MSpec _ | MComment _ -> Vars.empty    
   )
 
 (* let rec iterTransformExpr fresh_id e_salsa abstractEnv old_range = *)
@@ -720,7 +720,7 @@ let rec rewrite_instrs nodename m constEnv  vars_env m instrs ranges formalEnv p
 	   new_locals
 
 
-	 | MT.MReset(_) | MT.MNoReset _ | MT.MComment _ ->
+	 | MT.MReset(_) | MT.MNoReset _ | MT.MSpec _ | MT.MComment _ ->
 	    (* if !debug then Format.eprintf "Untouched %a (non real)@ " MC.pp_instr hd_instr; *)
 
 	   (* Untouched instruction *)
diff --git a/src/printers.ml b/src/printers.ml
index 51ceca36..6cb91a36 100644
--- a/src/printers.ml
+++ b/src/printers.ml
@@ -62,10 +62,13 @@ let pp_var fmt id =
     id.var_id
     pp_var_type id
 
+let pp_vars fmt vars =
+  fprintf_list ~sep:"; " pp_var fmt vars
+  
 let pp_quantifiers fmt (q, vars) =
   match q with
-    | Forall -> fprintf fmt "forall %a" (fprintf_list ~sep:"; " pp_var) vars 
-    | Exists -> fprintf fmt "exists %a" (fprintf_list ~sep:"; " pp_var) vars 
+    | Forall -> fprintf fmt "forall %a" pp_vars vars 
+    | Exists -> fprintf fmt "exists %a" pp_vars vars 
 
 let rec pp_struct_const_field fmt (label, c) =
   fprintf fmt "%a = %a;" pp_print_string label pp_const c
@@ -278,17 +281,17 @@ let pp_typedec fmt ty =
 
 
 
-let pp_quantifiers fmt (q, vars) =
-  match q with
-    | Forall -> fprintf fmt "forall %a" (fprintf_list ~sep:"; " pp_var) vars 
-    | Exists -> fprintf fmt "exists %a" (fprintf_list ~sep:"; " pp_var) vars 
+(* let pp_quantifiers fmt (q, vars) =
+ *   match q with
+ *     | Forall -> fprintf fmt "forall %a" pp_vars vars 
+ *     | Exists -> fprintf fmt "exists %a" (fprintf_list ~sep:"; " pp_var) vars  *)
 
-let pp_eexpr fmt e =
+(*let pp_eexpr fmt e =
   fprintf fmt "%a%t %a"
     (Utils.fprintf_list ~sep:"; " pp_quantifiers) e.eexpr_quantifiers
     (fun fmt -> match e.eexpr_quantifiers with [] -> () | _ -> fprintf fmt ";")
     pp_expr e.eexpr_qfexpr
-
+ *)
     
 let pp_spec_eq fmt eq = 
   fprintf fmt "var %a : %a = %a;" 
@@ -306,7 +309,7 @@ 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. *)
     fprintf_list ~eol:"@, " ~sep:"@, " (fun fmt v ->
-    fprintf fmt "const %a = %t;"
+    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;
@@ -315,10 +318,10 @@ let pp_spec fmt spec =
   fprintf_list ~eol:"@, " ~sep:"@, " (fun fmt r -> fprintf fmt "assume %a;" pp_eexpr r) fmt spec.assume;
   fprintf_list ~eol:"@, " ~sep:"@, " (fun fmt r -> fprintf fmt "guarantees %a;" pp_eexpr r) fmt spec.guarantees;
   fprintf_list ~eol:"@, " ~sep:"@, " (fun fmt mode ->
-    fprintf fmt "mode %s (@[@ %a@ %a@]);" 
+    fprintf fmt "mode %s (@[<v 0>%a@ %a@]);" 
       mode.mode_id
-      (fprintf_list ~eol:"@," ~sep:"@ " (fun fmt r -> fprintf fmt "require %a;" pp_eexpr r)) mode.require
-      (fprintf_list ~eol:"@," ~sep:"@ " (fun fmt r -> fprintf fmt "ensure %a;" pp_eexpr r)) mode.ensure
+      (fprintf_list ~eol:"" ~sep:"@ " (fun fmt r -> fprintf fmt "require %a;" pp_eexpr r)) mode.require
+      (fprintf_list ~eol:"" ~sep:"@ " (fun fmt r -> fprintf fmt "ensure %a;" pp_eexpr r)) mode.ensure
   ) fmt spec.modes;
   fprintf_list ~eol:"@, " ~sep:"@, " (fun fmt import ->
     fprintf fmt "import %s (%a) returns (%a);" 
@@ -327,29 +330,32 @@ let pp_spec fmt spec =
       pp_expr import.outputs
   ) fmt spec.imports
 
-
-  let node_as_contract nd =
+(* Project the contract node as a pure contract: local memories are pushed back in the contract definition. Should mainly be used to print it *) 
+let node_as_contract nd =
   match nd.node_spec with
   | None | Some (NodeSpec _) -> raise (Invalid_argument "Not a contract")
   | Some (Contract c) -> (
-    assert (c.locals = []);
-    assert (c.stmts = []);
+    (* While a processed contract shall have no locals, sttms nor
+       consts, an unprocessed one could. So we conservatively merge
+       elements, to enable printing unprocessed contracts *)
+    let consts, locals = List.partition(fun v -> v.var_dec_const) nd.node_locals in
     { c with
-      locals = nd.node_locals;
-      stmts = nd.node_stmts;
+      consts = consts @ c.consts;
+      locals = locals @ c.locals;
+      stmts = nd.node_stmts @ c.stmts;
     }
   )
-
+  
 let pp_contract fmt nd =    
+  
   let c = node_as_contract nd in
-  let pp_l = fprintf_list ~sep:"," pp_var_name in
-  fprintf fmt "@[<hov 2>(*@@ contract %s(%a) returns (%a);@ "
+  fprintf fmt "@[<v 2>(*@@ contract %s(%a) returns (%a);@ "
     nd.node_id
-    pp_l nd.node_inputs
-    pp_l nd.node_outputs;
-  fprintf fmt "let@ ";
+    pp_node_args nd.node_inputs
+    pp_node_args nd.node_outputs;
+  fprintf fmt "@[<v 2>let@ ";
   pp_spec fmt c;
-  fprintf fmt "tel@ @]*)@ "        
+  fprintf fmt "@]@ tel@ @]*)@ "        
     
 let pp_spec_as_comment fmt (inl, outl, spec) =
   match spec with
@@ -377,9 +383,9 @@ let pp_node fmt nd =
     pp_node_args nd.node_inputs
     pp_node_args nd.node_outputs;
   (* Contracts *)
-  fprintf fmt "%a%t"
+  fprintf fmt "%a"
     (fun fmt s -> match s with Some s -> pp_spec_as_comment fmt (nd.node_inputs, nd.node_outputs, s) | _ -> ()) nd.node_spec
-    (fun fmt -> match nd.node_spec with None -> () | Some _ -> fprintf fmt "@ ");
+    (* (fun fmt -> match nd.node_spec with None -> () | Some _ -> fprintf fmt "@ ") *);
   (* Locals *)
   fprintf fmt "%a" (fun fmt locals ->
       match locals with [] -> () | _ ->
diff --git a/src/typing.ml b/src/typing.ml
index be1ec772..8b84e621 100644
--- a/src/typing.ml
+++ b/src/typing.ml
@@ -712,6 +712,7 @@ module Make (T: Types.S) (Expr_type_hub: EXPR_TYPE_HUB with type type_expr = T.t
     (** [type_node env nd loc] types node [nd] in environment env. The
     location is used for error reports. *)
     and type_node env nd loc =
+      (* Format.eprintf "Typing node %s@." nd.node_id; *)
       let is_main = nd.node_id = !Options.main_node in
       (* In contracts, outputs are considered as input values *)
       let vd_env_ol = if nd.node_iscontract then nd.node_locals else nd.node_outputs@nd.node_locals in
@@ -726,13 +727,11 @@ module Make (T: Types.S) (Expr_type_hub: EXPR_TYPE_HUB with type type_expr = T.t
         List.fold_left
           (fun uvs v -> ISet.add v.var_id uvs)
           ISet.empty vd_env_ol in
-      Format.eprintf "Undef1: %a@ " pp_iset undefined_vars_init;
       let undefined_vars =
         let eqs, auts = get_node_eqs nd in
         (* TODO XXX: il faut typer les handlers de l'automate *)
         List.fold_left (type_eq (new_env, vd_env) is_main) undefined_vars_init eqs
       in
-      Format.eprintf "Undef2: %a@ " pp_iset undefined_vars;
       (* Typing asserts *)
       List.iter (fun assert_ ->
           let assert_expr =  assert_.assert_expr in
@@ -749,10 +748,8 @@ module Make (T: Types.S) (Expr_type_hub: EXPR_TYPE_HUB with type type_expr = T.t
       
       (* check that table is empty *)
       let local_consts = List.fold_left (fun res vdecl -> if vdecl.var_dec_const then ISet.add vdecl.var_id res else res) ISet.empty nd.node_locals in
-      Format.eprintf "Localconsts: %a@ " pp_iset local_consts;
       let undefined_vars = ISet.diff undefined_vars local_consts in
-      Format.eprintf "Undef3: %a@ " pp_iset undefined_vars;
-
+      
       if (not (ISet.is_empty undefined_vars)) then
         raise (Error (loc, Undefined_var undefined_vars));
       let ty_ins = type_of_vlist nd.node_inputs in
-- 
GitLab