From 59020713a7a653418d2006f419e54cdb9b18687d Mon Sep 17 00:00:00 2001 From: ploc <ploc@garoche.net> Date: Thu, 22 Nov 2018 18:32:51 -0800 Subject: [PATCH] Some progress on EMF bqckend. Refactoring machines code --- src/backends/EMF/EMF_backend.ml | 80 ++++++++- src/backends/EMF/EMF_common.ml | 302 +++++++++++++++++++++++--------- src/compiler_stages.ml | 3 +- src/corelang.ml | 9 - src/corelang.mli | 1 + src/lustre_types.ml | 2 +- src/machine_code.ml | 205 ++++++++++++++-------- src/machine_code_common.ml | 6 +- src/machine_code_common.mli | 2 +- src/machine_code_types.ml | 1 + src/normalization.ml | 219 ++++++++++++++++------- src/typing.ml | 13 +- 12 files changed, 608 insertions(+), 235 deletions(-) diff --git a/src/backends/EMF/EMF_backend.ml b/src/backends/EMF/EMF_backend.ml index 9f2c2f4a..4a4913be 100644 --- a/src/backends/EMF/EMF_backend.ml +++ b/src/backends/EMF/EMF_backend.ml @@ -375,14 +375,60 @@ let pp_emf_annot cpt fmt (key, ee) = pp_emf_eexpr ee in incr cpt + +let pp_emf_spec_mode fmt m = + fprintf fmt "{@["; + fprintf fmt "\"mode_id\": \"%s\",@ " + m.mode_id; + fprintf fmt "\"require\": [%a],@ " + pp_emf_eexprs m.ensure; + fprintf fmt "\"require\": [%a],@ " + pp_emf_eexprs m.require; + fprintf fmt "@]}" + +let pp_emf_spec_modes = pp_emf_list pp_emf_spec_mode + +let pp_emf_spec_import fmt i = + fprintf fmt "{@["; + fprintf fmt "\"contract\": \"%s\",@ " + i.import_nodeid; + fprintf fmt "\"inputs\": [%a],@ " + pp_emf_exprs i.inputs; + fprintf fmt "\"outputs\": [%a],@ " + pp_emf_exprs i.outputs; + fprintf fmt "@]}" + +let pp_emf_spec_imports = pp_emf_list pp_emf_spec_import + +let pp_emf_spec fmt spec = + fprintf fmt "{ @[<hov 0>"; + fprintf fmt "\"consts\": [%a],@ " + pp_emf_consts spec.consts; + fprintf fmt "\"locals\": [%a],@ " + 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]@ " + pp_emf_spec_imports spec.imports; + fprintf fmt "@] }" let pp_emf_annots cpt fmt annots = fprintf_list ~sep:",@ " (pp_emf_annot cpt) fmt annots.annots let pp_emf_annots_list cpt fmt annots_list = fprintf_list ~sep:",@ " (pp_emf_annots cpt) fmt annots_list + + + let pp_machine fmt m = let instrs = (*merge_branches*) m.mstep.step_instrs in try fprintf fmt "@[<v 2>\"%a\": {@ " - print_protect (fun fmt -> pp_print_string fmt m.mname.node_id); + print_protect (fun fmt -> pp_print_string fmt m.mname.node_id); + fprintf fmt "\"imported\": \"false\",@ "; fprintf fmt "\"kind\": %t,@ " (fun fmt -> if not ( snd (get_stateless_status m) ) then fprintf fmt "\"stateful\"" @@ -399,6 +445,7 @@ let pp_machine fmt m = fprintf fmt "\"original_name\": \"%s\",@ " m.mname.node_id; fprintf fmt "\"instrs\": {@[<v 0> %a@]@ },@ " (pp_emf_instrs m) instrs; + (match m.mspec with None -> () | Some spec -> fprintf fmt "\"spec\": %a,@ " pp_emf_spec spec); fprintf fmt "\"annots\": {@[<v 0> %a@]@ }" (pp_emf_annots_list (ref 0)) m.mannot; fprintf fmt "@]@ }" with Unhandled msg -> ( @@ -408,6 +455,25 @@ let pp_machine fmt m = eprintf "node skipped - no output generated@ @]@." ) +let pp_emf_imported_node fmt top = + let ind = Corelang.imported_node_of_top top in + try + fprintf fmt "@[<v 2>\"%a\": {@ " + print_protect (fun fmt -> pp_print_string fmt ind.nodei_id); + fprintf fmt "\"imported\": \"true\",@ "; + fprintf fmt "\"inputs\": [%a],@ " + pp_emf_vars_decl ind.nodei_inputs; + fprintf fmt "\"outputs\": [%a],@ " + pp_emf_vars_decl ind.nodei_outputs; + fprintf fmt "\"original_name\": \"%s\",@ " ind.nodei_id; + (match ind.nodei_spec with None -> () | Some spec -> fprintf fmt "\"spec\": %a" pp_emf_spec spec); + fprintf fmt "@]@ }" + with Unhandled msg -> ( + eprintf "[Error] @[<v 0>EMF backend@ Issues while translating node %s@ " + ind.nodei_id; + eprintf "%s@ " msg; + eprintf "node skipped - no output generated@ @]@." + ) (****************************************************) (* Main function: iterates over node and print them *) (****************************************************) @@ -425,13 +491,21 @@ let pp_meta fmt basename = fprintf fmt "@ @]},@ " let translate fmt basename prog machines = - (* record_types prog; *) + (* record_types prog; *) fprintf fmt "@[<v 0>{@ "; pp_meta fmt basename; + (* Typedef *) + fprintf fmt "\"typedef\": [@[<v 0>%a@]],@ " + (pp_emf_list pp_emf_typedef) (Corelang.get_typedefs prog); + fprintf fmt "\"consts\": [@[<v 0>%a@]],@ " + (pp_emf_list pp_emf_top_const) (Corelang.get_consts prog); + fprintf fmt "\"imported_nodes\": @[<v 0>{@ "; + pp_emf_list pp_emf_imported_node fmt (Corelang.get_imported_nodes prog); + fprintf fmt "}@],@ "; fprintf fmt "\"nodes\": @[<v 0>{@ "; (* Previous alternative: mapping normalized lustre to EMF: fprintf_list ~sep:",@ " pp_decl fmt prog; *) - fprintf_list ~sep:",@ " pp_machine fmt (List.rev machines); + pp_emf_list pp_machine fmt (List.rev machines); fprintf fmt "}@]@ }"; fprintf fmt "@]@ }" diff --git a/src/backends/EMF/EMF_common.ml b/src/backends/EMF/EMF_common.ml index dc95fa74..1f122f5f 100644 --- a/src/backends/EMF/EMF_common.ml +++ b/src/backends/EMF/EMF_common.ml @@ -76,105 +76,153 @@ let pp_var_name fmt v = print_protect fmt (fun fmt -> Printers.pp_var_name fmt v *) -let pp_tag_type fmt typ = - let rec aux tydec_desc = - match tydec_desc with - | Tydec_int -> fprintf fmt "int" - | Tydec_real -> fprintf fmt "real" - | Tydec_bool -> fprintf fmt "bool" - | Tydec_clock ty -> aux ty - | Tydec_enum const_list -> ( - let size = List.length const_list in - if size < 255 then - fprintf fmt "uint8" - else if size < 65535 then - fprintf fmt "uint16" - else - assert false (* Too much states. This not reasonable *) - ) - | Tydec_const _ | Tydec_struct _ | Tydec_array _ | Tydec_any -> eprintf "unhandled cst tag in EMF: %a@." Printers.pp_var_type_dec_desc tydec_desc; assert false - in - aux typ.tydef_desc - -let pp_cst_type fmt c (*infered_typ*) = - match c with - | Const_tag t -> - let typ = (Corelang.typedef_of_top (Hashtbl.find Corelang.tag_table t)) in - if typ.tydef_id = "bool" then - fprintf fmt "bool" - else - pp_tag_type fmt typ - | Const_int _ -> fprintf fmt "int" (*!Options.int_type*) - | Const_real _ -> fprintf fmt "real" (*!Options.real_type*) - | Const_string _ -> fprintf fmt "string" - | _ -> eprintf "cst: %a@." Printers.pp_const c; assert false +let rec pp_emf_dim fmt dim_expr = + fprintf fmt "{"; + (let open Dimension in + match dim_expr.dim_desc with + | Dbool b -> fprintf fmt "\"kind\": \"bool\",@ \"value\": \"%b\"" b + | Dint i -> fprintf fmt "\"kind\": \"int\",@ \"value\": \"%i\"" i + | Dident s -> fprintf fmt "\"kind\": \"ident\",@ \"value\": \"%s\"" s + | Dappl(f, args) -> fprintf fmt "\"kind\": \"fun\",@ \"id\": \"%s\",@ \"args\": [@[%a@]]" + f (Utils.fprintf_list ~sep:",@ " pp_emf_dim) args + | Dite(i,t,e) -> fprintf fmt "\"kind\": \"ite\",@ \"guard\": \"%a\",@ \"then\": %a,@ \"else\": %a" + pp_emf_dim i pp_emf_dim t pp_emf_dim e + | Dlink e -> pp_emf_dim fmt e + | Dvar + | Dunivar -> assert false (* unresolved *) + ); + fprintf fmt "}" -let rec pp_infered_type fmt t = - let open Types in - if is_bool_type t then fprintf fmt "bool" else - if is_int_type t then fprintf fmt "int" else (* !Options.int_type *) - if is_real_type t then fprintf fmt "real" else (* !Options.real_type *) - match t.tdesc with - | Tclock t -> - pp_infered_type fmt t - | Tstatic (_, t) -> - fprintf fmt "%a" pp_infered_type t - | Tconst id -> - (* This is a type id for a enumerated type, eg. introduced by automata *) - let typ = - (Corelang.typedef_of_top (Hashtbl.find Corelang.type_table (Tydec_const id))) - in - pp_tag_type fmt typ - | Tlink ty -> - pp_infered_type fmt ty - | _ -> eprintf "unhandled type: %a@." Types.print_node_ty t; assert false + + +(* First try to print the declared one *) let rec pp_concrete_type dec_t infered_t fmt = match dec_t with - | Tydec_int -> fprintf fmt "int" (* !Options.int_type *) - | Tydec_real -> fprintf fmt "real" (* !Options.real_type *) + | Tydec_any -> (* Dynamical built variable. No declared type. Shall + use the infered one. *) + pp_infered_type fmt infered_t + | Tydec_int -> fprintf fmt "{ \"kind\": \"int\" }" (* !Options.int_type *) + | Tydec_real -> fprintf fmt "{ \"kind\": \"real\" }" (* !Options.real_type *) (* TODO we could add more concrete types here if they were available in dec_t *) - | Tydec_bool -> fprintf fmt "bool" + | Tydec_bool -> fprintf fmt "{ \"kind\": \"bool\" }" | Tydec_clock t -> pp_concrete_type t infered_t fmt | Tydec_const id -> ( - (* This is a type id for a enumerated type, eg. introduced by automata *) + (* This is an alias type *) + + (* id for a enumerated type, eg. introduced by automata *) let typ = (Corelang.typedef_of_top (Hashtbl.find Corelang.type_table dec_t)) in - pp_tag_type fmt typ + (* Print the type name associated to this enumerated type. This is + basically an integer *) + pp_tag_type id typ infered_t fmt + ) + + | Tydec_struct _ | Tydec_enum _ -> + assert false (* should not happen. These type are only built when + declaring a type in the prefix of the lustre + file. They shall not be associated to variables + *) + + | Tydec_array (dim, e) -> ( + let inf_base = match infered_t.Typing.tdesc with + | Typing.Tarray(_,t) -> t + | _ -> (* returing something useless, hoping that the concrete + datatype will return something usefull *) + Typing.new_var () + in + fprintf fmt "{ \"kind\": \"array\", \"base_type\": %t, \"dim\": %a }" + (pp_concrete_type e inf_base) + pp_emf_dim dim ) - | Tydec_any -> pp_infered_type fmt infered_t - | _ -> eprintf - "unhandled construct in type printing for EMF backend: %a@." - Printers.pp_var_type_dec_desc dec_t; raise (Failure "var") + +(* | _ -> eprintf + * "unhandled construct in type printing for EMF backend: %a@." + * Printers.pp_var_type_dec_desc dec_t; raise (Failure "var") *) +and pp_tag_type id typ inf fmt = + (* We ought to represent these types as values: enum will become int, we keep the name for structs *) + let rec aux tydec_desc = + match tydec_desc with + | Tydec_int + | Tydec_real + | Tydec_bool + | Tydec_array _ -> pp_concrete_type tydec_desc inf fmt + | Tydec_const id -> + (* Alias of an alias: unrolling definitions *) + let typ = (Corelang.typedef_of_top + (Hashtbl.find Corelang.type_table tydec_desc)) + in + pp_tag_type id typ inf fmt + | Tydec_clock ty -> aux ty + | Tydec_enum const_list -> ( (* enum can be mapped to int *) + let size = List.length const_list in + fprintf fmt "{ \"name\": \"%s\", \"kind\": \"enum\", \"size\": \"%i\" }" id size + ) + | Tydec_struct _ -> + fprintf fmt "{ \"name\": \"%s\", \"kind\": \"struct\" }" id + | Tydec_any -> (* shall not happen: a declared type cannot be + bound to type any *) + assert false + in + aux typ.tydef_desc +and pp_infered_type fmt t = + (* Shall only be used for variable types that were not properly declared. Ie generated at compile time. *) + let open Types in + if is_bool_type t then fprintf fmt "bool" else + if is_int_type t then fprintf fmt "int" else (* !Options.int_type *) + if is_real_type t then fprintf fmt "real" else (* !Options.real_type *) + match t.tdesc with + | Tclock t -> + pp_infered_type fmt t + | Tstatic (_, t) -> + fprintf fmt "%a" pp_infered_type t + | Tconst id -> + (* This is a type id for a enumerated type, eg. introduced by automata *) + let typ = + (Corelang.typedef_of_top + (Hashtbl.find Corelang.type_table (Tydec_const id))) + in + pp_tag_type id typ t fmt + | Tlink ty -> + pp_infered_type fmt ty + | _ -> eprintf "unhandled type: %a@." Types.print_node_ty t; assert false (*let pp_cst_type fmt v = match v.value_desc with | Cst c-> pp_cst_type c v.value_type fmt (* constants do not have declared type (yet) *) | _ -> assert false *) - + +(* Provide both the declared type and the infered one. *) let pp_var_type fmt v = try if Machine_types.is_specified v then Machine_types.pp_var_type fmt v else pp_concrete_type v.var_dec_type.ty_dec_desc v.var_type fmt - with Failure _ -> eprintf "failed var: %a@." Printers.pp_var v; assert false + with Failure msg -> eprintf "failed var: %a@.%s@." Printers.pp_var v msg; assert false (******** Other print functions *) - + +let pp_emf_list ?(eol:('a, formatter, unit) Pervasives.format="") pp fmt l = + match l with + [] -> () + | _ -> fprintf fmt "@["; + Utils.fprintf_list ~sep:",@ " pp fmt l; + fprintf fmt "@]%(%)" eol + +(* Print the variable declaration *) let pp_emf_var_decl fmt v = fprintf fmt "@[{\"name\": \"%a\", \"datatype\":\"%a\", \"original_name\": \"%a\"}@]" pp_var_name v pp_var_type v Printers.pp_var_name v - -let pp_emf_vars_decl fmt vl = - fprintf fmt "@["; - Utils.fprintf_list ~sep:",@ " pp_emf_var_decl fmt vl; - fprintf fmt "@]" + +let pp_emf_vars_decl = pp_emf_list pp_emf_var_decl + + let reset_name id = "reset_" ^ id @@ -187,7 +235,26 @@ let pp_tag_id fmt t = let const_list = match typ.tydef_desc with Tydec_enum tl -> tl | _ -> assert false in fprintf fmt "%i" (get_idx t const_list) -let pp_emf_cst fmt c = +let pp_cst_type c inf fmt (*infered_typ*) = + match c with + | Const_tag t -> + let typ = (Corelang.typedef_of_top (Hashtbl.find Corelang.tag_table t)) in + if typ.tydef_id = "bool" then + fprintf fmt "bool" + else + pp_tag_type t typ inf fmt + | Const_int _ -> fprintf fmt "int" (*!Options.int_type*) + | Const_real _ -> fprintf fmt "real" (*!Options.real_type*) + | Const_string _ -> fprintf fmt "string" + | _ -> eprintf "cst: %a@." Printers.pp_const c; assert false + + +let pp_emf_cst c inf fmt = + let pp_typ fmt = + fprintf fmt "\"datatype\": \""; + pp_cst_type c inf fmt; + fprintf fmt "\"@ " + in match c with | Const_tag t-> let typ = (Corelang.typedef_of_top (Hashtbl.find Corelang.tag_table t)) in @@ -195,7 +262,7 @@ let pp_emf_cst fmt c = fprintf fmt "{@[\"type\": \"constant\",@ "; fprintf fmt"\"value\": \"%a\",@ " Printers.pp_const c; - fprintf fmt "\"datatype\": \"%a\"@ " pp_cst_type c; + pp_typ fmt; fprintf fmt "@]}" ) else ( @@ -203,25 +270,25 @@ let pp_emf_cst fmt c = pp_tag_id t; fprintf fmt "\"origin_type\": \"%s\",@ \"origin_value\": \"%s\",@ " typ.tydef_id t; - fprintf fmt "\"datatype\": \"%a\"@ " pp_cst_type c; + pp_typ fmt; fprintf fmt "@]}" ) | Const_string s -> - fprintf fmt "{@[\"type\": \"constant\",@ \"value\": \"%s\",@ " s; - fprintf fmt "\"datatype\": \"%a\"@ " pp_cst_type c; - fprintf fmt "@]}" + fprintf fmt "{@[\"type\": \"constant\",@ \"value\": \"%s\",@ " s; + pp_typ fmt; + fprintf fmt "@]}" | _ -> ( fprintf fmt "{@[\"type\": \"constant\",@ \"value\": \"%a\",@ " Printers.pp_const c; - fprintf fmt "\"datatype\": \"%a\"@ " pp_cst_type c; + pp_typ fmt; fprintf fmt "@]}" ) - +(* Print a value: either a constant or a variable value *) let pp_emf_cst_or_var m fmt v = match v.value_desc with - | Cst c -> pp_emf_cst fmt c + | Cst c -> pp_emf_cst c v.value_type fmt | Var v -> ( fprintf fmt "{@[\"type\": \"variable\",@ \"value\": \"%a\",@ " pp_var_name v; @@ -239,7 +306,7 @@ let pp_emf_cst_or_var_list m = let rec pp_emf_expr fmt e = match e.expr_desc with - | Expr_const c -> pp_emf_cst fmt c + | Expr_const c -> pp_emf_cst c e.expr_type fmt | Expr_ident id -> fprintf fmt "{@[\"type\": \"variable\",@ \"value\": \"%a\",@ " print_protect (fun fmt -> pp_print_string fmt id); @@ -254,6 +321,18 @@ let rec pp_emf_expr fmt e = | Expr_tuple el -> fprintf fmt "[@[<hov 0>%a@ @]]" (Utils.fprintf_list ~sep:",@ " pp_emf_expr) el + (* Missing these + | Expr_ite of expr * expr * expr + | Expr_arrow of expr * expr + | Expr_fby of expr * expr + | Expr_array of expr list + | Expr_access of expr * Dimension.dim_expr + | Expr_power of expr * Dimension.dim_expr + | Expr_pre of expr + | Expr_when of expr * ident * label + | Expr_merge of ident * (label * expr) list + | Expr_appl of call_t + *) | _ -> ( Log.report ~level:2 (fun fmt -> @@ -274,14 +353,75 @@ let rec pp_emf_expr fmt e = (* | Expr_when of expr * ident * label *) (* | Expr_merge of ident * (label * expr) list *) (* | Expr_appl of call_t *) - +let pp_emf_exprs = pp_emf_list pp_emf_expr + +let pp_emf_const fmt v = + fprintf fmt "@[{\"name\": \"%a\", \"datatype\":\"%a\", \"original_name\": \"%a\", \"value\": \"%a\"}@]" + pp_var_name v + pp_var_type v + Printers.pp_var_name v + pp_emf_expr (match v.var_dec_value with None -> assert false | Some e -> e) + +let pp_emf_consts = pp_emf_list pp_emf_const + let pp_emf_eexpr fmt ee = fprintf fmt "{@[<hov 0>\"quantifiers\": \"%a\",@ \"qfexpr\": @[%a@]@] }" (Utils.fprintf_list ~sep:"; " Printers.pp_quantifiers) ee.eexpr_quantifiers pp_emf_expr ee.eexpr_qfexpr - - + +let pp_emf_eexprs = pp_emf_list pp_emf_eexpr + +(* + TODO Thanksgiving + + trouver un moyen de transformer en machine code les instructions de chaque spec + peut etre associer a chaque imported node une minimachine + et rajouter un champ a spec dans machine code pour stoquer memoire et instr + *) + +let pp_emf_stmt fmt stmt = + match stmt with + | Aut _ -> assert false + | Eq eq -> ( + fprintf fmt "@[ @[<v 2>\"%a\": {@ " (Utils.fprintf_list ~sep:"_" pp_print_string) eq.eq_lhs; + fprintf fmt "\"lhs\": [%a],@ " (Utils.fprintf_list ~sep:", " (fun fmt vid -> fprintf fmt "\"%s\"" vid)) eq.eq_lhs; + fprintf fmt "\"rhs\": \"%a\",@ " pp_emf_expr eq.eq_rhs; + fprintf fmt "@]@]@ }" + ) + +let pp_emf_stmts = pp_emf_list pp_emf_stmt + +(* Printing the type declaration, not its use *) +let rec pp_emf_typ_dec fmt tydef_dec = + fprintf fmt "{"; + (match tydef_dec with + | Tydec_any -> fprintf fmt "\"kind\": \"any\"" + | Tydec_int -> fprintf fmt "\"kind\": \"int\"" + | Tydec_real -> fprintf fmt "\"kind\": \"real\"" + | Tydec_bool-> fprintf fmt "\"kind\": \"bool\"" + | Tydec_clock ck -> pp_emf_typ_dec fmt ck + | Tydec_const c -> fprintf fmt "\"kind\": \"alias\",@ \"value\": \"%s\"" c + | Tydec_enum el -> fprintf fmt "\"kind\": \"enum\",@ \"elements\": [%a]" + (Utils.fprintf_list ~sep:", " (fun fmt e -> fprintf fmt "\"%s\"" e)) el + | Tydec_struct s -> fprintf fmt "\"kind\": \"struct\",@ \"fields\": [%a]" + (Utils.fprintf_list ~sep:", " (fun fmt (id,typ) -> + fprintf fmt "\"%s\": %a" id pp_emf_typ_dec typ)) s + | Tydec_array (dim, typ) -> fprintf fmt "\"kind\": \"array\",@ \"dim\": @[%a@],@ \"base\": %a" + pp_emf_dim dim + pp_emf_typ_dec typ + ); + fprintf fmt "}" + +let pp_emf_typedef fmt typdef_top = + let typedef = Corelang.typedef_of_top typdef_top in + fprintf fmt "\"%s\": @[%a@]" typedef.tydef_id pp_emf_typ_dec typedef.tydef_desc + +let pp_emf_top_const fmt const_top = + let const = Corelang.const_of_top const_top in + fprintf fmt "\"%s\": " const.const_id; + pp_emf_cst const.const_value const.const_type fmt + (* Local Variables: *) (* compile-command: "make -C ../.." *) (* End: *) diff --git a/src/compiler_stages.ml b/src/compiler_stages.ml index d312a874..a6ac6272 100644 --- a/src/compiler_stages.ml +++ b/src/compiler_stages.ml @@ -188,12 +188,13 @@ let stage1 params prog dirname basename extension = Log.report ~level:1 (fun fmt -> fprintf fmt ".. normalization@,"); let prog = Normalization.normalize_prog params prog in Log.report ~level:2 (fun fmt -> fprintf fmt "@[<v 2>@ %a@]@," Printers.pp_prog prog); - + (* Compatibility with Lusi *) (* If compiling a lusi, generate the lusic. If this is a lus file, Check the existence of a lusi (Lustre Interface file) *) compile_source_to_header prog !Global.type_env !Global.clock_env dirname basename extension; + let prog = if !Options.mpfr then diff --git a/src/corelang.ml b/src/corelang.ml index 6d5ad318..48ea8745 100644 --- a/src/corelang.ml +++ b/src/corelang.ml @@ -220,7 +220,6 @@ let mkeexpr loc expr = eexpr_quantifiers = []; eexpr_type = Types.new_var (); eexpr_clock = Clocks.new_var true; - eexpr_normalized = None; eexpr_loc = loc } let extend_eexpr q e = { e with eexpr_quantifiers = q@e.eexpr_quantifiers } @@ -805,13 +804,6 @@ and rename_eexpr f_node f_var ee = eexpr_tag = Utils.new_tag (); 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; - eexpr_normalized = Utils.option_map - (fun (vdecl, eqs, vdecls) -> - rename_var f_node f_var vdecl, - List.map (rename_eq f_node f_var) eqs, - rename_vars f_node f_var vdecls - ) ee.eexpr_normalized; - } @@ -1035,7 +1027,6 @@ let rec substitute_expr vars_to_replace defs e = eexpr_type = expr.expr_type; eexpr_clock = expr.expr_clock; eexpr_loc = expr.expr_loc; - eexpr_normalized = None } (* and expr_desc_to_eexpr_desc expr_desc = *) (* let conv = expr_to_eexpr in *) diff --git a/src/corelang.mli b/src/corelang.mli index 20dd55e1..bb9675b3 100644 --- a/src/corelang.mli +++ b/src/corelang.mli @@ -86,6 +86,7 @@ val const_and: constant -> constant -> constant val const_xor: constant -> constant -> constant val const_impl: constant -> constant -> constant +val get_var: ident -> var_decl list -> var_decl val get_node_vars: node_desc -> var_decl list val get_node_var: ident -> node_desc -> var_decl val get_node_eqs: node_desc -> eq list * automata_desc list diff --git a/src/lustre_types.ml b/src/lustre_types.ml index d3bc43dc..829a9344 100644 --- a/src/lustre_types.ml +++ b/src/lustre_types.ml @@ -118,7 +118,7 @@ and eexpr = eexpr_quantifiers: (quantifier_type * var_decl list) list; mutable eexpr_type: Types.type_expr; mutable eexpr_clock: Clocks.clock_expr; - mutable eexpr_normalized: (var_decl * eq list * var_decl list) option; + (* mutable eexpr_normalized: (var_decl * eq list * var_decl list) option; *) eexpr_loc: Location.t} and expr_annot = diff --git a/src/machine_code.ml b/src/machine_code.ml index f8b88619..143d7d43 100644 --- a/src/machine_code.ml +++ b/src/machine_code.ml @@ -20,40 +20,44 @@ exception NormalizationError -(* translate_<foo> : node -> context -> <foo> -> machine code/expression *) +(* translate_<foo> : vars -> context -> <foo> -> machine code/expression *) (* the context contains m : state aka memory variables *) (* si : initialization instructions *) (* j : node aka machine instances *) (* d : local variables *) (* s : step instructions *) -let translate_ident node (m, si, j, d, s) id = +let translate_ident vars _ (* (m, si, j, d, s) *) id = (* Format.eprintf "trnaslating ident: %s@." id; *) - try (* id is a node var *) - let var_id = get_node_var id node in + try (* id is a var that shall be visible here , ie. in vars *) + let var_id = get_var id vars in mk_val (Var var_id) var_id.var_type with Not_found -> try (* id is a constant *) - let vdecl = (Corelang.var_decl_of_const (const_of_top (Hashtbl.find Corelang.consts_table id))) in + let vdecl = (Corelang.var_decl_of_const + (const_of_top (Hashtbl.find Corelang.consts_table id))) + in mk_val (Var vdecl) vdecl.var_type with Not_found -> (* id is a tag *) - (* DONE construire une liste des enum declarés et alors chercher dedans la liste - qui contient id *) + (* DONE construire une liste des enum declarés et alors chercher + dedans la liste qui contient id *) try let typ = (typedef_of_top (Hashtbl.find Corelang.tag_table id)).tydef_id in mk_val (Cst (Const_tag id)) (Type_predef.type_const typ) - with Not_found -> (Format.eprintf "internal error: Machine_code.translate_ident %s" id; + with Not_found -> (Format.eprintf + "internal error: Machine_code.translate_ident %s" + id; assert false) -let rec control_on_clock node ((m, si, j, d, s) as args) ck inst = +let rec control_on_clock vars ((m, si, j, d, s) as args) ck inst = match (Clocks.repr ck).cdesc with | Con (ck1, cr, l) -> let id = Clocks.const_of_carrier cr in - control_on_clock node args ck1 (mkinstr + control_on_clock vars args ck1 (mkinstr (* TODO il faudrait prendre le lustre associé à instr et rajouter print_ck_suffix ck) de clocks.ml *) - (MBranch (translate_ident node args id, + (MBranch (translate_ident vars args id, [l, [inst]] ))) | _ -> inst @@ -79,31 +83,44 @@ let specialize_op expr = | "C" -> specialize_to_c expr | _ -> expr -let rec translate_expr node ((m, si, j, d, s) as args) expr = +let rec translate_expr vars ((m, si, j, d, s) as args) expr = let expr = specialize_op expr in + (* all calls are using the same arguments (vars for the variable + enviroment and args for computed memories). No fold constructs + here. We can do partial evaluation of translate_expr *) + let translate_expr = translate_expr vars args in let value_desc = match expr.expr_desc with | Expr_const v -> Cst v - | Expr_ident x -> (translate_ident node args x).value_desc - | Expr_array el -> Array (List.map (translate_expr node args) el) - | Expr_access (t, i) -> Access (translate_expr node args t, translate_expr node args (expr_of_dimension i)) - | Expr_power (e, n) -> Power (translate_expr node args e, translate_expr node args (expr_of_dimension n)) + | Expr_ident x -> (translate_ident vars args x).value_desc + | Expr_array el -> Array (List.map translate_expr el) + | Expr_access (t, i) -> Access (translate_expr t, + translate_expr + (expr_of_dimension i)) + | Expr_power (e, n) -> Power (translate_expr e, + translate_expr + (expr_of_dimension n)) | Expr_tuple _ - | Expr_arrow _ - | Expr_fby _ - | Expr_pre _ -> (Printers.pp_expr Format.err_formatter expr; Format.pp_print_flush Format.err_formatter (); raise NormalizationError) - | Expr_when (e1, _, _) -> (translate_expr node args e1).value_desc + | Expr_arrow _ + | Expr_fby _ + | Expr_pre _ -> (Printers.pp_expr + Format.err_formatter expr; + Format.pp_print_flush + Format.err_formatter (); + raise NormalizationError) + + | Expr_when (e1, _, _) -> (translate_expr e1).value_desc | Expr_merge (x, _) -> raise NormalizationError | Expr_appl (id, e, _) when Basic_library.is_expr_internal_fun expr -> - let nd = node_from_name id in - Fun (node_name nd, List.map (translate_expr node args) (expr_list_of_expr e)) + let nd = node_from_name id in + Fun (node_name nd, List.map translate_expr (expr_list_of_expr e)) | Expr_ite (g,t,e) -> ( (* special treatment depending on the active backend. For horn backend, ite are preserved in expression. While they are removed for C or Java backends. *) match !Options.output with | "horn" -> - Fun ("ite", [translate_expr node args g; translate_expr node args t; translate_expr node args e]) + Fun ("ite", [translate_expr g; translate_expr t; translate_expr e]) | "C" | "java" | _ -> (Format.eprintf "Normalization error for backend %s: %a@." !Options.output @@ -114,65 +131,89 @@ let rec translate_expr node ((m, si, j, d, s) as args) expr = in mk_val value_desc expr.expr_type -let translate_guard node args expr = +let translate_guard vars args expr = match expr.expr_desc with - | Expr_ident x -> translate_ident node args x - | _ -> (Format.eprintf "internal error: translate_guard %s %a@." node.node_id Printers.pp_expr expr;assert false) + | Expr_ident x -> translate_ident vars args x + | _ -> (Format.eprintf "internal error: translate_guard %a@." + Printers.pp_expr expr; + assert false) -let rec translate_act node ((m, si, j, d, s) as args) (y, expr) = +let rec translate_act vars ((m, si, j, d, s) as args) (y, expr) = + let translate_act = translate_act vars args in + let translate_guard = translate_guard vars args in + let translate_ident = translate_ident vars args in + let translate_expr = translate_expr vars args in let eq = Corelang.mkeq Location.dummy_loc ([y.var_id], expr) in match expr.expr_desc with - | Expr_ite (c, t, e) -> let g = translate_guard node args c in + | Expr_ite (c, t, e) -> let g = translate_guard c in mk_conditional ?lustre_eq:(Some eq) g - [translate_act node args (y, t)] - [translate_act node args (y, e)] - | Expr_merge (x, hl) -> mkinstr ?lustre_eq:(Some eq) (MBranch (translate_ident node args x, - List.map (fun (t, h) -> t, [translate_act node args (y, h)]) hl)) - | _ -> mkinstr ?lustre_eq:(Some eq) (MLocalAssign (y, translate_expr node args expr)) + [translate_act (y, t)] + [translate_act (y, e)] + | Expr_merge (x, hl) -> mkinstr ?lustre_eq:(Some eq) + (MBranch (translate_ident x, + List.map (fun (t, h) -> + t, [translate_act (y, h)]) + hl)) + | _ -> mkinstr ?lustre_eq:(Some eq) + (MLocalAssign (y, translate_expr expr)) -let reset_instance node args i r c = +let reset_instance vars args i r c = match r with | None -> [] - | Some r -> let g = translate_guard node args r in - [control_on_clock node args c (mk_conditional g [mkinstr (MReset i)] [mkinstr (MNoReset i)])] + | Some r -> let g = translate_guard vars args r in + [control_on_clock + vars + args + c + (mk_conditional + g + [mkinstr (MReset i)] + [mkinstr (MNoReset i)]) + ] + +let translate_eq vars ((m, si, j, d, s) as args) eq = + let translate_expr = translate_expr vars args in + let translate_act = translate_act vars args in + let control_on_clock = control_on_clock vars args in + let reset_instance = reset_instance vars args in -let translate_eq node ((m, si, j, d, s) as args) eq = - (* Format.eprintf "translate_eq %a with clock %a@." Printers.pp_node_eq eq Clocks.print_ck eq.eq_rhs.expr_clock; *) + (* Format.eprintf "translate_eq %a with clock %a@." + Printers.pp_node_eq eq Clocks.print_ck eq.eq_rhs.expr_clock; *) match eq.eq_lhs, eq.eq_rhs.expr_desc with | [x], Expr_arrow (e1, e2) -> - let var_x = get_node_var x node in - let o = new_instance node Arrow.arrow_top_decl eq.eq_rhs.expr_tag in - let c1 = translate_expr node args e1 in - let c2 = translate_expr node args e2 in + let var_x = get_var x vars in + let o = new_instance Arrow.arrow_top_decl eq.eq_rhs.expr_tag in + let c1 = translate_expr e1 in + let c2 = translate_expr e2 in (m, mkinstr (MReset o) :: si, Utils.IMap.add o (Arrow.arrow_top_decl, []) j, d, - (control_on_clock node args eq.eq_rhs.expr_clock (mkinstr ?lustre_eq:(Some eq) (MStep ([var_x], o, [c1;c2])))) :: s) - | [x], Expr_pre e1 when VSet.mem (get_node_var x node) d -> - let var_x = get_node_var x node in + (control_on_clock eq.eq_rhs.expr_clock (mkinstr ?lustre_eq:(Some eq) (MStep ([var_x], o, [c1;c2])))) :: s) + | [x], Expr_pre e1 when VSet.mem (get_var x vars) d -> + let var_x = get_var x vars in (VSet.add var_x m, si, j, d, - control_on_clock node args eq.eq_rhs.expr_clock (mkinstr ?lustre_eq:(Some eq) (MStateAssign (var_x, translate_expr node args e1))) :: s) - | [x], Expr_fby (e1, e2) when VSet.mem (get_node_var x node) d -> - let var_x = get_node_var x node in + control_on_clock eq.eq_rhs.expr_clock (mkinstr ?lustre_eq:(Some eq) (MStateAssign (var_x, translate_expr e1))) :: s) + | [x], Expr_fby (e1, e2) when VSet.mem (get_var x vars) d -> + let var_x = get_var x vars in (VSet.add var_x m, - mkinstr ?lustre_eq:(Some eq) (MStateAssign (var_x, translate_expr node args e1)) :: si, + mkinstr ?lustre_eq:(Some eq) (MStateAssign (var_x, translate_expr e1)) :: si, j, d, - control_on_clock node args eq.eq_rhs.expr_clock (mkinstr ?lustre_eq:(Some eq) (MStateAssign (var_x, translate_expr node args e2))) :: s) + control_on_clock eq.eq_rhs.expr_clock (mkinstr ?lustre_eq:(Some eq) (MStateAssign (var_x, translate_expr e2))) :: s) | p , Expr_appl (f, arg, r) when not (Basic_library.is_expr_internal_fun eq.eq_rhs) -> - let var_p = List.map (fun v -> get_node_var v node) p in + let var_p = List.map (fun v -> get_var v vars) p in let el = expr_list_of_expr arg in - let vl = List.map (translate_expr node args) el in + let vl = List.map translate_expr el in let node_f = node_from_name f in let call_f = node_f, NodeDep.filter_static_inputs (node_inputs node_f) el in - let o = new_instance node node_f eq.eq_rhs.expr_tag in + let o = new_instance node_f eq.eq_rhs.expr_tag in let env_cks = List.fold_right (fun arg cks -> arg.expr_clock :: cks) el [eq.eq_rhs.expr_clock] in let call_ck = Clock_calculus.compute_root_clock (Clock_predef.ck_tuple env_cks) in (*Clocks.new_var true in @@ -184,8 +225,8 @@ let translate_eq node ((m, si, j, d, s) as args) eq = d, (if Stateless.check_node node_f then [] - else reset_instance node args o r call_ck) @ - (control_on_clock node args call_ck (mkinstr ?lustre_eq:(Some eq) (MStep (var_p, o, vl)))) :: s) + else reset_instance o r call_ck) @ + (control_on_clock call_ck (mkinstr ?lustre_eq:(Some eq) (MStep (var_p, o, vl)))) :: s) (* (* special treatment depending on the active backend. For horn backend, x = ite (g,t,e) are preserved. While they are replaced as if g then x = t else x = e in C or Java @@ -204,13 +245,11 @@ let translate_eq node ((m, si, j, d, s) as args) eq = *) | [x], _ -> ( - let var_x = get_node_var x node in + let var_x = get_var x vars in (m, si, j, d, control_on_clock - node - args eq.eq_rhs.expr_clock - (translate_act node args (var_x, eq.eq_rhs)) :: s + (translate_act (var_x, eq.eq_rhs)) :: s ) ) | _ -> @@ -235,15 +274,8 @@ let constant_equations nd = let translate_eqs node args eqs = List.fold_right (fun eq args -> translate_eq node args eq) eqs args;; -let translate_decl nd sch = - (*Log.report ~level:1 (fun fmt -> Printers.pp_node fmt nd);*) - let schedule = sch.Scheduling_type.schedule in - let sorted_eqs = Scheduling.sort_equations_from_schedule nd schedule in - let constant_eqs = constant_equations nd in - - (* In case of non functional backend (eg. C), additional local variables have - to be declared for each assert *) - let new_locals, assert_instrs, nd_node_asserts = +let process_asserts nd = + let exprl = List.map (fun assert_ -> assert_.assert_expr ) nd.node_asserts in if Backends.is_functional () then [], [], exprl @@ -267,21 +299,41 @@ let translate_decl nd sch = in assert_var.var_type <- Type_predef.type_bool (* Types.new_ty (Types.Tbool) *); let eq = mkeq loc ([var_id], expr) in - (i+1, assert_var::vars, eq::eqlist, {expr with expr_desc = Expr_ident var_id}::assertlist) + (i+1, assert_var::vars, eq::eqlist, {expr with expr_desc = Expr_ident var_id}::assertlist) ) (1, [], [], []) exprl in vars, eql, assertl - in - let locals_list = nd.node_locals @ new_locals in + +let translate_decl nd sch = + (*Log.report ~level:1 (fun fmt -> Printers.pp_node fmt nd);*) + let schedule = sch.Scheduling_type.schedule in + let sorted_eqs = Scheduling.sort_equations_from_schedule nd schedule in + let constant_eqs = constant_equations nd in + (* In case of non functional backend (eg. C), additional local variables have + to be declared for each assert *) + let new_locals, assert_instrs, nd_node_asserts = process_asserts nd in + let locals_list = nd.node_locals @ new_locals in let nd = { nd with node_locals = locals_list } in + let vars = get_node_vars nd in + let init_args = VSet.empty, [], Utils.IMap.empty, List.fold_right (fun l -> VSet.add l) locals_list VSet.empty, [] in (* memories, init instructions, node calls, local variables (including memories), step instrs *) - let m0, init0, j0, locals0, s0 = translate_eqs nd init_args constant_eqs in + + let m0, init0, j0, locals0, s0 = + translate_eqs vars init_args constant_eqs + in + assert (VSet.is_empty m0); assert (init0 = []); assert (Utils.IMap.is_empty j0); - let m, init, j, locals, s as context_with_asserts = translate_eqs nd (m0, init0, j0, locals0, []) (assert_instrs@sorted_eqs) in + + let m, init, j, locals, s as context_with_asserts = + translate_eqs + vars + (m0, init0, j0, locals0, []) + (assert_instrs@sorted_eqs) + in let mmap = Utils.IMap.fold (fun i n res -> (i, n)::res) j [] in { mname = nd; @@ -295,7 +347,10 @@ let translate_decl nd sch = step_inputs = nd.node_inputs; step_outputs = nd.node_outputs; step_locals = VSet.elements (VSet.diff locals m); - step_checks = List.map (fun d -> d.Dimension.dim_loc, translate_expr nd init_args (expr_of_dimension d)) nd.node_checks; + step_checks = List.map (fun d -> d.Dimension.dim_loc, + translate_expr vars init_args + (expr_of_dimension d)) + nd.node_checks; step_instrs = ( (* special treatment depending on the active backend. For horn backend, common branches are not merged while they are in C or Java @@ -308,7 +363,7 @@ let translate_decl nd sch = else s ); - step_asserts = List.map (translate_expr nd context_with_asserts) nd_node_asserts; + step_asserts = List.map (translate_expr vars context_with_asserts) nd_node_asserts; }; mspec = nd.node_spec; mannot = nd.node_annot; diff --git a/src/machine_code_common.ml b/src/machine_code_common.ml index d72cf89d..f784d10f 100644 --- a/src/machine_code_common.ml +++ b/src/machine_code_common.ml @@ -216,7 +216,7 @@ let empty_machine = let new_instance = let cpt = ref (-1) in - fun caller callee tag -> + fun callee tag -> begin let o = if Stateless.check_node callee then @@ -225,7 +225,9 @@ let new_instance = Printf.sprintf "ni_%d" (incr cpt; !cpt) in let o = if !Options.ansi && is_generic_node callee - then Printf.sprintf "%s_inst_%d" o (Utils.position (fun e -> e.expr_tag = tag) caller.node_gencalls) + then Printf.sprintf "%s_inst_%d" + o + (incr cpt; !cpt) else o in o end diff --git a/src/machine_code_common.mli b/src/machine_code_common.mli index a5eede3d..ad080b34 100644 --- a/src/machine_code_common.mli +++ b/src/machine_code_common.mli @@ -9,7 +9,7 @@ val mk_val: Machine_code_types.value_t_desc -> Types.type_expr -> Machine_code_t val mk_conditional: ?lustre_eq:Lustre_types.eq -> Machine_code_types.value_t -> Machine_code_types.instr_t list -> Machine_code_types.instr_t list -> Machine_code_types.instr_t val empty_machine: Machine_code_types.machine_t val arrow_machine: Machine_code_types.machine_t -val new_instance: Lustre_types.node_desc -> Lustre_types.top_decl -> Lustre_types.tag -> Lustre_types.ident +val new_instance: Lustre_types.top_decl -> Lustre_types.tag -> Lustre_types.ident val value_of_dimension: Machine_code_types.machine_t -> Dimension.dim_expr -> Machine_code_types.value_t val dimension_of_value:Machine_code_types.value_t -> Dimension.dim_expr val pp_instr: Machine_code_types.machine_t -> Format.formatter -> Machine_code_types.instr_t -> unit diff --git a/src/machine_code_types.ml b/src/machine_code_types.ml index 7a614e29..4d962b66 100644 --- a/src/machine_code_types.ml +++ b/src/machine_code_types.ml @@ -41,6 +41,7 @@ and instr_t_desc = type static_call = top_decl * (Dimension.dim_expr list) + type machine_t = { mname: node_desc; mmemory: var_decl list; diff --git a/src/normalization.ml b/src/normalization.ml index e151836a..ca5cfd76 100644 --- a/src/normalization.ml +++ b/src/normalization.ml @@ -170,14 +170,16 @@ let mk_expr_alias_opt opt norm_ctx (defs, vars) expr = then let new_aliases = List.map2 - (mk_fresh_var (norm_ctx.parentid, norm_ctx.vars) expr.expr_loc) + (mk_fresh_var (norm_ctx.parentid, (norm_ctx.vars@vars)) expr.expr_loc) (Types.type_list_of_type expr.expr_type) (Clocks.clock_list_of_clock expr.expr_clock) in let new_def = mkeq expr.expr_loc (List.map (fun v -> v.var_id) new_aliases, expr) in (* Typing and Registering machine type *) - let _ = if Machine_types.is_active then Machine_types.type_def (norm_ctx.parentid, norm_ctx.vars) new_aliases expr in + let _ = if Machine_types.is_active then + Machine_types.type_def (norm_ctx.parentid, norm_ctx.vars) new_aliases expr + in (new_def::defs, new_aliases@vars), replace_expr new_aliases expr else (defs, vars), expr @@ -400,46 +402,110 @@ let rec normalize_eq norm_ctx defvars eq = let normalize_eq_split norm_ctx defvars eq = try let defs, vars = normalize_eq norm_ctx defvars eq in - List.fold_right (fun eq (def, vars) -> - let eq_defs = Splitting.tuple_split_eq eq in - if eq_defs = [eq] then - eq::def, vars - else - List.fold_left (normalize_eq norm_ctx) (def, vars) eq_defs - ) defs ([], vars) - - with _ -> ( + List.fold_right (fun eq (def, vars) -> + let eq_defs = Splitting.tuple_split_eq eq in + if eq_defs = [eq] then + eq::def, vars + else + List.fold_left (normalize_eq norm_ctx) (def, vars) eq_defs + ) defs ([], vars) + + with ex -> ( Format.eprintf "Issue normalizing eq split: %a@." Printers.pp_node_eq eq; - assert false + raise ex ) -let normalize_eexpr decls norm_ctx vars ee = ee (* - (* New output variable *) - let output_id = "spec" ^ string_of_int ee.eexpr_tag in - let output_var = - mkvar_decl - ee.eexpr_loc - (output_id, - mktyp ee.eexpr_loc Tydec_any, (*TODO: Make it bool when it is spec *) - mkclock ee.eexpr_loc Ckdec_any, - false (* not a constant *), - None, - None - ) +(* Projecting an eexpr to an eexpr associated to a single + variable. Returns the updated ee, the bounded variable and the + associated statement *) +let normalize_pred_eexpr decls 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 ( + (* New output variable *) + let output_id = "spec" ^ string_of_int ee.eexpr_tag in + let output_var = + mkvar_decl + ee.eexpr_loc + (output_id, + mktyp ee.eexpr_loc Tydec_bool, (* It is a predicate, hence a bool *) + mkclock ee.eexpr_loc Ckdec_any, + false (* not a constant *), + None, + None + ) + in + 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 + + (* Now processing a fresh equation output_id = eexpr_qfexpr. We + 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 + + (* Normalizing expr and eqs *) + let defs, vars = List.fold_left (normalize_eq_split norm_ctx) (def, vars) eqs 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) + (ISet.add output_id ISet.empty) vars in + *) + + (* Typing / Clocking *) + try + ignore (Typing.type_var_decl_list vars !Global.type_env vars); + (* + let env = Typing.type_var_decl [] !Global.type_env xxxx output_var in (* typing the variable *) + (* Format.eprintf "typing var %s: %a@." output_id Types.print_ty output_var.var_type; *) + let env = Typing.type_var_decl_list (vars@node.node_outputs@node.node_inputs) env (vars@node.node_outputs@node.node_inputs) in + (*Format.eprintf "Env: %a@.@?" (Env.pp_env Types.print_ty) env;*) + let undefined_vars = List.fold_left (Typing.type_eq (env, quant_vars@vars) false) todefine defs in + (* check that table is empty *) + if (not (ISet.is_empty undefined_vars)) then + raise (Types.Error (ee.eexpr_loc, Types.Undefined_var undefined_vars)); + + (*Format.eprintf "normalized eqs %a@.@?" + (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs; *) + *) + + 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 + (Utils.fprintf_list ~sep:", " Printers.pp_node_eq) defs + Location.pp_loc loc + + + ; + raise exc + + ) + + (* let quant_vars = List.flatten (List.map snd ee.eexpr_quantifiers) in (* Calls are first inlined *) - let nodes = get_nodes decls in - let calls = ISet.elements (get_expr_calls nodes ee.eexpr_qfexpr) in -(* TODO remettre egalement, i ly a un probleme de decapsulage de nodes - let calls = List.map - (fun called_nd -> List.find (fun nd2 -> nd2.node_id = called_nd) nodes) calls - in -*) + (*Format.eprintf "eexpr %a@.calls: %a@.@?" Printers.pp_eexpr ee (Utils.fprintf_list ~sep:", " (fun fmt nd -> pp_print_string fmt nd.node_id)) calls; *) - let eq = mkeq ee.eexpr_loc ([output_id], ee.eexpr_qfexpr) in - let locals = node.node_locals @ (List.fold_left (fun accu (_, q) -> q@accu) [] ee.eexpr_quantifiers) in let (new_locals, eqs) = if calls = [] && not (eq_has_arrows eq) then (locals, [eq]) @@ -485,35 +551,70 @@ let normalize_eexpr decls norm_ctx vars ee = ee (* raise exc *) - -let normalize_spec decls iovars s = s (* - (* Each stmt is normalized *) - let orig_vars = iovars @ s.locals in + +(* We use node local vars to make sure we are creating fresh variables *) +let normalize_spec decls parentid (in_vars, out_vars, l_vars) s = + (* Original set of variables actually visible from here: iun/out and + spec locals (no node locals) *) + let orig_vars = in_vars @ out_vars @ s.locals in let not_is_orig_var v = List.for_all ((!=) v) orig_vars in - let defs, vars = - let eqs, auts = List.fold_right (fun (el,al) s -> match s with Eq e -> e::el, al | Aut a -> el, a::al) s.stmts ([], []) in - if auts != [] then assert false; (* Automata should be expanded by now. *) - List.fold_left (normalize_eq node) ([], orig_vars) eqs + let norm_ctx = { + parentid = parentid; + vars = in_vars @ out_vars @ l_vars; + is_output = (fun _ -> false) (* no need to introduce fresh variables for outputs *); + } + in + (* Normalizing existing stmts *) + let eqs, auts = List.fold_right (fun s (el,al) -> match s with Eq e -> e::el, al | Aut a -> el, a::al) s.stmts ([], []) in + if auts != [] then assert false; (* Automata should be expanded by now. *) + let defsvars = + List.fold_left (normalize_eq norm_ctx) ([], orig_vars) eqs + in + (* 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) -> + let ee', defvars = normalize_pred_eexpr decls norm_ctx defvars ee in + ee'::accu, defvars + ) l ([], defvars) in - let new_locals = List.filter not_is_orig_var vars in (* removing inouts and initial locals ones *) - (* + + let assume', defsvars = process_predicates s.assume defsvars in + let guarantees', defsvars = process_predicates s.guarantees defsvars in + let 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) + in + + let new_locals = List.filter not_is_orig_var vars in (* removing inouts and initial locals ones *) + {s with locals = s.locals @ new_locals; stmts = List.map (fun eq -> Eq eq) defs; - let nee _ = () in - (*normalize_eexpr decls iovars in *) - List.iter nee s.assume; - List.iter nee s.guarantees; - List.iter (fun m -> - List.iter nee m.require; - List.iter nee m.ensure - ) s.modes; - *) - s - *) + assume = assume'; + guarantees = guarantees'; + modes = modes' + } +(* let nee _ = () in + * (\*normalize_eexpr decls iovars in *\) + * List.iter nee s.assume; + * List.iter nee s.guarantees; + * List.iter (fun m -> + * List.iter nee m.require; + * List.iter nee m.ensure + * ) s.modes; *) + + + + + (* The normalization phase introduces new local variables - output cannot be memories. If this happen, new local variables acting as @@ -534,8 +635,7 @@ let normalize_spec decls iovars s = s (* *) let normalize_node decls node = reset_cpt_fresh (); - let inputs_outputs = node.node_inputs@node.node_outputs in - let orig_vars = inputs_outputs@node.node_locals in + 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 let norm_ctx = { @@ -636,7 +736,7 @@ let normalize_node decls node = Careful: we do not normalize annotations, since they can have the form x = (a, b, c) *) - match node.node_spec with None -> None | Some s -> Some (normalize_spec decls inputs_outputs s) + match node.node_spec with None -> None | Some s -> Some (normalize_spec decls node.node_id (node.node_inputs, node.node_outputs, node.node_locals) s) end in @@ -658,8 +758,7 @@ let normalize_inode decls nd = match nd.nodei_spec with None -> nd | Some s -> - let inputs_outputs = nd.nodei_inputs@nd.nodei_outputs in - let s = normalize_spec decls inputs_outputs s in + let s = normalize_spec decls nd.nodei_id (nd.nodei_inputs, nd.nodei_outputs, []) s in { nd with nodei_spec = Some s } let normalize_decl (decls: program_t) (decl: top_decl) : top_decl = diff --git a/src/typing.ml b/src/typing.ml index cf4d79ef..dfee23e2 100644 --- a/src/typing.ml +++ b/src/typing.ml @@ -27,7 +27,7 @@ open Corelang open Format -(* TODO general remark: expect in the add_vdelc, it seems to me that +(* TODO general remark: except in the add_vdecl, it seems to me that all the pairs (env, vd_env) should be replace with just env, since vd_env is never used and the env element is always extract with a fst *) @@ -686,7 +686,16 @@ module Make (T: Types.S) (Expr_type_hub: EXPR_TYPE_HUB with type type_expr = T.t undefined_vars_init eqs in - + (* Typing each predicate expr *) + let type_pred_ee ee : unit= + type_subtyping_arg (env, vd_env) (false (* not in main *)) (false (* not a const *)) ee.eexpr_qfexpr type_bool + in + List.iter type_pred_ee + ( + spec.assume + @ spec.guarantees + @ List.flatten (List.map (fun m -> m.ensure @ m.require) spec.modes) + ); (*TODO enrich env locally with locals and consts type each pre/post as a boolean expr -- GitLab