https://github.com/EasyCrypt/easycrypt
Revision 6df81b68bb7fb2010d10043e5c11e4401cf56d37 authored by Benjamin Gregoire on 01 April 2014, 07:58:40 UTC, committed by Benjamin Gregoire on 01 April 2014, 07:58:40 UTC
1 parent e43821c
Tip revision: 6df81b68bb7fb2010d10043e5c11e4401cf56d37 authored by Benjamin Gregoire on 01 April 2014, 07:58:40 UTC
add product of two and 3 sets
add product of two and 3 sets
Tip revision: 6df81b6
ecWhy3.ml
(* ----------------------------------------------------------------------*)
open EcMaps
open Why3
open EcUtils
open EcSymbols
open EcIdent
open EcPath
open EcTypes
open EcBaseLogic
open EcDecl
open EcFol
open EcModules
open EcTheory
module Mp = EcPath.Mp
module Mm = EcPath.Mm
module Mx = EcPath.Mx
module Msym = EcSymbols.Msym
exception CannotTranslate of string
(* ----------------------------------------------------------------------*)
module Talpha = struct
type t = Term.vsymbol list * Term.term
type talphaenv = {
tae_map : int Term.Mvs.t;
tae_ctn : int ref;
}
let tae_create () =
{ tae_map = Term.Mvs.empty; tae_ctn = ref 0; }
let vs_rename_alpha tae vs =
{ tae with tae_map = Term.Mvs.add vs (postincr tae.tae_ctn) tae.tae_map; }
let vl_rename_alpha tae vl =
List.fold_left vs_rename_alpha tae vl
let rec pat_rename_alpha m p =
match p.Term.pat_node with
| Term.Pvar v -> vs_rename_alpha m v
| Term.Pas (p, v) -> pat_rename_alpha (vs_rename_alpha m v) p
| Term.Por (p, _) -> pat_rename_alpha m p
| _ -> Term.pat_fold pat_rename_alpha m p
let w3_ty_compare t1 t2 = Ty.ty_hash t1 - Ty.ty_hash t2
let w3_ls_compare l1 l2 = Term.ls_hash l1 - Term.ls_hash l2
let rec pat_compare_alpha m1 m2 p1 p2 =
if Term.pat_equal p1 p2 then 0 else
let ct = w3_ty_compare p1.Term.pat_ty p2.Term.pat_ty in
if ct <> 0 then ct else
match p1.Term.pat_node, p2.Term.pat_node with
| Term.Pwild, Term.Pwild -> 0
| Term.Pvar v1, Term.Pvar v2 -> begin
match Term.Mvs.find_opt v1 m1.tae_map,
Term.Mvs.find_opt v2 m2.tae_map
with
| Some _ , None -> 1
| None , Some _ -> -1
| None , None -> Term.vs_hash v1 - Term.vs_hash v2
| Some i1, Some i2 -> i1 - i2
end
| Term.Papp (f1, l1), Term.Papp (f2, l2) ->
compare2
(lazy (w3_ls_compare f1 f2))
(lazy (List.compare (pat_compare_alpha m1 m2) l1 l2))
| Term.Pas (p1, _), Term.Pas (p2, _) ->
pat_compare_alpha m1 m2 p1 p2
| Term.Por (p1, q1), Term.Por (p2, q2) ->
compare2
(lazy (pat_compare_alpha m1 m2 p1 p2))
(lazy (pat_compare_alpha m1 m2 q1 q2))
| _ -> compare_tag p1.Term.pat_node p2.Term.pat_node
let rec t_compare_alpha m1 m2 t1 t2 =
if Term.t_equal t1 t2 then 0 else
match ocompare w3_ty_compare t1.Term.t_ty t2.Term.t_ty with
| ct when ct <> 0 -> ct
| _ -> begin
match t1.Term.t_node, t2.Term.t_node with
| Term.Tvar v1, Term.Tvar v2 -> begin
match Term.Mvs.find_opt v1 m1.tae_map,
Term.Mvs.find_opt v2 m2.tae_map
with
| Some _ , None -> 1
| None , Some _ -> -1
| None , None -> Term.vs_hash v1 - Term.vs_hash v2
| Some i1, Some i2 -> i1 - i2
end
| Term.Tconst c1, Term.Tconst c2 ->
Pervasives.compare c1 c2
| Term.Tapp (f1, l1), Term.Tapp (f2, l2) ->
compare2
(lazy (w3_ls_compare f1 f2))
(lazy (List.compare (t_compare_alpha m1 m2) l1 l2))
| Term.Tif (f1, t1, e1), Term.Tif (f2, t2, e2) ->
compare3
(lazy (t_compare_alpha m1 m2 f1 f2))
(lazy (t_compare_alpha m1 m2 t1 t2))
(lazy (t_compare_alpha m1 m2 e1 e2))
| Term.Tlet (t1, b1), Term.Tlet (t2, b2) -> begin
match t_compare_alpha m1 m2 t1 t2 with
| ct when ct <> 0 -> ct
| _ ->
let u1,e1 = Term.t_open_bound b1 in
let u2,e2 = Term.t_open_bound b2 in
let m1 = vs_rename_alpha m1 u1 in
let m2 = vs_rename_alpha m2 u2 in
t_compare_alpha m1 m2 e1 e2
end
| Term.Tcase (t1, bl1), Term.Tcase (t2, bl2) -> begin
match t_compare_alpha m1 m2 t1 t2 with
| ct when ct <> 0 -> ct
| _ ->
let br_compare b1 b2 =
let p1,e1 = Term.t_open_branch b1 in
let p2,e2 = Term.t_open_branch b2 in
match pat_compare_alpha m1 m2 p1 p2 with
| ct when ct <> 0 -> ct
| _ ->
let m1 = pat_rename_alpha m1 p1 in
let m2 = pat_rename_alpha m2 p2 in
t_compare_alpha m1 m2 e1 e2
in
List.compare br_compare bl1 bl2
end
| Term.Teps b1, Term.Teps b2 ->
let u1,e1 = Term.t_open_bound b1 in
let u2,e2 = Term.t_open_bound b2 in
let m1 = vs_rename_alpha m1 u1 in
let m2 = vs_rename_alpha m2 u2 in
t_compare_alpha m1 m2 e1 e2
| Term.Tquant (q1, b1), Term.Tquant (q2, b2) ->
let compare_body b1 b2 =
let cv v1 v2 = w3_ty_compare v1.Term.vs_ty v2.Term.vs_ty in
let vl1,_,e1 = Term.t_open_quant b1 in
let vl2,_,e2 = Term.t_open_quant b2 in
compare2
(lazy (List.compare cv vl1 vl2))
(lazy (let m1 = vl_rename_alpha m1 vl1 in
let m2 = vl_rename_alpha m2 vl2 in
t_compare_alpha m1 m2 e1 e2))
in
compare2
(lazy (Pervasives.compare q1 q2))
(lazy (compare_body b1 b2))
| Term.Tbinop (o1, f1, g1), Term.Tbinop (o2, f2, g2) ->
compare3
(lazy (Pervasives.compare o1 o2))
(lazy (t_compare_alpha m1 m2 f1 f2))
(lazy (t_compare_alpha m1 m2 g1 g2))
| Term.Tnot f1, Term.Tnot f2 ->
t_compare_alpha m1 m2 f1 f2
| _ -> compare_tag t1.Term.t_node t2.Term.t_node
end
let compare (vl1,e1) (vl2,e2) =
let m1 = tae_create () in
let m2 = tae_create () in
let cv v1 v2 = w3_ty_compare v1.Term.vs_ty v2.Term.vs_ty in
compare2
(lazy (List.compare cv vl1 vl2))
(lazy (let m1 = vl_rename_alpha m1 vl1 in
let m2 = vl_rename_alpha m2 vl2 in
t_compare_alpha m1 m2 e1 e2))
end
module Mta = EcMaps.Map.Make(Talpha)
(* ----------------------------------------------------------------------*)
type env = {
logic_task : Task.task;
env_ty : ty_body Mp.t;
env_op : (Term.lsymbol * Term.lsymbol * Ty.tvsymbol list) Mp.t;
env_proj : Term.lsymbol Mint.t Mint.t;
env_ax : Decl.prsymbol Mp.t;
env_mp : Term.lsymbol Mm.t;
env_xpv : Term.lsymbol Mx.t;
env_xpf : Term.lsymbol Mx.t;
env_tv : Ty.ty Mid.t;
env_id : Term.term Mid.t;
env_w3 : (EcPath.path * Ty.tvsymbol list) Ident.Mid.t;
env_lam : Term.term Mta.t;
env_rax : EcPath.path Decl.Mpr.t;
}
and ty_body =
Ty.tysymbol *
[ `Plain
| `Datatype of (symbol * Term.lsymbol) list
| `Record of (symbol * Term.lsymbol)
* (symbol * Term.lsymbol * Ty.ty) list ]
let ty_body_equal ((ty1, xi1) : ty_body) ((ty2, xi2) : ty_body) =
let c_equal (c1, l1) (c2, l2) =
EcSymbols.equal c1 c2 && Term.ls_equal l1 l2
and r_equal (c1, l1, ty1) (c2, l2, ty2) =
EcSymbols.equal c1 c2
&& Term.ls_equal l1 l2
&& Ty.ty_equal ty1 ty2
in
(Ty.ts_equal ty1 ty2)
&& match xi1, xi2 with
| `Plain , `Plain ->
true
| `Datatype ls1, `Datatype ls2 ->
List.all2 c_equal ls1 ls2
| `Record ((c1, l1), fs1), `Record ((c2, l2), fs2) ->
EcSymbols.equal c1 c2
&& Term.ls_equal l1 l2
&& List.all2 r_equal fs1 fs2
| _, _ -> false
let w3_ls_true = Term.fs_bool_true
let w3_ls_false = Term.fs_bool_false
let w3_ls_not, decl_not, spec_not =
let ls =
Term.create_fsymbol (Ident.id_fresh "Not") []
(Ty.ty_func Ty.ty_bool Ty.ty_bool) in
let decl = Decl.create_param_decl ls in
let preid = Ident.id_fresh "b" in
let id = Term.create_vsymbol preid Ty.ty_bool in
let b = Term.t_var id in
let f_app = Term.t_func_app (Term.t_app_infer ls []) b in
let form =
Term.t_forall_close [id] []
(Term.t_iff (Term.t_equ f_app Term.t_bool_true)
(Term.t_not (Term.t_equ b Term.t_bool_true))) in
let pr = Decl.create_prsymbol (Ident.id_fresh "Not_spec") in
let decl_spec = Decl.create_prop_decl Decl.Paxiom pr form in
ls, decl, decl_spec
let mk_w3_opp2 s mk =
let ls =
Term.create_fsymbol (Ident.id_fresh s) []
(Ty.ty_func Ty.ty_bool (Ty.ty_func Ty.ty_bool Ty.ty_bool)) in
let decl = Decl.create_param_decl ls in
let preid = Ident.id_fresh "b" in
let id1 = Term.create_vsymbol preid Ty.ty_bool in
let id2 = Term.create_vsymbol preid Ty.ty_bool in
let b1 = Term.t_var id1 in
let b2 = Term.t_var id2 in
let f_app =
Term.t_func_app (Term.t_func_app (Term.t_app_infer ls []) b1) b2 in
let form =
Term.t_forall_close [id1;id2] []
(Term.t_iff (Term.t_equ f_app Term.t_bool_true)
(mk (Term.t_equ b1 Term.t_bool_true)
(Term.t_equ b2 Term.t_bool_true))) in
let pr = Decl.create_prsymbol (Ident.id_fresh (s^"_spec")) in
let decl_spec = Decl.create_prop_decl Decl.Paxiom pr form in
ls, decl, decl_spec
let w3_ls_and, decl_and, spec_and = mk_w3_opp2 "ANDS" Term.t_and
let w3_ls_anda, decl_anda, spec_anda = mk_w3_opp2 "ANDA" Term.t_and_asym
let w3_ls_or, decl_or, spec_or = mk_w3_opp2 "ORS" Term.t_or
let w3_ls_ora, decl_ora, spec_ora = mk_w3_opp2 "ORA" Term.t_or_asym
let w3_ls_imp, decl_imp, spec_imp = mk_w3_opp2 "IMP" Term.t_implies
let w3_ls_iff, decl_iff, spec_iff = mk_w3_opp2 "IFF" Term.t_iff
let w3_ls_eq, decl_eq, spec_eq =
let a = Ty.create_tvsymbol (Ident.id_fresh "'a") in
let ta = Ty.ty_var a in
let ty = (Ty.ty_func ta (Ty.ty_func ta Ty.ty_bool)) in
let ls = Term.create_fsymbol (Ident.id_fresh "EQ") [] ty in
let decl = Decl.create_param_decl ls in
let preid = Ident.id_fresh "x" in
let id1 = Term.create_vsymbol preid ta in
let id2 = Term.create_vsymbol preid ta in
let b1 = Term.t_var id1 in
let b2 = Term.t_var id2 in
let f_app =
Term.t_func_app (Term.t_func_app (Term.fs_app ls [] ty) b1) b2 in
let form =
Term.t_forall_close [id1;id2] []
(Term.t_iff (Term.t_equ f_app Term.t_bool_true)
(Term.t_equ b1 b2)) in
let pr = Decl.create_prsymbol (Ident.id_fresh ("EQ_spec")) in
let decl_spec = Decl.create_prop_decl Decl.Paxiom pr form in
ls, decl, decl_spec
let ts_distr, fs_mu, distr_theory =
let th = Theory.create_theory (Ident.id_fresh "Distr") in
let th = Theory.use_export th Theory.bool_theory in
let th = Theory.use_export th Theory.highord_theory in
let vta = Ty.create_tvsymbol (Ident.id_fresh "ta") in
let ta = Ty.ty_var vta in
let tdistr = Ty.create_tysymbol (Ident.id_fresh "distr") [vta] None in
let th = Theory.add_ty_decl th tdistr in
let mu =
Term.create_fsymbol (Ident.id_fresh "mu")
[Ty.ty_app tdistr [ta]; Ty.ty_func ta Ty.ty_bool]
Ty.ty_real in
let th = Theory.add_param_decl th mu in
tdistr, mu, Theory.close_theory th
let ty_distr t = Ty.ty_app ts_distr [t]
(* Special type for translation of glob, hoare, equiv and pr *)
(*
type memory
(* type name *)
type mod
type 't var
type ('ta, 'tr) fun
op app_mod : mod -> mod -> mod
op get_var : 't var -> memory -> 't
op sem : ('ta,'tr) fun -> memory -> 'ta -> memory distr
translation of module :
+ abstract module M :
we declare a type "tglob_M" which is the type of the global memory of the module
we declare a logical symbol of type "tglob var", it is used of the translation of Fglob m
we declare a logical symbol M : mod.
for each function in the signature we declare a logical symbol of type
mod -> ... -> mod -> (ta,tr) fun
where the number of mod correspond to the module parameter
ta is the tuple type of arguments and tr is the result type
+ alias : nothing is done, alias are inlined
+ structure :
we declare a logical symbol M : mod.
for each variable a symbol of type var t
foreach submodule N a symbol M.N of type mod -> mod -> mod -> mod
where the number of mod correspond to the module parameter
foreach function a symbol as for abstract module
translation of local variable
xpath -> var t
*)
let ts_mem = Ty.create_tysymbol (Ident.id_fresh "memory") [] None
let ty_mem = Ty.ty_app ts_mem []
let ts_mod = Ty.create_tysymbol (Ident.id_fresh "module") [] None
let ty_mod = Ty.ty_app ts_mod []
let ts_var =
let t = Ty.create_tvsymbol (Ident.id_fresh "t") in
Ty.create_tysymbol (Ident.id_fresh "var") [t] None
let ty_var t = Ty.ty_app ts_var [t]
let ts_fun =
let ta = Ty.create_tvsymbol (Ident.id_fresh "ta")
(* and tr = Ty.create_tvsymbol (Ident.id_fresh "tr") *) in
Ty.create_tysymbol (Ident.id_fresh "fun") [ta(*;tr*)] None
let ty_fun ta (* tr *) = Ty.ty_app ts_fun [ta (*; tr *)]
let fs_app_mod =
Term.create_fsymbol (Ident.id_fresh "app_mod") [ty_mod;ty_mod] ty_mod
let app_mod f m =
Term.fs_app fs_app_mod [f;m] ty_mod
let fs_get_var =
let t = Ty.ty_var (Ty.create_tvsymbol (Ident.id_fresh "t")) in
Term.create_fsymbol (Ident.id_fresh "get_var") [ty_var t;ty_mem] t
let get_var v m =
Term.t_app_infer fs_get_var [v;m]
let fs_sem =
let ta = Ty.ty_var (Ty.create_tvsymbol (Ident.id_fresh "ta"))
(* and tr = Ty.ty_var (Ty.create_tvsymbol (Ident.id_fresh "tr")) *) in
let tf = Ty.ty_app ts_fun [ta (*; tr *)] in
Term.create_fsymbol (Ident.id_fresh "sem") [tf;ty_mem;ta] (ty_distr ty_mem)
let getpr f mem args ev =
let sem = Term.t_app_infer fs_sem [f;mem;args] in
Term.t_app_infer fs_mu [sem;ev]
let add_decl_with_tuples task d =
let ids = Ident.Mid.set_diff d.Decl.d_syms (Task.task_known task) in
let add id s = match Ty.is_ts_tuple_id id with
| Some n -> Stdlib.Sint.add n s
| None -> s in
let ixs = Ident.Sid.fold add ids Stdlib.Sint.empty in
let add n task = Task.use_export task (Theory.tuple_theory n) in
Task.add_decl (Stdlib.Sint.fold add ixs task) d
let initial_task =
let task =
List.fold_left Task.use_export None
[Theory.builtin_theory;Theory.bool_theory;Theory.highord_theory;
distr_theory] in
let task =
List.fold_left Task.add_decl task
[decl_not; spec_not;
decl_and; spec_and; decl_anda; spec_anda;
decl_or; spec_or; decl_ora; spec_ora;
decl_imp; spec_imp; decl_iff; spec_iff;
decl_eq; spec_eq ] in
let ts = [ts_mem; ts_mod; ts_var; ts_fun] in
let add_ty_decl task ts =
add_decl_with_tuples task (Decl.create_ty_decl ts) in
let fs = [fs_app_mod; fs_get_var;fs_sem] in
let add_param_decl task fs =
add_decl_with_tuples task (Decl.create_param_decl fs) in
let task = List.fold_left add_ty_decl task ts in
List.fold_left add_param_decl task fs
let empty = {
logic_task = initial_task;
env_ty = Mp.empty;
env_op = Mp.empty;
env_proj = Mint.empty;
env_ax = Mp.empty;
env_mp = Mm.empty;
env_xpv = Mx.empty;
env_xpf = Mx.empty;
env_tv = Mid.empty;
env_id = Mid.empty;
env_w3 = Ident.Mid.empty;
env_lam = Mta.empty;
env_rax = Decl.Mpr.empty; }
(* ---------------------------------------------------------------------- *)
type rebinding_w3 = {
rb_th : Theory.theory;
rb_decl : Decl.decl list;
rb_ty : ty_body Mp.t;
rb_op : (Term.lsymbol * Term.lsymbol * Ty.tvsymbol list) Mp.t;
rb_ax : Decl.prsymbol Mp.t;
rb_w3 : (EcPath.path * Ty.tvsymbol list) Ident.Mid.t;
}
let rb_empty th = {
rb_th = th;
rb_decl = [];
rb_ty = Mp.empty;
rb_op = Mp.empty;
rb_ax = Mp.empty;
rb_w3 = Ident.Mid.empty;
}
type highorder_decl = (Term.lsymbol * Decl.decl * Decl.decl) option
type rebinding_item =
| RBuse of rebinding_w3
| RBty of EcPath.path * rbty_body * Decl.decl
| RBop of EcPath.path * (Term.lsymbol * Ty.tvsymbol list) * Decl.decl * highorder_decl
| RBax of EcPath.path * Decl.prsymbol * Decl.decl
| RBmp of EcPath.mpath * Term.lsymbol
| RBxpf of EcPath.xpath * Term.lsymbol
| RBxpv of EcPath.xpath * Term.lsymbol
| RBfun of Decl.decl * Decl.decl * Talpha.t * Term.term
| RBproj of int * int * Term.lsymbol * Decl.decl
and rbty_body =
Ty.tysymbol *
[ `Plain
| `Datatype of (symbol * Term.lsymbol * highorder_decl) list
| `Record of (symbol * Term.lsymbol * highorder_decl)
* (symbol * Term.lsymbol * highorder_decl * Ty.ty) list ]
type rebinding = rebinding_item list
(* -------------------------------------------------------------------- *)
let ty_of_rbty ((ty, body) : rbty_body) : ty_body=
let body =
match body with
| `Plain ->
`Plain
| `Datatype cs ->
`Datatype (List.map (fun (c, ls, _) -> (c, ls)) cs)
| `Record ((c, cls, _), fields) ->
let fields = List.map (fun (f, ls, _, fty) -> (f, ls, fty)) fields in
`Record ((c, cls), fields)
in
(ty, body)
(* -------------------------------------------------------------------- *)
let merge check k o1 o2 =
match o1, o2 with
| Some e1, Some e2 -> check k e1 e2; o1
| _, None -> o1
| None, _ -> o2
exception MergeW3Ty of EcPath.path * ty_body * ty_body
exception MergeW3Op of EcPath.path * Term.lsymbol * Term.lsymbol
exception MergeW3Ax of EcPath.path * Decl.prsymbol * Decl.prsymbol
exception MergeW3Id of Ident.ident * EcPath.path * EcPath.path
let merge_ty =
let check p t1 t2 =
if not (ty_body_equal t1 t2) then raise (MergeW3Ty(p,t1,t2)) in
Mp.merge (merge check)
let merge_op =
let check p (t1,_,_) (t2,_,_) =
if not (Term.ls_equal t1 t2) then raise (MergeW3Op(p,t1,t2)) in
Mp.merge (merge check)
let merge_ax =
let check p t1 t2 =
if not (Decl.pr_equal t1 t2) then raise (MergeW3Ax(p,t1,t2)) in
Mp.merge (merge check)
let merge_id =
let check p (t1,_) (t2,_) =
if not (EcPath.p_equal t1 t2) then raise (MergeW3Id(p,t1,t2)) in
Ident.Mid.merge (merge check)
let mk_highorder_func ls =
let targs = ls.Term.ls_args in
let tres = ls.Term.ls_value in
if targs = [] then None
else
let pid = Ident.id_fresh (ls.Term.ls_name.Ident.id_string ^ "_ho") in
let codom = (odfl Ty.ty_bool tres) in
let ty = List.fold_right Ty.ty_func ls.Term.ls_args codom in
let ls' = Term.create_fsymbol pid [] ty in
let decl' = Decl.create_param_decl ls' in
let pid_spec = Ident.id_fresh (ls.Term.ls_name.Ident.id_string ^ "_ho_spec") in
let pr = Decl.create_prsymbol pid_spec in
let preid = Ident.id_fresh "x" in
let params = List.map (Term.create_vsymbol preid) targs in
let args = List.map Term.t_var params in
let f_app' =
List.fold_left Term.t_func_app (Term.fs_app ls' [] ty) args in
let f_app = Term.t_app ls args tres in
let spec =
match tres with
| None -> Term.t_iff (Term.t_equ f_app' Term.t_bool_true) f_app
| Some _ -> Term.t_equ f_app' f_app in
let spec = Term.t_forall_close params [] spec in
let decl_s = Decl.create_prop_decl Decl.Paxiom pr spec in
Some(ls',decl',decl_s)
let add_ts env path rbts decl =
let ts = ty_of_rbty rbts in
if Mp.mem path env.env_ty then begin
assert (ty_body_equal ts (Mp.find path env.env_ty));
env
end else begin
let add_extra_op env c ls odecl =
let tvs = (fst ts).Ty.ts_args in
let cpath = EcPath.pqoname (EcPath.prefix path) c in
match odecl with
| None ->
{ env with env_op = Mp.add cpath (ls, ls, tvs) env.env_op }
| Some (ls', dcl1, dcl2) ->
List.fold_left
(fun env dcl ->
{ env with logic_task = add_decl_with_tuples env.logic_task dcl })
{ env with env_op = Mp.add cpath (ls, ls', tvs) env.env_op }
[dcl1; dcl2]
in
let env =
{ env with
env_ty = Mp.add path ts env.env_ty;
logic_task = add_decl_with_tuples env.logic_task decl; }
in
match snd rbts with
| `Plain -> env
| `Datatype ls -> begin
let for1 env (c, ls, odecl) = add_extra_op env c ls odecl in
List.fold_left for1 env ls
end
| `Record (ctor, fields) -> begin
let for1 env (f, ls, odecl, _) = add_extra_op env f ls odecl in
let env = List.fold_left for1 env fields in
curry3 (add_extra_op env) ctor
end
end
let add_ls env path ls tparams decl odecl =
let ls', add' =
match odecl with
| None -> ls, fun t -> t
| Some(ls', decl', decl_s) ->
ls', fun t ->
let t = add_decl_with_tuples t decl' in
add_decl_with_tuples t decl_s
in
{ env with
env_op = Mp.add path (ls,ls',tparams) env.env_op;
logic_task = add' (add_decl_with_tuples env.logic_task decl); }
let add_mp env mp ls =
let decl = Decl.create_param_decl ls in
let add o = assert (o = None); Some ls in
{ env with
env_mp = Mm.change add mp env.env_mp;
logic_task = add_decl_with_tuples env.logic_task decl}
let add_xpv env xp ls =
let decl = Decl.create_param_decl ls in
let add o = assert (o = None); Some ls in
{ env with
env_xpv = Mx.change add xp env.env_xpv;
logic_task = add_decl_with_tuples env.logic_task decl}
let add_xpf env xp ls =
let decl = Decl.create_param_decl ls in
let add o = assert (o = None); Some ls in
{ env with
env_xpf = Mx.change add xp env.env_xpf;
logic_task = add_decl_with_tuples env.logic_task decl}
let add_pr env path pr decl =
if Mp.mem path env.env_ax then
(assert (Decl.pr_equal pr (Mp.find path env.env_ax)); env)
else
{ env with
env_ax = Mp.add path pr env.env_ax;
env_rax = Decl.Mpr.add pr path env.env_rax;
logic_task = add_decl_with_tuples env.logic_task decl }
let rebind_item env = function
| RBuse w3 ->
let task = Task.use_export env.logic_task w3.rb_th in
let task = List.fold_left Task.add_decl task w3.rb_decl in
{ env with
logic_task = task;
env_ty = merge_ty env.env_ty w3.rb_ty;
env_op = merge_op env.env_op w3.rb_op;
env_ax = merge_ax env.env_ax w3.rb_ax;
env_w3 = merge_id env.env_w3 w3.rb_w3; }
| RBty(p,ts,decl) -> add_ts env p ts decl
| RBop(p,(ls,tvs),decl,odecl) -> add_ls env p ls tvs decl odecl
| RBax(p,pr,decl) -> add_pr env p pr decl
| RBmp(p,ls) -> add_mp env p ls
| RBxpv(p,ls) -> add_xpv env p ls
| RBxpf(p,ls) -> add_xpf env p ls
| RBfun(decl,sdecl, k, t) ->
let task =
List.fold_left add_decl_with_tuples
env.logic_task [decl(*;decls*);sdecl] in
{ env with
env_lam = Mta.add k t env.env_lam;
logic_task = task }
| RBproj(n,p,ls,d) ->
let task = add_decl_with_tuples env.logic_task d in
let mn = try Mint.find n env.env_proj with Not_found -> Mint.empty in
let ep = Mint.add n (Mint.add p ls mn) env.env_proj in
{ env with env_proj = ep; logic_task = task }
let rebind = List.fold_left rebind_item
(* ---------------------------------------------------------------------- *)
(* ----------------------- Import why3 theory -------------------------- *)
(* ---------------------------------------------------------------------- *)
type renaming_kind =
| RDts
| RDls
| RDpr
type renaming_decl = (string list * renaming_kind * EcSymbols.symbol) list
let w3_id_string id = id.Ident.id_string
module Renaming = struct
type renaming = {
r_ts : EcSymbols.symbol Ty.Mts.t;
r_ls : EcSymbols.symbol Term.Mls.t;
r_pr : EcSymbols.symbol Decl.Mpr.t
}
let init rd th =
let ns = th.Theory.th_export in
let rec aux ts ls pr rd =
match rd with
| [] -> { r_ts = ts; r_ls = ls; r_pr = pr }
| (p,RDts,id) :: rd ->
let ts = Ty.Mts.add (Theory.ns_find_ts ns p) id ts in
aux ts ls pr rd
| (p,RDls,id) :: rd ->
let ls = Term.Mls.add (Theory.ns_find_ls ns p) id ls in
aux ts ls pr rd
| (p,RDpr,id)::rd ->
let pr = Decl.Mpr.add (Theory.ns_find_pr ns p) id pr in
aux ts ls pr rd in
aux Ty.Mts.empty Term.Mls.empty Decl.Mpr.empty rd
let get_ts rn ts =
try Ty.Mts.find ts rn.r_ts
with _ ->
let id = ts.Ty.ts_name in
w3_id_string id
let remove_infix s =
let len = String.length s in
if len < 7 then s else
let inf = String.sub s 0 6 in
if inf = "infix " then String.sub s 6 (len - 6) else
let prf = String.sub s 0 7 in
if prf = "prefix " then String.sub s 7 (len - 7) else
if s = "mixfix []" then EcCoreLib.s_get else
if s = "mixfix [<-]" then EcCoreLib.s_set else
s
let get_ls rn ls =
try Term.Mls.find ls rn.r_ls
with _ ->
let id = ls.Term.ls_name in
let s = remove_infix (w3_id_string id) in
s
let get_pr rn pr =
try Decl.Mpr.find pr rn.r_pr
with _ ->
let id = pr.Decl.pr_name in
w3_id_string id
end
module Wtvm = struct
type t = EcIdent.t Ty.Mtv.t ref
let create () = ref Ty.Mtv.empty
let get tvm tv =
try Ty.Mtv.find tv !tvm
with _ ->
let s = w3_id_string tv.Ty.tv_name in
assert (String.length s <> 0);
let s = if s.[0] = '\'' then s else String.concat "" ["\'"; s] in
let id = EcIdent.create s in
tvm := Ty.Mtv.add tv id !tvm;
id
let tparams tvm =
List.map (fun x -> (x, Sp.empty)) (Ty.Mtv.values !tvm)
end
exception UnknownWhy3Ident of Ident.ident
let path_of_id env id =
try Ident.Mid.find id env.env_w3
with _ -> raise (UnknownWhy3Ident id)
let rec import_w3_ty env tvm ty =
match ty.Ty.ty_node with
| Ty.Tyvar v -> tvar (Wtvm.get tvm v)
| Ty.Tyapp(t, args) ->
let args = List.map (import_w3_ty env tvm) args in
try
let path,_ = path_of_id env t.Ty.ts_name in
tconstr path args
with e ->
if Ty.is_ts_tuple t then ttuple args
else if Ty.ts_equal t Ty.ts_func then
let t1,t2 = List.hd2 args in
tfun t1 t2
else if Ty.ts_equal t Ty.ts_pred then
let t1,t2 = List.hd args, tbool in
tfun t1 t2
else raise e
let add_w3_ty env p ty =
{ env with
env_ty = Mp.add p (ty, `Plain) env.env_ty;
env_w3 = Ident.Mid.add (ty.Ty.ts_name) (p, []) env.env_w3 }
let rbadd_w3_ty rb p ty =
{ rb with
rb_ty = Mp.add p (ty, `Plain) rb.rb_ty;
rb_w3 = Ident.Mid.add (ty.Ty.ts_name) (p,[]) rb.rb_w3 }
type zipper_elem =
| Zenter of EcSymbols.symbol
| Zdecl of theory_item
and zipper = zipper_elem list
let import_w3_tydef rn path (env,rb,z) ty =
let tvm = Wtvm.create () in
let params = List.map (fun x -> Wtvm.get tvm x, Sp.empty) ty.Ty.ts_args in
let def =
match ty.Ty.ts_def |> omap (import_w3_ty env tvm) with
| None -> `Abstract Sp.empty
| Some ty -> `Concrete ty
in
let eid = Renaming.get_ts rn ty in
let td = { tyd_params = params; tyd_type = def } in
let p = EcPath.pqname path eid in
let env = add_w3_ty env p ty in
let rb = rbadd_w3_ty rb p ty in
(env, rb, Zdecl (Th_type (eid, td)) :: z)
let force_bool codom =
match codom with
| None -> EcTypes.tbool
| Some t -> t
exception CannotTranslateW3Ec
exception UnboundLS of Term.lsymbol
let import_w3_quant = function
| Term.Tforall -> Lforall
| Term.Texists -> Lexists
let is_asym t =
Ident.Slab.mem Term.asym_label t.Term.t_label
let import_w3_term env tvm =
let memo = Ty.Hty.memo 37 (import_w3_ty env tvm) in
let import_ty ty =
match ty with
| None -> EcTypes.tbool
| Some t -> memo t in
let add_local v vm =
let id = EcIdent.create (w3_id_string v.Term.vs_name) in
let ty = import_ty (Some v.Term.vs_ty) in
(id,ty), Term.Mvs.add v id vm in
let add_locals vs vm =
let r = ref vm in
let its = List.map (fun v -> let (d,vm) = add_local v !r in r := vm; d) vs in
its, !r in
let rec import vm t =
match t.Term.t_node with
| Term.Tvar v -> f_local (Term.Mvs.find v vm) (import_ty t.Term.t_ty)
| Term.Tconst _ -> raise CannotTranslateW3Ec (* FIXME *)
| Term.Tapp(f,wargs) ->
let args = List.map (import vm) wargs in
let import_ty = import_w3_ty env tvm in
let wty = t.Term.t_ty in
let codom = odfl tbool (wty |> omap import_ty) in
begin try
let p,tvs =
try Ident.Mid.find f.Term.ls_name env.env_w3
with _ -> raise (UnboundLS f) in
let s = Term.ls_app_inst f wargs wty in
let tys = List.map (fun vs -> import_ty (Ty.Mtv.find vs s)) tvs in
let dom = List.map EcFol.f_ty args in
let op = f_op p tys (toarrow dom codom) in
f_app op args codom
with UnboundLS f as e ->
if Term.is_fs_tuple f then f_tuple args
else
if (Term.ls_equal f Term.fs_func_app ||
Term.ls_equal f Term.ps_pred_app) then
let a1,a2 = List.hd2 args in
f_app a1 [a2] codom
else raise e
end
| Term.Tif(t1,t2,t3) ->
let f1 = import vm t1 in
let f2 = import vm t2 in
let f3 = import vm t3 in
f_if f1 f2 f3
| Term.Tlet(e,tb) ->
let f1 = import vm e in
let v, t = Term.t_open_bound tb in
let (id,_), vm = add_local v vm in
let f2 = import vm t in
f_let (LSymbol (id,f1.f_ty)) f1 f2
| Term.Tcase _ -> raise CannotTranslateW3Ec (* FIXME : tuple *)
| Term.Teps _ -> raise CannotTranslateW3Ec
| Term.Tquant(q,tq) ->
let vs,_,t = Term.t_open_quant tq in
let ids, vm = add_locals vs vm in
let ids = List.map (fun (x, ty) -> (x, GTty ty)) ids in
let f = import vm t in
f_quant (import_w3_quant q) ids f
| Term.Tbinop(op,t1,t2) ->
let f1 = import vm t1 in
let f2 = import vm t2 in
begin match op with
| Term.Tand ->
if is_asym t1 then f_anda f1 f2 else f_and f1 f2
| Term.Tor ->
if is_asym t1 then f_ora f1 f2 else f_or f1 f2
| Term.Timplies -> f_imp f1 f2
| Term.Tiff -> f_iff f1 f2
end
| Term.Tnot t -> f_not (import vm t)
| Term.Ttrue -> f_true
| Term.Tfalse -> f_false in
import_ty, add_locals, import
let add_w3_ls env p ls wparams odecl =
let ls' = match odecl with None -> ls | Some (ls',_,_) -> ls' in
{ env with
env_op = Mp.add p (ls,ls',wparams) env.env_op;
env_w3 = Ident.Mid.add ls.Term.ls_name (p,wparams) env.env_w3 }
let rbadd_w3_ls rb p ls wparams odecl =
let ls',rb_decl =
match odecl with
| None -> ls, rb.rb_decl
| Some (ls',d',ds) -> ls', ds::d'::rb.rb_decl in
{ rb with
rb_op = Mp.add p (ls,ls',wparams) rb.rb_op;
rb_w3 = Ident.Mid.add ls.Term.ls_name (p,wparams) rb.rb_w3;
rb_decl = rb_decl;
}
let import_w3_ls rn path (env,rb,z) ls =
let tvm = Wtvm.create () in
let dom = List.map (import_w3_ty env tvm) ls.Term.ls_args in
let codom = ls.Term.ls_value |> omap (import_w3_ty env tvm) in
let wparams = Ty.Stv.elements (Term.ls_ty_freevars ls) in
let params = List.map (fun x -> Wtvm.get tvm x, Sp.empty) wparams in
let eid = Renaming.get_ls rn ls in
let op = mk_op params (toarrow dom (force_bool codom)) None in
let p = EcPath.pqname path eid in
let odecl = mk_highorder_func ls in
let env = add_w3_ls env p ls wparams odecl in
let rb = rbadd_w3_ls rb p ls wparams odecl in
env, rb, Zdecl (Th_operator (eid,op)) :: z
let import_w3_constructor rn path envld (ls, pls) =
let envld = import_w3_ls rn path envld ls in
List.fold_left (fun envld ols ->
match ols with
| Some ls -> import_w3_ls rn path envld ls
| None -> envld) envld pls
let import_w3_constructors rn path =
List.fold_left (import_w3_constructor rn path)
let add_w3_pr env p pr =
{ env with
env_ax = Mp.add p pr env.env_ax;
env_w3 = Ident.Mid.add (pr.Decl.pr_name) (p,[]) env.env_w3 }
let rbadd_w3_pr rb p pr =
{ rb with
rb_ax = Mp.add p pr rb.rb_ax;
rb_w3 = Ident.Mid.add (pr.Decl.pr_name) (p,[]) rb.rb_w3 }
let import_w3_pr rn path (env,rb,z as envld) k pr t =
match k with
| Decl.Plemma | Decl.Paxiom ->
let eid = Renaming.get_pr rn pr in
let tvm = Wtvm.create () in
let _, _, import = import_w3_term env tvm in
let spec =
try Some (import Term.Mvs.empty t);
with CannotTranslateW3Ec -> None in
(* FIXME: assert unicity of string in [ax_tparams] *)
let ax = {
ax_tparams = Wtvm.tparams tvm;
ax_spec = spec;
ax_kind = if k = Decl.Plemma then `Lemma else `Axiom;
ax_nosmt = false; } in
let p = EcPath.pqname path eid in
let env = add_w3_pr env p pr in
let rb = rbadd_w3_pr rb p pr in
env, rb, Zdecl(Th_axiom (eid,ax)) :: z
| Decl.Pgoal | Decl.Pskip -> envld
let import_decl rn path envld d =
match d.Decl.d_node with
| Decl.Dtype ty -> import_w3_tydef rn path envld ty
| Decl.Ddata ddl ->
let lty, lc = List.split ddl in
let envld = List.fold_left (import_w3_tydef rn path) envld lty in
List.fold_left (import_w3_constructors rn path) envld lc
| Decl.Dparam ls -> import_w3_ls rn path envld ls
| Decl.Dlogic lls ->
let lls = List.map fst lls in
List.fold_left (import_w3_ls rn path) envld lls
| Decl.Dind _ -> envld (* FIXME *)
| Decl.Dprop (k,pr,t) -> import_w3_pr rn path envld k pr t
let import_decls rn path env rb decls =
let rec diff ls ls' =
match ls, ls' with
| s::ls, s'::ls' when s = s' -> diff ls ls'
| _, _ -> List.rev ls, ls' in
let rec close accu ls path z =
match ls, z, path.EcPath.p_node with
| [], _, _ -> path, z
| s::ls, Zenter id:: z, EcPath.Pqname(p,id') ->
assert (s = id && EcSymbols.equal id id');
close [] ls p (Zdecl (Th_theory (id, accu)) :: z)
| _s::_ls, Zenter _id:: _z, _ -> assert false
| _, Zdecl d::z, _ -> close (d::accu) ls path z
| _, [], _ -> assert false in
let open_ ls path z =
List.fold_left (fun (path, z) s ->
EcPath.pqname path s, (Zenter s) :: z) (path, z) ls
in
let close_open ls ls' path z =
let ls, ls' = diff ls ls' in
let path, z = close [] ls path z in
open_ ls' path z in
let rec aux ls path (env,rb,z as envld) decls =
match decls with
| d::decls ->
let ids = d.Decl.d_news in
if Ident.Sid.is_empty ids then aux ls path envld decls
else
let id = Ident.Sid.choose ids in
let (_,_,s) = Theory.restore_path id in
let ls' = List.rev (List.tl (List.rev s)) in
let path, z = close_open ls ls' path z in
let envld = import_decl rn path (env,rb,z) d in
aux ls' path envld decls
| [] ->
let final_close z =
List.rev_map (function Zdecl d -> d | _ -> assert false) z in
let _, z = close [] ls path z in
(env,rb,final_close z) in
aux [] path (env,rb,[]) decls
let import_w3 env path th rd =
let rb = rb_empty th in
let rn = Renaming.init rd th in
let task = Task.use_export None th in
let ths = Ident.Mid.remove th.Theory.th_name (Task.used_theories task) in
let others = Task.used_symbols ths in
let decls = Task.local_decls task others in
let _env,rb,ld = import_decls rn path env rb decls in
let rb = { rb with rb_decl = List.rev rb.rb_decl } in
ld, RBuse rb
(* ----------------------------------------------------------------------- *)
(* ------------------------ Exporting to why3 ---------------------------- *)
(* ----------------------------------------------------------------------- *)
let preid id =
Ident.id_fresh (EcIdent.name id)
let str_p p =
Ident.id_fresh (String.map (fun c -> if c = '.' then '_' else c) p)
let preid_p p = str_p (EcPath.tostring p)
let preid_mp mp = str_p (EcPath.m_tostring mp)
let preid_xp xp = str_p (EcPath.x_tostring xp)
let create_tvsymbol id =
Ty.create_tvsymbol (preid id)
(* ------------------------ Types -----------------------------------------*)
exception UnboundTypeVariable of EcIdent.t
let trans_pty env p =
oget (Mp.find_opt p env.env_ty |> omap fst)
let trans_tv env id =
match Mid.find_opt id env.env_tv with
| None -> raise (UnboundTypeVariable id)
| Some x -> x
let trans_tglob env mp =
assert (mp.EcPath.m_args = []); (* tglob should have been normalized *)
match mp.EcPath.m_top with
| `Local id -> (try Mid.find id env.env_tv with _ -> assert false)
| _ -> assert false (* tglob should have been normalized *)
let trans_glob env mp =
assert (mp.EcPath.m_args = []); (* tglob should have been normalized *)
match mp.EcPath.m_top with
| `Local id ->
(try Mid.find id env.env_id with _ ->
Format.printf "trans_glob %s@." (EcIdent.tostring id);
assert false)
| _ ->
Format.printf "trans_glob %s@." (EcPath.m_tostring mp);
assert false (* tglob should have been normalized *)
let rec trans_ty env ty =
match ty.ty_node with
| Tglob mp -> trans_tglob env mp
| Tunivar _ -> assert false
| Tvar id -> trans_tv env id
| Ttuple tys -> Ty.ty_tuple (trans_tys env tys)
| Tconstr(p,tys) ->
let id = trans_pty env p in
Ty.ty_app id (trans_tys env tys)
| Tfun(t1,t2) -> Ty.ty_func (trans_ty env t1) (trans_ty env t2)
and trans_tys env tys = List.map (trans_ty env) tys
let trans_typarams =
let trans_tv env ((id, _) : ty_param) = (* FIXME: TC HOOK *)
let tv = create_tvsymbol id in
let add o = assert (o = None); Some (Ty.ty_var tv) in
({ env with env_tv = Mid.change add id env.env_tv }, tv)
in
List.map_fold trans_tv
let trans_tydecl env path td =
let pid = preid_p path in
let (env, tparams) = trans_typarams env td.tyd_params in
match td.tyd_type with
| `Abstract _ -> (* FIXME: TC HOOK *)
let ts = Ty.create_tysymbol pid tparams None in
let decl = Decl.create_ty_decl ts in
((ts, `Plain), decl)
| `Concrete ty ->
let ty = trans_ty env ty in
let ts = Ty.create_tysymbol pid tparams (Some ty) in
let decl = Decl.create_ty_decl ts in
((ts, `Plain), decl)
| `Datatype { tydt_ctors = cs } ->
let ts = Ty.create_tysymbol pid tparams None in
let decl = Decl.create_ty_decl ts in
let env = add_ts env path (ts, `Plain) decl in
let ncs = List.length cs in
let (cs, wcs) =
let for1 (c, aty) =
let cid = preid_p (EcPath.pqname path c) in
let aty = aty |> List.map (trans_ty env) in
let dom = tconstr path (List.map (tvar |- fst) td.tyd_params) in
let dom = dom |> trans_ty env in
let cls = Term.create_lsymbol ~constr:ncs cid aty (Some dom) in
let ocls = mk_highorder_func cls in
((c, cls, ocls), (cls, List.create (List.length aty) None))
in
List.split (List.map for1 cs)
in
let decl = Decl.create_data_decl [(ts, wcs)] in
((ts, `Datatype cs), decl)
| `Record (_, fields) ->
let ts = Ty.create_tysymbol pid tparams None in
let decl = Decl.create_ty_decl ts in
let env = add_ts env path (ts, `Plain) decl in
let myself = tconstr path (List.map (tvar |- fst) td.tyd_params) in
let myself = myself |> trans_ty env in
let ps =
let for1 (f, aty) =
let fid = preid_p (EcPath.pqname path f) in
let aty = trans_ty env aty in
let pls = Term.create_lsymbol fid [myself] (Some aty) in
let opls = mk_highorder_func pls in
(f, pls, opls, aty)
in
List.map for1 fields in
let cid = preid_p (EcPath.pqname path "$record") in
let csym = Printf.sprintf "mk_%s" (EcPath.basename path) in
let cls = Term.create_lsymbol ~constr:1 cid (List.map proj4_4 ps) (Some myself) in
let ocls = mk_highorder_func cls in
let decl = Decl.create_data_decl [ts, [cls, List.map (some |- proj4_2) ps]] in
((ts, `Record ((csym, cls, ocls), ps)), decl)
(* --------------------------- Formulas ------------------------------- *)
let trans_lv env lv =
match Mid.find_opt lv env.env_id with
| None ->
Printf.printf "cannot find %s\n%!" (EcIdent.tostring lv);
assert false
| Some x -> x
let trans_mp env p = try Mm.find p env.env_mp with _ -> assert false
let trans_xpv env p = try Mx.find p env.env_xpv with _ -> assert false
let trans_xpf env p = try Mx.find p env.env_xpf with _ -> assert false
let rm_mp_args mp =
EcPath.mpath mp.EcPath.m_top []
let is_top_mp mp =
match mp.EcPath.m_top with
| `Local _ | `Concrete(_,None) -> true
| `Concrete (_, Some _) -> false
let rec trans_mod env mp =
let args = List.map (trans_mod env) mp.EcPath.m_args in
let fs = trans_mp env (rm_mp_args mp) in
if is_top_mp mp then List.fold_left app_mod (Term.fs_app fs [] ty_mod) args
else Term.fs_app fs args ty_mod
let rm_xp_args xp =
let mp = rm_mp_args xp.EcPath.x_top in
EcPath.xpath mp xp.EcPath.x_sub
let trans_fun env xp targs =
let args = List.map (trans_mod env) xp.EcPath.x_top.EcPath.m_args in
let xp = rm_xp_args xp in
let fs = trans_xpf env xp in
Term.fs_app fs args (ty_fun targs)
let trans_pvloc env xp ty =
let args = List.map (trans_mod env) xp.EcPath.x_top.EcPath.m_args in
let xp = rm_xp_args xp in
let fs = trans_xpv env xp in
Term.fs_app fs args (ty_var ty)
let trans_pv env pv ty mem =
let xp = pv.pv_name in
let mem = trans_lv env mem in
let ty = trans_ty env ty in
let v =
if is_loc pv then trans_pvloc env xp ty
else Term.fs_app (trans_xpv env xp) [] (ty_var ty) in
get_var v mem
let create_vsymbol id ty = Term.create_vsymbol (preid id) ty
let add_id env (id, ty) =
let wid = create_vsymbol id ty in
let add o = assert (o = None); Some (Term.t_var wid) in
{ env with env_id = Mid.change add id env.env_id }, wid
let add_ids env ids lty =
assert (List.length lty = List.length ids);
List.map_fold add_id env (List.combine ids lty)
let t_app p args ty =
if p.Term.ls_value = None then Term.t_app p args None
else Term.t_app p args (Some ty)
let prop_of_bool t =
assert (Ty.oty_equal t.Term.t_ty (Some Ty.ty_bool));
match t.Term.t_node with
| Term.Tif(t1,t2,t3) when
Term.t_equal t2 Term.t_bool_true &&
Term.t_equal t3 Term.t_bool_false -> t1
| _ ->
if Term.t_equal t Term.t_bool_true then Term.t_true
else if Term.t_equal t Term.t_bool_false then Term.t_false
else Term.t_equ t Term.t_bool_true
let force_prop t =
if t.Term.t_ty = None then t
else prop_of_bool t
let bool_of_prop t =
assert (t.Term.t_ty = None);
match t.Term.t_node with
| Term.Ttrue -> Term.t_bool_true
| Term.Tfalse -> Term.t_bool_false
| Term.Tapp(ls,[t;tt]) when
Term.t_equal tt Term.t_bool_true &&
Term.ls_equal ls Term.ps_equ -> t
| _ ->
Term.t_if t Term.t_bool_true Term.t_bool_false
let force_bool t = if t.Term.t_ty = None then bool_of_prop t else t
let mk_not args =
match args with
| [e] -> Term.t_not e
| _ -> assert false
let mk_pred2 f l =
match l with
| [e1;e2] -> f e1 e2
| _ -> assert false
let mk_anda = mk_pred2 Term.t_and_asym
let mk_and = mk_pred2 Term.t_and
let mk_ora = mk_pred2 Term.t_or_asym
let mk_or = mk_pred2 Term.t_or
let mk_imp = mk_pred2 Term.t_implies
let mk_iff = mk_pred2 Term.t_iff
let mk_eq = mk_pred2 Term.t_equ
let trans_op env p tys =
match op_kind p with
| OK_true -> ([],None), w3_ls_true, fun _ -> Term.t_true
| OK_false -> ([],None), w3_ls_false, fun _ -> Term.t_false
| OK_not -> ([None],None), w3_ls_not, mk_not
| OK_and true -> ([None;None],None), w3_ls_anda, mk_anda
| OK_and false -> ([None;None],None), w3_ls_and, mk_and
| OK_or true -> ([None;None],None), w3_ls_ora, mk_ora
| OK_or false -> ([None;None],None), w3_ls_or, mk_or
| OK_imp -> ([None;None],None), w3_ls_imp, mk_imp
| OK_iff -> ([None;None],None), w3_ls_iff, mk_iff
| OK_eq ->
let ty = trans_ty env (List.hd tys) in
([Some ty;Some ty],None), w3_ls_eq, mk_eq
| _ ->
let ls,ls', tvs =
match Mp.find_opt p env.env_op with
| None ->
raise (CannotTranslate "trans_op")
| Some x -> x in
let mtv =
List.fold_left2 (fun mtv tv ty ->
Ty.Mtv.add tv (trans_ty env ty) mtv) Ty.Mtv.empty
tvs tys in
let targs = List.map (fun t -> Some (Ty.ty_inst mtv t)) ls.Term.ls_args in
let tres = ls.Term.ls_value |> omap (Ty.ty_inst mtv) in
let mk args = Term.t_app ls args tres in
(targs,tres), ls', mk
let apply_highorder f args =
List.fold_left (fun f a -> Term.t_func_app f (force_bool a)) f args
let cast_arg a ty =
match a.Term.t_ty, ty with
| None, None -> a
| None, Some _ -> force_bool a
| Some _, None -> force_prop a
| Some _,Some _ -> a
let cast_app mk args targs = mk (List.map2 cast_arg args targs)
let rec highorder_type targs tres =
match targs with
| [] -> odfl Ty.ty_bool tres
| a::targs -> Ty.ty_func a (highorder_type targs tres)
let trans_app env p tys args =
let (targs,tres), ls', mk = trans_op env p tys in
let arity = List.length targs in
let nargs = List.length args in
if arity = nargs then cast_app mk args targs
else if arity < nargs then
let args1,args2 = List.take_n arity args in
apply_highorder (cast_app mk args1 targs) args2
else (* arity > nargs *)
let targs = List.map (odfl Ty.ty_bool) targs in
let fty = highorder_type targs tres in
apply_highorder (Term.fs_app ls' [] fty) args
let destr_ty_tuple t =
match t.Ty.ty_node with
| Ty.Tyapp (ts, lt) -> assert (Ty.is_ts_tuple ts); lt
| _ -> assert false
let merge_branches lb =
if List.exists (fun b -> b.Term.t_ty = None) lb then List.map force_prop lb
else lb
let trans_gty env gty =
match gty with
| GTty ty -> env, trans_ty env ty
| GTmodty _ -> raise (CannotTranslate "binding of module")
| GTmem mt ->
match mt with
| None -> env, ty_mem
| Some lmt ->
let xp = EcMemory.lmt_xpath lmt in
let tparams = List.map (fun _ -> ty_mod) xp.EcPath.x_top.EcPath.m_args in
let xp = rm_xp_args xp in
let add id (p,ty) env =
match p with
| Some _ -> env
| None ->
let ty = trans_ty env ty in
let xp = EcPath.xqname xp id in
if Mx.mem xp env.env_xpv then
let ls = Mx.find xp env.env_xpv in
assert (List.all2 Ty.ty_equal ls.Term.ls_args tparams);
assert (Ty.oty_equal ls.Term.ls_value (Some (ty_var ty)));
env
else
let ls = Term.create_fsymbol (preid_xp xp) tparams (ty_var ty) in
let decl = Decl.create_param_decl ls in
{ env with
env_xpv = Mx.add xp ls env.env_xpv;
logic_task = add_decl_with_tuples env.logic_task decl } in
let env = Msym.fold add (EcMemory.lmt_bindings lmt) env in
env, ty_mem
let trans_gtys env gtys =
List.map_fold trans_gty env gtys
let trans_form env f =
let env = ref env in
let save () = !env.env_id in
let restore mid = env := { !env with env_id = mid} in
let rb = ref [] in
let trans_proj n p =
let mn =
try Mint.find n !env.env_proj with Not_found -> Mint.empty in
try Mint.find p mn with Not_found ->
let tvs =
Array.init n (fun _ -> Ty.create_tvsymbol (Ident.id_fresh "a")) in
let ts = Array.map Ty.ty_var tvs in
let t = Ty.ty_tuple (Array.to_list ts) in
let tp = ts.(p) in
let pat = Array.map (fun t -> Term.pat_wild t) ts in
let vp = Term.create_vsymbol (Ident.id_fresh "v") tp in
pat.(p) <- Term.pat_var vp;
let br =
Term.t_close_branch
(Term.pat_app (Term.fs_tuple n) (Array.to_list pat) t)
(Term.t_var vp) in
let va = Term.create_vsymbol (Ident.id_fresh "p") t in
let body = Term.t_case (Term.t_var va) [ br ] in
let s = Format.sprintf "proj%i_%i" n p in
let ls = Term.create_lsymbol (Ident.id_fresh s) [t] (Some tp) in
let decl = Decl.create_logic_decl [Decl.make_ls_defn ls [va] body ] in
let mn = Mint.add p ls mn in
env := {!env with
logic_task = add_decl_with_tuples !env.logic_task decl;
env_proj = Mint.add n mn !env.env_proj
};
rb := RBproj(n,p,ls,decl)::!rb;
ls in
let rec trans_form f =
match f.f_node with
| Fquant(q,b,fq) ->
let mid = save () in
let ids, tys = List.split b in
let env0, tys = trans_gtys !env tys in
let env1, vs = add_ids env0 ids tys in
env := env1;
let fq = trans_form fq in
let res =
match q with
| Lforall -> Term.t_forall_close vs [] (force_prop fq)
| Lexists -> Term.t_exists_close vs [] (force_prop fq)
| Llambda -> trans_lambda vs fq in
restore mid;
res
| Fif(f1,f2,f3) ->
let f1 = trans_form f1 in
let f2 = trans_form f2 in
let f3 = trans_form f3 in
let f2,f3 =
match merge_branches [f2;f3] with
| [f2;f3] -> f2, f3
| _ -> assert false in
Term.t_if_simp (force_prop f1) f2 f3
| Flet(lp,f1,f2) ->
let mid = save () in
let f1 = trans_form_b f1 in
let res =
match lp with
| LSymbol (id,_) ->
let env0, id = add_id !env (id, Term.t_type f1) in
env := env0;
let f2 = trans_form f2 in
Term.t_let f1 (Term.t_close_bound id f2)
| LTuple ids ->
let ids = List.map fst ids in
let t1 = Term.t_type f1 in
let env0, ids = add_ids !env ids (destr_ty_tuple t1) in
env := env0;
let pat =
Term.pat_app (Term.fs_tuple (List.length ids))
(List.map Term.pat_var ids) t1 in
let f2 = trans_form f2 in
let br = Term.t_close_branch pat f2 in
Term.t_case f1 [br]
| LRecord (recp, fields) ->
let ctor =
match Mp.find_opt recp (!env).env_ty with
| Some (_, `Record ((_, ctor), _)) -> ctor
| _ -> assert false in
let pat =
let pat =
List.map (fun (x, ty) ->
let ty = trans_ty !env ty in
let v =
match x with
| None -> None
| Some x ->
let env0, v = add_id !env (x, ty) in
env := env0; Some v
in
match v with
| None -> Term.pat_wild ty
| Some v -> Term.pat_var v)
fields
in
Term.pat_app ctor pat (Term.t_type f1) in
let f2 = trans_form f2 in
let br = Term.t_close_branch pat f2 in
Term.t_case f1 [br]
in
restore mid; res
| Fint n ->
let n = Number.ConstInt(Number.int_const_dec (string_of_int n)) in
Term.t_const n
| Flocal id -> trans_lv !env id
| Fop(p,tys) -> trans_app !env p tys []
| Fapp({f_node = Fop(p,tys) },args) ->
let args = List.map trans_form args in
trans_app !env p tys args
| Fapp(e,args) ->
let args = List.map trans_form args in
apply_highorder (trans_form e) args
| Ftuple args ->
let args = List.map trans_form_b args in
Term.t_tuple args
| Fproj(f,i) ->
let a = trans_form f in
let ty = oget (a.Term.t_ty) in
let n =
match ty.Ty.ty_node with
| Ty.Tyapp(_,targs) -> List.length targs
| _ -> assert false in
let ls = trans_proj n i in
Term.t_app_infer ls [a]
| FhoareF _ -> raise (CannotTranslate "FhoareF")
| FhoareS _ -> raise (CannotTranslate "FhoareS")
| FbdHoareF _ -> raise (CannotTranslate "FbdHoareF")
| FbdHoareS _ -> raise (CannotTranslate "FbdHoareS")
| FequivF _ -> raise (CannotTranslate "FequivF")
| FeagerF _ -> raise (CannotTranslate "FeagerF")
| FequivS _ -> raise (CannotTranslate "FequivS")
| Fpvar(pv,m) ->
let pv = trans_pv !env pv f.f_ty m in
pv
| Fglob(mp,m) ->
let mo = trans_glob !env mp in
let mem = trans_lv !env m in
get_var mo mem
| Fpr(mem,mp,args,ev) ->
let mem = trans_lv !env mem in
let args = trans_form_b args in
let f =
trans_fun !env mp (oget args.Term.t_ty) in
let mid = save () in
let env0, ty = trans_gty !env (GTmem None) in
let env1, vs = add_id env0 (EcFol.mhr, ty) in
env := env1;
let evbody = trans_form ev in
let ev = trans_lambda [vs] evbody in
restore mid;
getpr f mem args ev
and trans_form_b f = force_bool (trans_form f)
and trans_lambda vs body =
(* TODO how to share lambda with free variable *)
try Mta.find (vs,body) !env.env_lam
with Not_found ->
(* We compute the free variable of the lambda *)
let fv =
List.fold_left (fun s x -> Term.Mvs.remove x s)
body.Term.t_vars vs in
let fv_ids = Term.Mvs.keys fv in
let tfv = List.map (fun v -> v.Term.vs_ty) fv_ids in
let tvs = List.map (fun v -> v.Term.vs_ty) vs in
let codom =
if body.Term.t_ty = None then Ty.ty_bool else oget body.Term.t_ty in
(* We create the symbol corresponding to the lambda *)
let lam_sym = Ident.id_fresh "unamed_lambda" in
let flam_sym =
Term.create_fsymbol lam_sym tfv
(List.fold_right Ty.ty_func tvs codom) in
let decl_sym = Decl.create_param_decl flam_sym in
(* We create the spec *)
let fvargs = List.map Term.t_var fv_ids in
let vsargs = List.map Term.t_var vs in
let flam_app =
Term.t_app_infer flam_sym fvargs in
let flam_fullapp =
List.fold_left Term.t_func_app flam_app vsargs in
let concl =
if body.Term.t_ty = None then Term.t_iff (force_prop flam_fullapp) body
else Term.t_equ flam_fullapp body in
let spec = Term.t_forall_close (fv_ids@vs) [] concl in
let spec_sym =
Decl.create_prsymbol (Ident.id_fresh "unamed_lambda_spec") in
let decl_spec = Decl.create_prop_decl Decl.Paxiom spec_sym spec in
rb := RBfun(decl_sym,decl_spec, (vs,body), flam_app) :: !rb;
env := { !env with
env_lam = Mta.add (vs,body) flam_app !env.env_lam;
logic_task =
List.fold_left add_decl_with_tuples !env.logic_task
[decl_sym;decl_spec] };
flam_app in
let f = trans_form f in
!env, !rb, f
let destr_ty_fun ty =
let rec aux tys codom =
match codom.Ty.ty_node with
| Ty.Tyapp(ts,[dom;codom]) when Ty.ts_equal ts Ty.ts_func ->
aux (dom::tys) codom
| _ -> List.rev tys, codom in
aux [] ty
let trans_oper_body env path wparams ty body =
let pid = preid_p path in
let body =
match body with
| OB_oper None -> None
| OB_oper (Some (OP_Plain o)) -> Some (`Plain (EcFol.form_of_expr EcFol.mhr o))
| OB_oper (Some (OP_Fix o)) -> Some (`Fix o)
| OB_oper (Some (OP_Constr _)) -> assert false
| OB_oper (Some (OP_Record _)) -> assert false
| OB_oper (Some (OP_Proj _)) -> assert false
| OB_oper (Some (OP_TC )) -> assert false
| OB_pred o -> o |> omap (fun x -> `Plain x)
in
match body with
| None ->
let ty = trans_ty env ty in
let dom, codom = destr_ty_fun ty in
let codom = if Ty.ty_equal codom Ty.ty_bool then None else Some codom in
(env, [], Term.create_lsymbol pid dom codom, None)
| Some (`Plain body) ->
let bd, body =
match body.f_node with
| Fquant (Llambda, bd, f) -> (bd, f)
| _ -> ([], body) in
let ids, dom = List.split bd in
let env, dom = trans_gtys env dom in
let env, vs = add_ids env ids dom in
let env, rb, f = trans_form env body in
let f =
if Ty.oty_equal f.Term.t_ty (Some Ty.ty_bool)
then force_prop f
else f
in
(env, rb, Term.create_lsymbol pid dom f.Term.t_ty, Some (vs, f))
| Some (`Fix o) ->
let (env, dom, vs) =
let ids, dom = List.split o.opf_args in
let dom = List.map (trans_ty env) dom in
let env, vs = add_ids env ids dom in
(env, dom, vs)
in
let ls = Term.create_lsymbol pid dom (Some (trans_ty env o.opf_resty)) in
let pterm = List.map (List.nth vs) (fst o.opf_struct) in
let ptermty = List.map (fun x -> x.Term.vs_ty) pterm in
let ptermc = List.length ptermty in
let ops = env.env_op in
let env = { env with env_op = Mp.add path (ls, ls, wparams) env.env_op; } in
let ((env, rb), ptns) =
let rec compile ((env, rb), ptns) (ctors, m) =
match m with
| OPB_Branch bs ->
Parray.fold_left
(fun ((env, rb), ptns) b ->
let cl = proj3_1 (oget (Mp.find_opt (fst b.opb_ctor) env.env_op)) in
compile ((env, rb), ptns) (cl :: ctors, b.opb_sub))
((env, rb), ptns) bs
| OPB_Leaf (locals, e) ->
let ctors = List.rev ctors in
let env, vs =
List.map_fold
(fun env locals ->
let ids, sig_ = List.split locals in
let sig_ = List.map (trans_ty env) sig_ in
add_ids env ids sig_)
env locals
in
let env, rb1, e = trans_form env (EcFol.form_of_expr EcFol.mhr e) in
let ptn =
let for1 (cl, vs) pty =
let ptn = List.map Term.pat_var vs in
let ptn = Term.pat_app cl ptn pty in
ptn
in
try List.map2 for1 (List.combine ctors vs) ptermty
with Failure _ -> assert false
in
let ptn =
if ptermc > 1
then Term.pat_app (Term.fs_tuple ptermc) ptn (Ty.ty_tuple ptermty)
else oget (List.ohead ptn)
in
((env, rb1@rb), (ptn, e)::ptns)
in
compile ((env, []), []) ([], o.opf_branches)
in
let ptns = List.rev ptns in
let ptns = List.map (fun (p, e) -> Term.t_close_branch p (force_bool e)) ptns in
let mtch =
if ptermc > 1
then Term.t_tuple (List.map Term.t_var pterm)
else Term.t_var (oget (List.ohead pterm)) in
let body = Term.t_case mtch ptns in
({ env with env_op = ops; }, rb, ls, Some (vs, body))
let trans_oper env path op =
let mty = env.env_tv in
let mid = env.env_id in
let env, wparams = trans_typarams env op.op_tparams in
let env, rb, ls, body = trans_oper_body env path wparams op.op_ty op.op_kind in
let decl =
match body with
| None -> Decl.create_param_decl ls
| Some(ids,f) -> Decl.create_logic_decl [Decl.make_ls_defn ls ids f]
in
({ env with env_tv = mty; env_id = mid; }, rb, ls, wparams, decl)
let add_ty env path td =
let (ts, decl) = trans_tydecl env path td in
(add_ts env path ts decl, [RBty (path, ts, decl)])
let add_op env path op =
try
let env, rb, ls, wparams, decl = trans_oper env path op in
let odecl = mk_highorder_func ls in
let env = add_ls env path ls wparams decl odecl in
let rb = RBop(path,(ls,wparams),decl,odecl)::rb in
(env, rb)
with CannotTranslate _ -> (env, [])
let add_ax env path ax =
let pr = Decl.create_prsymbol (preid_p path) in
let mty = env.env_tv in
let mid = env.env_id in
let env, _ = trans_typarams env ax.ax_tparams in
match ax.ax_spec with
| None -> assert false
| Some f ->
let env, rb =
try
let env,rb,f = trans_form env f in
let decl = Decl.create_prop_decl Decl.Paxiom pr (force_prop f) in
add_pr env path pr decl, RBax(path,pr,decl)::rb
with CannotTranslate _ ->
{ env with env_tv = mty}, [] in
{ env with env_tv = mty; env_id = mid }, rb
let add_mod_exp_mp env mp me =
assert (mp.EcPath.m_args = []);
assert (match mp.EcPath.m_top with
| `Local _ | `Concrete(_, None) -> true
| _ -> false);
let is_alias = function ME_Alias _ -> true | _ -> false in
match me.me_body with
| ME_Alias (arity,_) ->
if arity = 0 then env, []
else
let ls = Term.create_fsymbol (preid_mp mp) [] ty_mod in
add_mp env mp ls, [RBmp(mp,ls)]
| _ ->
let ls = Term.create_fsymbol (preid_mp mp) [] ty_mod in
let env = ref (add_mp env mp ls) in
let rb = ref [RBmp(mp,ls)] in
let tparams = List.map (fun _ -> ty_mod) me.me_sig.mis_params in
let add_xpv xp ls =
env := add_xpv !env xp ls;
rb := RBxpv(xp,ls) :: !rb in
let add_gpv xp ty =
assert (not (Mx.mem xp !env.env_xpv));
let ty = trans_ty !env ty in
let ls = Term.create_fsymbol (preid_xp xp) [] (ty_var ty) in
add_xpv xp ls in
let add_lpv xp ty =
assert (not (Mx.mem xp !env.env_xpv));
let ty = trans_ty !env ty in
let ls = Term.create_fsymbol (preid_xp xp) tparams (ty_var ty) in
add_xpv xp ls in
let rec add_comps mp comps = List.iter (add_comp mp) comps
and add_comp mp comp =
match comp with
| MI_Module me ->
if not (is_alias me.me_body) then begin
let mp = EcPath.mqname mp me.me_name in
let ls = Term.create_fsymbol (preid_mp mp) tparams ty_mod in
env := add_mp !env mp ls;
rb := RBmp(mp,ls) :: !rb;
add_comps mp me.me_comps
end
| MI_Variable v ->
add_gpv (EcPath.xpath_fun mp v.v_name) v.v_type
| MI_Function f ->
let tys =trans_ty !env f.f_sig.fs_arg in
let xp = EcPath.xpath_fun mp f.f_name in
let ls = Term.create_fsymbol (preid_xp xp) tparams (ty_fun tys) in
env := add_xpf !env xp ls;
rb := RBxpf(xp,ls) :: !rb;
add_lpv (EcPath.xqname xp "param") f.f_sig.fs_arg;
add_lpv (EcPath.xqname xp "res") f.f_sig.fs_ret in
add_comps mp me.me_comps;
!env, !rb
let add_mod_exp env p me = add_mod_exp_mp env (mpath_crt p [] None) me
let check_w3_formula pi task f =
let pr = Decl.create_prsymbol (Ident.id_fresh "goal") in
let decl = Decl.create_prop_decl Decl.Pgoal pr f in
let task = add_decl_with_tuples task decl in
EcProvers.execute_task pi task = Some true
exception CannotProve of axiom
type me_of_mt = EcIdent.t -> module_type -> mod_restr -> module_expr
let trans_tv env id =
let ts = Ty.create_tysymbol (preid id) [] None in
let decl = Decl.create_ty_decl ts in
{ env with
env_tv = Mid.add id (Ty.ty_app ts []) env.env_tv;
logic_task = add_decl_with_tuples env.logic_task decl }
let add_abs_mod me_of_mt env id mt restr =
let me = me_of_mt id mt restr in
let env = trans_tv env id in
(* represent the type of the glob memory of the module *)
let ty = Mid.find id env.env_tv in
let vty = ty_var ty in
let ls = Term.create_fsymbol (preid id) [] vty in
let decl = Decl.create_param_decl ls in
let env =
{ env with env_id = Mid.add id (t_app ls [] vty) env.env_id;
logic_task = add_decl_with_tuples env.logic_task decl } in
let nenv,_ = add_mod_exp_mp env (EcPath.mident id) me in
nenv
(* -------------------------------------------------------------------- *)
open EcProvers
let rec filter_task_r w3env (hints : hints) task = (* FIXME: not tail-rec *)
match task with
| None -> None
| Some task ->
let aout = filter_task_r w3env hints task.Task.task_prev in
match task.Task.task_decl.Theory.td_node with
| Theory.Decl { Decl.d_node = Decl.Dprop (_, x, _) } -> begin
match Decl.Mpr.find_opt x w3env.env_rax with
| None -> Task.add_tdecl aout task.Task.task_decl
| Some p -> begin
match Hints.mem p hints with
| true -> Task.add_tdecl aout task.Task.task_decl
| false -> aout
end
end
| _ -> Task.add_tdecl aout task.Task.task_decl
let filter_task w3env hints task =
if hints = Hints.full
then task
else filter_task_r w3env hints task
(* -------------------------------------------------------------------- *)
let check_goal me_of_mt env pi hints (hyps, concl) =
let env = ref env in
let trans_tv id = env := trans_tv !env id in
let trans_hyp (id,ld) =
try
match ld with
| LD_var (ty,body) ->
let codom = trans_ty !env ty in
let pid = preid id in
let ls = Term.create_fsymbol pid [] codom in
let decl = match body with
| None -> Decl.create_param_decl ls
| Some e ->
let nenv, _, e = trans_form !env e in
env := nenv;
Decl.create_logic_decl [Decl.make_ls_defn ls [] (force_bool e)] in
env :=
{ !env with env_id = Mid.add id (t_app ls [] codom) !env.env_id;
logic_task = add_decl_with_tuples !env.logic_task decl }
| LD_hyp f ->
let nenv, _, f = trans_form !env f in
env := nenv;
let pr = Decl.create_prsymbol (preid id) in
let decl = Decl.create_prop_decl Decl.Paxiom pr (force_prop f) in
env :=
{ !env with logic_task = add_decl_with_tuples !env.logic_task decl }
| LD_mem mt ->
let env0, _ = trans_gty !env (GTmem mt) in
let ls = Term.create_fsymbol (preid id) [] ty_mem in
let decl = Decl.create_param_decl ls in
env :=
{ env0 with env_id = Mid.add id (t_app ls [] ty_mem) env0.env_id;
logic_task = add_decl_with_tuples env0.logic_task decl }
| LD_modty (mt,restr) ->
env := add_abs_mod me_of_mt !env id mt restr
| LD_abs_st _ -> ()
with CannotTranslate _ -> ()
in
List.iter trans_tv (List.map fst hyps.h_tvar);
List.iter trans_hyp (List.rev hyps.h_local);
let env, _, concl = trans_form !env concl in
let task = filter_task env hints env.logic_task in
check_w3_formula pi task (force_prop concl)
Computing file changes ...