(**************************************************************************) (* *) (* Heptagon *) (* *) (* Author : Marc Pouzet *) (* Organization : Demons, LRI, University of Paris-Sud, Orsay *) (* *) (**************************************************************************) (* The internal MiniLustre representation *) open Location open Dep open Misc open Names open Ident open Signature open Static type iterator_type = | Imap | Ifold | Imapfold type type_dec = { t_name: name; t_desc: tdesc; t_loc: location } and tdesc = | Type_abs | Type_enum of name list | Type_struct of structure and exp = { e_desc: desc; (* its descriptor *) mutable e_ck: ck; mutable e_ty: ty; e_loc: location } and desc = | Econst of const | Evar of ident | Econstvar of name | Efby of const option * exp | Etuple of exp list | Ecall of op_desc * exp list * ident option (** [op_desc] is the function called [exp list] is the passed arguments [ident option] is the optional reset condition *) | Ewhen of exp * longname * ident | Emerge of ident * (longname * exp) list | Eifthenelse of exp * exp * exp | Efield of exp * longname | Efield_update of longname * exp * exp (*field, record, value*) | Estruct of (longname * exp) list | Earray of exp list | Earray_op of array_op and array_op = | Erepeat of size_exp * exp | Eselect of size_exp list * exp (*indices, array*) | Eselect_dyn of exp list * size_exp list * exp * exp (*indices, bounds, array, default*) | Eupdate of size_exp list * exp * exp (*indices, array, value*) | Eselect_slice of size_exp * size_exp * exp (*lower bound, upper bound, array*) | Econcat of exp * exp | Eiterator of iterator_name * longname * size_exp list * size_exp * exp list * ident option and op_desc = longname * size_exp list * op_kind and op_kind = | Eop | Enode and ct = | Ck of ck | Cprod of ct list and ck = | Cbase | Cvar of link ref | Con of ck * longname * ident and link = | Cindex of int | Clink of ck and const = | Cint of int | Cfloat of float | Cconstr of longname | Carray of size_exp * const and pat = | Etuplepat of pat list | Evarpat of ident type eq = { eq_lhs : pat; eq_rhs : exp; eq_loc : loc } type var_dec = { v_name : ident; v_type : ty; v_clock : ck } type contract = { c_assume : exp; c_enforce : exp; c_controllables : var_dec list; c_local : var_dec list; c_eq : eq list; } type node_dec = { n_name : name; n_input : var_dec list; n_output : var_dec list; n_contract : contract option; n_local : var_dec list; n_equs : eq list; n_loc : location; n_params : param list; n_params_constraints : size_constr list; n_params_instances : (int list) list; }(*TODO commenter ou passer en env*) type const_dec = { c_name : name; c_value : size_exp; c_loc : location; } type program = { p_pragmas: (name * string) list; p_opened : name list; p_types : type_dec list; p_nodes : node_dec list; p_consts : const_dec list; } (*Helper functions to build the AST*) let make_exp desc ty l ck loc = { e_desc = desc; e_ty = ty; e_linearity = l; e_ck = ck; e_loc = loc } let make_dummy_exp desc ty = { e_desc = desc; e_ty = ty; e_linearity = NotLinear; e_ck = Cbase; e_loc = no_location } let rec size_exp_of_exp e = match e.e_desc with | Econstvar n -> SVar n | Econst (Cint i) -> SConst i | Eop(op, _, [e1;e2]) -> let sop = op_from_app_name op in SOp(sop, size_exp_of_exp e1, size_exp_of_exp e2) | _ -> raise Not_static (*Returns the list of bounds of an array type*) let rec bounds_list ty = match ty with | Tarray(ty, n) -> n::(bounds_list ty) | _ -> [] (** Returns the var_dec object corresponding to the name n in a list of var_dec. *) let rec vd_find n = function | [] -> Format.printf "Not found var %s\n" (name n); raise Not_found | vd::l -> if vd.v_name = n then vd else vd_find n l (** Returns whether an object of name n belongs to a list of var_dec. *) let rec vd_mem n = function | [] -> false | vd::l -> vd.v_name = n or (vd_mem n l) (** [is_record_type ty] returns whether ty corresponds to a record type. *) let is_record_type ty = match ty with | Tid n -> (try ignore (Modules.find_struct n); true with Not_found -> false ) | _ -> false module Vars = struct let rec vars_pat acc = function | Evarpat(x) -> x :: acc | Etuplepat(pat_list) -> List.fold_left vars_pat acc pat_list let rec vars_ck acc = function | Con(ck, c, n) -> if List.mem (IVar n) acc then acc else (IVar n) :: acc | Cbase | Cvar { contents = Cindex _ } -> acc | Cvar { contents = Clink ck } -> vars_ck acc ck let rec read is_left acc e = let add x acc = if List.mem (IVar x) acc then acc else (IVar x) :: acc in let acc = match e.e_desc with | Emerge(x, c_e_list) -> let acc = add x acc in List.fold_left (fun acc (_, e) -> read is_left acc e) acc c_e_list | Eifthenelse(e1, e2, e3) -> read is_left (read is_left (read is_left acc e1) e2) e3 | Ewhen(e, c, x) -> let acc = add x acc in read is_left acc e | Eop(_, _, e_list) | Etuple(e_list) -> List.fold_left (read is_left) acc e_list | Eapp(_, _, e_list) -> List.fold_left (read is_left) acc e_list | Eevery(_, _, e_list, x) -> let acc = add x acc in List.fold_left (read is_left) acc e_list | Efby(_, e) -> if is_left then vars_ck acc e.e_ck else read is_left acc e | Ereset_mem (_, _,res) -> add res acc | Evar(n) -> add n acc | Efield({ e_desc = Evar x }, f) -> let acc = add x acc in let x = IField(x,f) in if List.mem x acc then acc else x::acc | Efield(e, _) -> read is_left acc e | Estruct(f_e_list) -> List.fold_left (fun acc (_, e) -> read is_left acc e) acc f_e_list | Econst _ | Econstvar _ -> acc (*Array operators*) | Earray e_list -> List.fold_left (read is_left) acc e_list | Erepeat (_,e) -> read is_left acc e | Eselect (_,e) -> read is_left acc e | Eselect_dyn (e_list, _, e1, e2) -> let acc = List.fold_left (read is_left) acc e_list in read is_left (read is_left acc e1) e2 | Eupdate (_, e1, e2) | Efield_update (_, e1, e2) -> read is_left (read is_left acc e1) e2 | Eselect_slice (_ , _, e) -> read is_left acc e | Econcat (e1, e2) -> read is_left (read is_left acc e1) e2 | Eiterator (_, _, _, _, e_list, _) -> List.fold_left (read is_left) acc e_list in vars_ck acc e.e_ck let rec remove x = function | [] -> [] | y :: l -> if x = y then l else y :: remove x l let def acc { eq_lhs = pat } = vars_pat acc pat let read is_left { eq_lhs = pat; eq_rhs = e } = match pat, e.e_desc with | Evarpat(n), Efby(_, e1) -> if is_left then remove (IVar n) (read is_left [] e1) else read is_left [] e1 | _ -> read is_left [] e let rec remove_records = function | [] -> [] | (IVar x)::l -> (IVar x)::(remove_records l) | (IField(x,f))::l -> let l = remove (IVar x) l in (IField(x,f))::(remove_records l) let read_ivars is_left eq = remove_records (read is_left eq) let read is_left eq = filter_vars (read is_left eq) let antidep { eq_rhs = e } = match e.e_desc with Efby _ -> true | _ -> false let clock { eq_rhs = e } = match e.e_desc with | Emerge(_, (_, e) :: _) -> e.e_ck | _ -> e.e_ck let head ck = let rec headrec ck l = match ck with | Cbase | Cvar { contents = Cindex _ } -> l | Con(ck, c, n) -> headrec ck (n :: l) | Cvar { contents = Clink ck } -> headrec ck l in headrec ck [] let rec linear_use acc e = match e.e_desc with | Emerge(_, c_e_list) -> List.fold_left (fun acc (_, e) -> linear_use acc e) acc c_e_list | Eifthenelse(e1, e2, e3) -> linear_use (linear_use (linear_use acc e1) e2) e3 | Ewhen(e, _, _) | Efield(e, _) | Efby(_, e) -> linear_use acc e | Eop(_,_, e_list) | Etuple(e_list) | Earray e_list | Eapp(_,_, e_list) | Eiterator (_, _, _, _, e_list, _) | Eevery(_,_, e_list, _) -> List.fold_left linear_use acc e_list | Evar(n) -> (match e.e_linearity with | At _ -> if List.mem n acc then acc else n :: acc | _ -> acc ) | Estruct(f_e_list) -> List.fold_left (fun acc (_, e) -> linear_use acc e) acc f_e_list | Econst _ | Econstvar _ | Ereset_mem (_, _,_) -> acc (*Array operators*) | Erepeat (_,e) | Eselect (_,e) | Eselect_slice (_ , _, e) -> linear_use acc e | Eselect_dyn (e_list, _, e1, e2) -> let acc = List.fold_left linear_use acc e_list in linear_use (linear_use acc e1) e2 | Eupdate (_, e1, e2) | Efield_update (_, e1, e2) | Econcat (e1, e2) -> linear_use (linear_use acc e1) e2 let mem_reset { eq_rhs = e } = match e.e_desc with | Ereset_mem (y, _, _) -> [y] | _ -> [] end (* data-flow dependences. pre-dependences are discarded *) module DataFlowDep = Make (struct type equation = eq let read eq = Vars.read true eq let def = Vars.def let linear_read eq = Vars.linear_use [] eq.eq_rhs let mem_reset = Vars.mem_reset let antidep = Vars.antidep end) (* all dependences between variables *) module AllDep = Make (struct type equation = eq let read eq = Vars.read false eq let linear_read eq = Vars.linear_use [] eq.eq_rhs let mem_reset = Vars.mem_reset let def = Vars.def let antidep eq = false end) module Printer = struct open Format let is_infix = let module StrSet = Set.Make(String) in let set_infix = StrSet.singleton "or" in fun s -> if (StrSet.mem s set_infix) then true else begin match (String.get s 0) with | 'a' .. 'z' | 'A' .. 'Z' | '_' | '`' -> false | _ -> true end let rec print_list ff print sep l = match l with | [] -> () | [x] -> print ff x | x :: l -> print ff x; fprintf ff "%s@ " sep; print_list ff print sep l let print_name ff n = let n = if is_infix n then match n with | "*" -> "( * )" | _ -> "(" ^ n ^ ")" else n in fprintf ff "%s" n let print_longname ff n = match n with | Name(m) -> print_name ff m | Modname({ qual = "Pervasives"; id = m }) -> print_name ff m | Modname({ qual = m1; id = m2 }) -> fprintf ff "%s." m1; print_name ff m2 let print_ident ff id = fprintf ff "%s" (name id) let rec print_pat ff = function | Evarpat(n) -> print_ident ff n | Etuplepat(pat_list) -> fprintf ff "@[("; print_list ff print_pat "," pat_list; fprintf ff ")@]" let rec print_type ff = function | Tint -> fprintf ff "int" | Tfloat -> fprintf ff "float" | Tid(id) -> print_longname ff id | Tarray(ty, n) -> print_type ff ty; fprintf ff "^"; print_size_exp ff n let rec print_type ff = function | Tbase(ty) -> print_type ff ty | Tprod(ty_list) -> fprintf ff "@[("; print_list ff print_type " *" ty_list; fprintf ff ")@]" let rec print_ck ff = function | Cbase -> fprintf ff "base" | Con(ck, c, n) -> print_ck ff ck; fprintf ff " on "; print_longname ff c; fprintf ff "("; print_ident ff n; fprintf ff ")" | Cvar { contents = Cindex n } -> fprintf ff "base" | Cvar { contents = Clink ck } -> print_ck ff ck let rec print_clock ff = function | Ck(ck) -> print_ck ff ck | Cprod(ct_list) -> fprintf ff "@[("; print_list ff print_clock " *" ct_list; fprintf ff ")@]" let print_vd ff { v_name = n; v_type = ty; v_clock = ck } = fprintf ff "@["; print_ident ff n; fprintf ff ":"; print_type ff ty; fprintf ff " at "; print_ck ff ck; fprintf ff "@]" let rec print_c ff = function | Cint i -> fprintf ff "%d" i | Cfloat f -> fprintf ff "%f" f | Cconstr(tag) -> print_longname ff tag | Carray (n, c) -> print_c ff c; fprintf ff "^"; print_size_exp ff n let print_call_params ff = function | [] -> () | l -> fprintf ff "<<"; print_list ff print_size_exp "," l; fprintf ff ">>" let rec print_exps ff e_list = fprintf ff "@[(";print_list ff print_exp "," e_list; fprintf ff ")@]" and print_exp ff e = if !Misc.full_type_info then fprintf ff "("; begin match e.e_desc with | Evar x -> print_ident ff x | Econstvar x -> print_name ff x | Econst c -> print_c ff c | Efby(Some(c), e) -> print_c ff c; fprintf ff " fby "; print_exp ff e | Ereset_mem(y,v,res) -> fprintf ff "@[reset_mem "; print_ident ff y; fprintf ff " = "; print_c ff v; fprintf ff " every "; print_ident ff res; fprintf ff "@]" | Efby(None, e) -> fprintf ff "pre "; print_exp ff e | Eop((Name(m) | Modname { qual = "Pervasives"; id = m }), params, [e1;e2]) when is_infix m -> fprintf ff "(%a %s %a %a)" print_exp e1 m print_call_params params print_exp e2 | Eop(op, params, e_list) -> print_longname ff op; print_call_params ff params; print_exps ff e_list | Eapp({ a_op = f }, params, e_list) -> print_longname ff f; print_call_params ff params; print_exps ff e_list | Eevery({ a_op = f }, params, e_list, x) -> print_longname ff f; print_call_params ff params; print_exps ff e_list; fprintf ff " every "; print_ident ff x | Ewhen(e, c, n) -> fprintf ff "("; print_exp ff e; fprintf ff " when "; print_longname ff c; fprintf ff "("; print_ident ff n; fprintf ff ")"; fprintf ff ")" | Eifthenelse(e1, e2, e3) -> fprintf ff "@[if ";print_exp ff e1; fprintf ff "@ then "; print_exp ff e2; fprintf ff "@ else "; print_exp ff e3; fprintf ff "@]" | Emerge(x, tag_e_list) -> fprintf ff "@[merge ";print_ident ff x;fprintf ff "@ "; fprintf ff "@["; print_tag_e_list ff tag_e_list; fprintf ff "@]@]" | Etuple(e_list) -> fprintf ff "@[("; print_list ff print_exp "," e_list; fprintf ff ")@]" | Efield(e, field) -> print_exp ff e; fprintf ff "."; print_longname ff field | Estruct(f_e_list) -> fprintf ff "@[{"; print_list ff (fun ff (field, e) -> print_longname ff field;fprintf ff " = "; print_exp ff e) ";" f_e_list; fprintf ff "}@]" (*Array operators*) | Earray e_list -> fprintf ff "@[["; print_list ff print_exp ";" e_list; fprintf ff "]@]" | Erepeat (n,e) -> print_exp ff e; fprintf ff "^"; print_size_exp ff n | Eselect (idx,e) -> print_exp ff e; fprintf ff "["; print_list ff print_size_exp "][" idx; fprintf ff "]" | Eselect_dyn (idx, _, e1, e2) -> fprintf ff "@["; print_exp ff e1; fprintf ff "["; print_list ff print_exp "][" idx; fprintf ff "] default "; print_exp ff e2; fprintf ff "@]" | Eupdate (idx, e1, e2) -> fprintf ff "@["; print_exp ff e1; fprintf ff " with ["; print_list ff print_size_exp "][" idx; fprintf ff "] = "; print_exp ff e2; fprintf ff "@]" | Eselect_slice (idx1, idx2, e) -> print_exp ff e; fprintf ff "["; print_size_exp ff idx1; fprintf ff ".."; print_size_exp ff idx2; fprintf ff "]" | Econcat (e1, e2) -> print_exp ff e1; fprintf ff " @@ "; print_exp ff e2 | Eiterator (it, f, params, n, e_list, reset) -> fprintf ff "("; fprintf ff "%s" (iterator_to_string it); fprintf ff " "; (match params with | [] -> print_longname ff f | l -> fprintf ff "("; print_longname ff f; print_call_params ff params; fprintf ff ")" ); fprintf ff " <<"; print_size_exp ff n; fprintf ff ">>) (@["; print_list ff print_exp "," e_list; fprintf ff ")@]"; (match reset with | None -> () | Some r -> fprintf ff " every %s" (name r) ) | Efield_update (f, e1, e2) -> fprintf ff "@["; print_exp ff e1; fprintf ff " with ."; print_longname ff f; fprintf ff " = "; print_exp ff e2; fprintf ff "@]" end; if !Misc.full_type_info then begin fprintf ff " : %a)" print_type e.e_ty; if e.e_loc = no_location then fprintf ff " (no loc)" end and print_tag_e_list ff tag_e_list = print_list ff (fun ff (tag, e) -> fprintf ff "@[("; print_longname ff tag; fprintf ff " -> "; print_exp ff e; fprintf ff ")@]@,") "" tag_e_list let print_eq ff { eq_lhs = p; eq_rhs = e } = fprintf ff "@["; print_pat ff p; (* (\* DEBUG *\) *) (* fprintf ff " : "; *) (* print_ck ff e.e_ck; *) (* (\* END DEBUG *\) *) fprintf ff " =@ "; print_exp ff e; if !Misc.full_type_info then begin fprintf ff "@ at "; print_ck ff e.e_ck end; fprintf ff ";@]" let print_eqs ff l = fprintf ff "@["; print_list ff print_eq "" l; fprintf ff "@]" let print_open_module ff name = fprintf ff "@[open "; print_name ff name; fprintf ff "@.@]" let print_type_def ff { t_name = name; t_desc = tdesc } = match tdesc with | Type_abs -> fprintf ff "@[type %s@\n@]" name | Type_enum(tag_name_list) -> fprintf ff "@[type %s = " name; print_list ff print_name "|" tag_name_list; fprintf ff "@\n@]" | Type_struct(f_ty_list) -> fprintf ff "@[type %s = " name; fprintf ff "@[{"; print_list ff (fun ff (field, ty) -> print_name ff field; fprintf ff ": "; print_type ff ty) ";" f_ty_list; fprintf ff "}@]@\n@]" let print_contract ff {c_local = l; c_eq = eqs; c_assume = e_a; c_enforce = e_g; c_controllables = cl } = if l <> [] then begin fprintf ff "contract\n"; fprintf ff "@[var "; print_list ff print_vd ";" l; fprintf ff ";@]\n" end; if eqs <> [] then begin fprintf ff "@[let @,"; print_eqs ff eqs; fprintf ff "@]"; fprintf ff "tel\n" end; fprintf ff "assume@ %a@;enforce@ %a with (" print_exp e_a print_exp e_g; print_list ff print_vd ";" cl; fprintf ff ")" let print_node_params ff = function | [] -> () | l -> fprintf ff "<<"; print_list ff print_name "," l; fprintf ff ">>" let print_node ff { n_name = n;n_input = ni;n_output = no; n_contract = contract; n_local = nl; n_equs = ne; n_params = params; } = fprintf ff "@[node %s" n; print_node_params ff params; fprintf ff "(@["; print_list ff print_vd ";" ni; fprintf ff "@]) returns (@["; print_list ff print_vd ";" no; fprintf ff "@])@,"; optunit (print_contract ff) contract; if nl <> [] then begin fprintf ff "@[var "; print_list ff print_vd ";" nl; fprintf ff ";@]@," end; fprintf ff "@[let @,"; print_eqs ff ne; fprintf ff "@]@;"; fprintf ff "tel";fprintf ff "@.@]" let print_exp oc e = let ff = formatter_of_out_channel oc in print_exp ff e; fprintf ff "@." let print_type oc ty = let ff = formatter_of_out_channel oc in print_type ff ty; fprintf ff "@?" let print_clock oc ct = let ff = formatter_of_out_channel oc in print_clock ff ct; fprintf ff "@?" let print oc { p_opened = pm; p_types = pt; p_nodes = pn } = let ff = formatter_of_out_channel oc in List.iter (print_open_module ff) pm; List.iter (print_type_def ff) pt; List.iter (print_node ff) pn; fprintf ff "@?" end