heptagon/main/hept2mls.ml
2010-06-18 14:59:10 +02:00

431 lines
15 KiB
OCaml

(**************************************************************************)
(* *)
(* Heptagon *)
(* *)
(* Author : Marc Pouzet *)
(* Organization : Demons, LRI, University of Paris-Sud, Orsay *)
(* *)
(**************************************************************************)
(* removing switch statements and translation into Minils *)
open Location
open Misc
open Names
open Ident
open Static
open Types
open Format
open Printf
module HeptPrinter = Printer
open Minils
open Signature
module Error =
struct
type error =
| Ereset_not_var
| Eunsupported_language_construct
let message loc kind =
begin match kind with
| Ereset_not_var ->
eprintf "%aOnly variables can be used for resets.\n"
output_location loc
| Eunsupported_language_construct ->
eprintf "%aThis construct is not supported by MiniLS.\n"
output_location loc
end;
raise Misc.Error
end
module Env =
(* associate a clock level [base on C1(x1) on ... Cn(xn)] to every *)
(* local name [x] *)
(* then [x] is translated into [x when C1(x1) ... when Cn(xn)] *)
struct
type env =
| Eempty
| Ecomp of env * IdentSet.t
| Eon of env * longname * ident
let empty = Eempty
let push env tag c = Eon(env, tag, c)
let add l env =
Ecomp(env,
List.fold_left
(fun acc { Heptagon.v_name = n } -> IdentSet.add n acc) IdentSet.empty l)
(* sample e according to the clock [base on C1(x1) on ... on Cn(xn)] *)
let con env x e =
let rec conrec env =
match env with
| Eempty -> Format.printf "%s\n" (name x); assert false
| Eon(env, tag, name) ->
let e, ck = conrec env in
let ck_tag_name = Con(ck, tag, name) in
{ e with e_desc = Ewhen(e, tag, name); e_ck = ck_tag_name },
ck_tag_name
| Ecomp(env, l) ->
if IdentSet.mem x l then (e, Cbase) else conrec env in
let e, _ = conrec env in e
(* a constant [c] is translated into [c when C1(x1) on ... on Cn(xn)] *)
let const env e =
let rec constrec env =
match env with
| Eempty -> e, Cbase
| Eon(env, tag, name) ->
let e, ck = constrec env in
let ck_tag_name = Con(ck, tag, name) in
{ e with e_desc = Ewhen(e, tag, name); e_ck = ck_tag_name },
ck_tag_name
| Ecomp(env, l) -> constrec env in
let e, _ = constrec env in e
end
(* add an equation *)
let equation locals l_eqs e =
let n = Ident.fresh "ck" in
n,
(mk_var_dec n e.e_ty) :: locals,
(mk_equation (Evarpat n) e):: l_eqs
(* inserts the definition [x,e] into the set of shared equations *)
let rec add x e shared =
match shared with
| [] -> [x, e]
| (y, e_y) :: s ->
if x < y then (x, e) :: shared else (y, e_y) :: add x e s
let add_locals ni l_eqs s_eqs s_handlers =
let rec addrec l_eqs s_eqs s_handlers =
match s_handlers with
| [] -> l_eqs, s_eqs
| (x, e) :: s_handlers ->
if IdentSet.mem x ni then addrec l_eqs (add x e s_eqs) s_handlers
else
addrec ((mk_equation (Evarpat x) e) :: l_eqs)
s_eqs s_handlers in
addrec l_eqs s_eqs s_handlers
let translate_var { Heptagon.v_name = n; Heptagon.v_type = ty; } =
mk_var_dec n ty
let translate_locals locals l =
List.fold_left (fun locals v -> translate_var v :: locals) locals l
(*transforms [c1, [(x1, e11);...;(xn, e1n)];...;ck, [(x1,ek1);...;(xn,ekn)]] *)
(*into [x1=merge x (c1, e11)...(ck, ek1);...;xn=merge x (c1, e1n)...(ck,ekn)]*)
let switch x ci_eqs_list =
(* Defensive coherence check *)
let check ci_eqs_list =
let rec unique = function
[] -> true
| x :: h -> not (List.mem x h) && (unique h) in
let rec extract eqs_lists =
match eqs_lists with
| [] -> [],[]
| []::eqs_lists' ->
(* check length *)
assert (List.for_all (function [] -> true | _ -> false) eqs_lists');
[],[]
| ((x,e)::eqs)::eqs_lists' ->
let firsts,nexts = extract eqs_lists' in
(x,e)::firsts,eqs::nexts in
let rec check_eqs eqs_lists =
match eqs_lists with
| [] -> ()
| []::eqs_lists' ->
(* check length *)
assert (List.for_all (function [] -> true | _ -> false) eqs_lists')
| _ ->
let firsts,nexts = extract eqs_lists in
(* check all firsts defining same name *)
if (List.for_all (fun (x,e) -> x = (fst (List.hd firsts))) firsts)
then ()
else
begin
List.iter (fun (x,e) -> Printf.eprintf "|%s|, " (name x)) firsts;
assert false
end;
check_eqs nexts in
let ci,eqs = List.split ci_eqs_list in
(* constructors uniqueness *)
assert (unique ci);
check_eqs eqs in
let rec split ci_eqs_list =
match ci_eqs_list with
| [] | (_, []) :: _ -> [], []
| (ci, (y, e) :: shared_eq_list) :: ci_eqs_list ->
let ci_e_list, ci_eqs_list = split ci_eqs_list in
(ci, e) :: ci_e_list, (ci, shared_eq_list) :: ci_eqs_list in
let rec distribute ci_eqs_list =
match ci_eqs_list with
| [] | (_, []) :: _ -> []
| (ci, (y, { e_ty = ty; e_loc = loc }) :: _) :: _ ->
let ci_e_list, ci_eqs_list = split ci_eqs_list in
(y, mk_exp ~exp_ty:ty (Emerge(x, ci_e_list))) ::
distribute ci_eqs_list in
check ci_eqs_list;
distribute ci_eqs_list
let rec const = function
| Heptagon.Cint i -> Cint i
| Heptagon.Cfloat f -> Cfloat f
| Heptagon.Cconstr t -> Cconstr t
| Heptagon.Carray(n, c) -> Carray(n, const c)
let translate_op_kind = function
| Heptagon.Eop -> Eop
| Heptagon.Enode -> Enode
let translate_op_desc { Heptagon.op_name = n; Heptagon.op_params = p;
Heptagon.op_kind = k } =
{ op_name = n; op_params = p;
op_kind = translate_op_kind k }
let translate_reset = function
| Some { Heptagon.e_desc = Heptagon.Evar n } -> Some n
| Some re -> Error.message re.Heptagon.e_loc Error.Ereset_not_var
| None -> None
let translate_iterator_type = function
| Heptagon.Imap -> Imap
| Heptagon.Ifold -> Ifold
| Heptagon.Imapfold -> Imapfold
let rec application env { Heptagon.a_op = op; } e_list =
match op, e_list with
| Heptagon.Epre(None), [e] -> Efby(None, e)
| Heptagon.Epre(Some(c)), [e] -> Efby(Some(const c), e)
| Heptagon.Efby, [{ e_desc = Econst(c) } ; e] -> Efby(Some(c), e)
| Heptagon.Eifthenelse, [e1;e2;e3] -> Eifthenelse(e1, e2, e3)
| Heptagon.Ecall(op_desc, r), e_list ->
Ecall(translate_op_desc op_desc, e_list, translate_reset r)
| Heptagon.Efield_update f, [e1;e2] -> Efield_update(f, e1, e2)
| Heptagon.Earray_op op, e_list ->
Earray_op (translate_array_op env op e_list)
and translate_array_op env op e_list =
match op, e_list with
| Heptagon.Erepeat, [e; idx] ->
Erepeat (size_exp_of_exp idx, e)
| Heptagon.Eselect idx_list, [e] ->
Eselect (idx_list, e)
(*Little hack: we need the to access the type of the array being accessed to
store the bounds (which will be used at code generation time, where the types
are harder to find). *)
| Heptagon.Eselect_dyn, e::defe::idx_list ->
let bounds = bounds_list e.e_ty in
Eselect_dyn (idx_list, bounds, e, defe)
| Heptagon.Eupdate idx_list, [e1;e2] ->
Eupdate (idx_list, e1, e2)
| Heptagon.Eselect_slice, [e; idx1; idx2] ->
Eselect_slice (size_exp_of_exp idx1, size_exp_of_exp idx2, e)
| Heptagon.Econcat, [e1; e2] ->
Econcat (e1, e2)
| Heptagon.Eiterator(it, op_desc, reset), idx::e_list ->
Eiterator(translate_iterator_type it,
translate_op_desc op_desc,
size_exp_of_exp idx, e_list,
translate_reset reset)
let rec translate env
{ Heptagon.e_desc = desc; Heptagon.e_ty = ty;
Heptagon.e_loc = loc } =
match desc with
| Heptagon.Econst(c) ->
Env.const env (mk_exp ~loc:loc ~exp_ty:ty (Econst (const c)))
| Heptagon.Evar x ->
Env.con env x (mk_exp ~loc:loc ~exp_ty:ty (Evar x))
| Heptagon.Econstvar(x) ->
Env.const env (mk_exp ~loc:loc ~exp_ty:ty (Econstvar x))
| Heptagon.Etuple(e_list) ->
mk_exp ~loc:loc ~exp_ty:ty (Etuple (List.map (translate env) e_list))
| Heptagon.Eapp(app, e_list) ->
mk_exp ~loc:loc ~exp_ty:ty (application env app
(List.map (translate env) e_list))
| Heptagon.Efield(e, field) ->
mk_exp ~loc:loc ~exp_ty:ty (Efield (translate env e, field))
| Heptagon.Estruct f_e_list ->
let f_e_list = List.map
(fun (f, e) -> (f, translate env e)) f_e_list in
mk_exp ~loc:loc ~exp_ty:ty (Estruct f_e_list)
| Heptagon.Earray(e_list) ->
mk_exp ~loc:loc ~exp_ty:ty (Earray (List.map (translate env) e_list))
| Heptagon.Elast _ -> Error.message loc Error.Eunsupported_language_construct
let rec translate_pat = function
| Heptagon.Evarpat(n) -> Evarpat n
| Heptagon.Etuplepat(l) -> Etuplepat (List.map translate_pat l)
let rec rename_pat ni locals s_eqs = function
| Heptagon.Evarpat(n), ty ->
if IdentSet.mem n ni then (
let n_copy = Ident.fresh (sourcename n) in
Evarpat n_copy,
(mk_var_dec n_copy ty) :: locals,
add n (mk_exp ~exp_ty:ty (Evar n_copy)) s_eqs
) else
Evarpat n, locals, s_eqs
| Heptagon.Etuplepat(l), Tprod l_ty ->
let l, locals, s_eqs =
List.fold_right2
(fun pat ty (p_list, locals, s_eqs) ->
let pat, locals, s_eqs = rename_pat ni locals s_eqs (pat,ty) in
pat :: p_list, locals, s_eqs) l l_ty
([], locals, s_eqs) in
Etuplepat(l), locals, s_eqs
| _ -> assert false
let all_locals ni p =
IdentSet.is_empty (IdentSet.inter (Heptagon.vars_pat p) ni)
let rec translate_eq env ni (locals, l_eqs, s_eqs)
{ Heptagon.eq_desc = desc; Heptagon.eq_loc = loc } =
match desc with
| Heptagon.Eswitch(e, switch_handlers) ->
translate_switch_handlers env ni (locals,l_eqs,s_eqs) e switch_handlers
| Heptagon.Eeq(Heptagon.Evarpat n, e) when IdentSet.mem n ni ->
locals,
l_eqs,
add n (translate env e) s_eqs
| Heptagon.Eeq(p, e) when all_locals ni p ->
(* all vars from [p] are local *)
locals,
(mk_equation ~loc:loc (translate_pat p) (translate env e)) :: l_eqs,
s_eqs
| Heptagon.Eeq(p, e) (* some are local *) ->
(* transforms [p = e] into [p' = e; p = p'] *)
let p', locals, s_eqs =
rename_pat ni locals s_eqs (p, e.Heptagon.e_ty) in
locals,
(mk_equation ~loc:loc p' (translate env e)) :: l_eqs,
s_eqs
| Heptagon.Epresent _ | Heptagon.Eautomaton _ | Heptagon.Ereset _ ->
Error.message loc Error.Eunsupported_language_construct
and translate_eqs env ni (locals, local_eqs, shared_eqs) eq_list =
List.fold_left
(fun (locals, local_eqs, shared_eqs) eq ->
translate_eq env ni (locals, local_eqs, shared_eqs) eq)
(locals, local_eqs, shared_eqs) eq_list
and translate_block env ni (locals, l_eqs)
{ Heptagon.b_local = l; Heptagon.b_equs = eq_list} =
let env = Env.add l env in
let locals = translate_locals locals l in
let locals, local_eqs, shared_eqs =
translate_eqs env ni (locals, l_eqs, []) eq_list in
locals, local_eqs, shared_eqs
and translate_switch_handlers env ni (locals, l_eqs, s_eqs) e handlers =
let rec transrec x ni_handlers (locals, l_eqs, ci_s_eqs_list) handlers =
match handlers with
[] -> locals, l_eqs, ci_s_eqs_list
| { Heptagon.w_name = ci; Heptagon.w_block = b } :: handlers ->
let locals, l_eqs, s_eqs =
translate_block (Env.push env ci x) ni_handlers (locals, l_eqs) b in
transrec x ni_handlers (locals, l_eqs, (ci, s_eqs) :: ci_s_eqs_list)
handlers in
let def = function
[] -> IdentSet.empty
| { Heptagon.w_block = { Heptagon.b_defnames = env } } :: _ ->
(* Create set from env *)
(Ident.Env.fold (fun name _ set -> IdentSet.add name set) env IdentSet.empty) in
let ni_handlers = def handlers in
let x, locals, l_eqs = equation locals l_eqs (translate env e) in
let locals, l_eqs, ci_s_eqs_list =
transrec x ni_handlers (locals, l_eqs, []) handlers in
let s_handlers = switch x ci_s_eqs_list in
let l_eqs, s_eqs = add_locals ni l_eqs s_eqs s_handlers in
locals, l_eqs, s_eqs
let translate_contract env contract =
match contract with
| None -> None, env
| Some { Heptagon.c_local = v;
Heptagon.c_eq = eq_list;
Heptagon.c_assume = e_a;
Heptagon.c_enforce = e_g;
Heptagon.c_controllables = cl } ->
let env = Env.add cl env in
let env' = Env.add v env in
let locals = translate_locals [] v in
let locals, l_eqs, s_eqs =
translate_eqs env' IdentSet.empty (locals, [], []) eq_list in
let l_eqs, _ = add_locals IdentSet.empty l_eqs [] s_eqs in
let e_a = translate env' e_a in
let e_g = translate env' e_g in
Some { c_local = locals;
c_eq = l_eqs;
c_assume = e_a;
c_enforce = e_g;
c_controllables = List.map translate_var cl },
env
let node
{ Heptagon.n_name = n; Heptagon.n_input = i; Heptagon.n_output = o;
Heptagon.n_contract = contract;
Heptagon.n_local = l; Heptagon.n_equs = eq_list;
Heptagon.n_loc = loc;
Heptagon.n_params = params;
Heptagon.n_params_constraints = params_constr } =
let env = Env.add o (Env.add i Env.empty) in
let contract, env = translate_contract env contract in
let env = Env.add l env in
let locals = translate_locals [] l in
let locals, l_eqs, s_eqs =
translate_eqs env IdentSet.empty (locals, [], []) eq_list in
let l_eqs, _ = add_locals IdentSet.empty l_eqs [] s_eqs in
{ n_name = n;
n_input = List.map translate_var i;
n_output = List.map translate_var o;
n_contract = contract;
n_local = locals;
n_equs = l_eqs;
n_loc = loc ;
n_params = params;
n_params_constraints = params_constr;
n_params_instances = []; }
let typedec
{Heptagon.t_name = n; Heptagon.t_desc = tdesc; Heptagon.t_loc = loc} =
let onetype = function
| Heptagon.Type_abs -> Type_abs
| Heptagon.Type_enum tag_list -> Type_enum tag_list
| Heptagon.Type_struct field_ty_list ->
Type_struct field_ty_list
in
{ t_name = n; t_desc = onetype tdesc; t_loc = loc }
let const_dec cd =
{ c_name = cd.Heptagon.c_name;
c_value = cd.Heptagon.c_value;
c_loc = cd.Heptagon.c_loc; }
let program
{ Heptagon.p_pragmas = pragmas;
Heptagon.p_opened = modules;
Heptagon.p_types = pt_list;
Heptagon.p_nodes = n_list;
Heptagon.p_consts = c_list; } =
{ p_pragmas = pragmas;
p_opened = modules;
p_types = List.map typedec pt_list;
p_nodes = List.map node n_list;
p_consts = List.map const_dec c_list}