123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439(** Implementation of the why3 tactic. *)openLplibopenTimedopenCommonopenErroropenCoreopenTermopenPrintopenFolopenProof(** Logging function for external prover calling with Why3. *)letlog=Logger.make'y'"why3""why3 provers"letlog=log.pp(** [default_prover] contains the name of the current prover. Note that it can
be changed by using the "set prover <string>" command. *)letdefault_prover:stringref=ref"Alt-Ergo"(** [timeout] is the current time limit (in seconds) for a Why3 prover to find
a proof. It can be changed with "set prover <int>". *)lettimeout:intref=ref2(** [why3_config] is the Why3 configuration read from the configuration file
(["~/.why3.conf"] usually). For more information, visit the Why3
documentation at http://why3.lri.fr/api/Whyconf.html. *)letwhy3_config:Why3.Whyconf.config=letcfg=Why3.Whyconf.init_configNoneinletprovers=Why3.Whyconf.get_proverscfginConsole.out2"provers available for why3:";letproverp_=Console.out2"%a"Why3.Whyconf.print_proverpinWhy3.Whyconf.Mprover.iterproverprovers;cfg(** [why3_main] is the main section of the Why3 configuration. *)letwhy3_main:Why3.Whyconf.main=Why3.Whyconf.get_mainwhy3_config(** [why3_env] is the initialized Why3 environment. *)letwhy3_env:Why3.Env.env=Why3.Env.create_env(Why3.Whyconf.loadpathwhy3_main)(** Data type used to record how Lambdapi symbols, variables and terms are
mapped to Why3 symbols or variables. *)typel2y={s2ts:(sym*Why3.Ty.tysymbol)list(* Mapping of type symbols. *);t2ts:(term*Why3.Ty.tysymbol)list(* Mapping of non-Why3 subtypes. *);v2tv:(var*Why3.Ty.tvsymbol)list(* Mapping of type variables. *);s2ls:(sym*(Why3.Term.lsymbol*bool))list(* Mapping of function symbols. [true] is for predicates. *);v2ls:(var*(Why3.Term.lsymbol*bool))list(* Mapping of environment variables. [true] is for predicates. *);t2ls:(term*Why3.Term.lsymbol)list(* Mapping of non-Why3 subterms. *);v2vs:(var*Why3.Term.vsymbol)list(* Mapping of object variables. *)}letempty_l2y={s2ts=[];v2tv=[];t2ts=[];s2ls=[];v2ls=[];v2vs=[];t2ls=[]}letl2yppfm=letopenDebug.DinBase.outppf"{s2ts=%a; v2tv=%a; t2ts=%a; s2ls=%a; v2ls=%a; v2vs=%a; t2ls=%a}"(list(pairsymWhy3.Pretty.print_ts))m.s2ts(list(pairvarWhy3.Pretty.print_tv))m.v2tv(list(pairtermWhy3.Pretty.print_ts))m.t2ts(list(pairsym(pairWhy3.Pretty.print_lsbool)))m.s2ls(list(pairvar(pairWhy3.Pretty.print_lsbool)))m.v2ls(list(pairvarWhy3.Pretty.print_vs))m.v2vs(list(pairtermWhy3.Pretty.print_ls))m.t2ls(** Translation functions below raise Exit if a term cannot be
translated. They return an update l2y map as well because mappings are
done while translating terms. *)(** [translate_set m t] tries to translate a Lambdapi term [t:Set] to a Why3
type. *)letrectranslate_setmt=ifLogger.log_enabled()thenlog"translate_set %a [%a]"l2ymtermt;matchget_argstwith|Symbs,ts->letm,ts=translate_setsmtsinletm,s=matchList.assoc_optsm.s2tswith|Somes'->m,s'|None->letid=Why3.Ident.id_freshs.sym_nameinlets'=Why3.Ty.create_tysymbolid[]Why3.Ty.NoDefinifLogger.log_enabled()thenlog"add tysymbol %a"Why3.Pretty.print_tss';{mwiths2ts=(s,s')::m.s2ts},s'inm,Why3.Ty.ty_appsts|Varix,[]->beginmatchList.assoc_eq_opteq_varsxm.v2tvwith|Sometv->m,Why3.Ty.ty_vartv|None->raiseExitend|_->raiseExit(*try m, Why3.Ty.ty_app (List.assoc_eq (Eval.eq_modulo []) t m.t2ts) []
with Not_found ->
let id = Why3.Ident.id_fresh "T" in
let s = Why3.Ty.create_tysymbol id [] Why3.Ty.NoDef in
{m with t2ts = (t,s)::m.t2ts}, Why3.Ty.ty_app s []*)andtranslate_setsmts=List.fold_right(funt(m,ts)->letm,t=translate_setmtinm,t::ts)ts(m,[])(** [translate_type m t] tries to translate a Lambdapi term [t:TYPE] of the
form [P _] to a Why3 type. *)lettranslate_typecfgmt=ifLogger.log_enabled()thenlog"translate_type %a [%a]"l2ymtermt;matchget_argstwith|Symbs,[t]whens==cfg.symb_T->translate_setmt|_->raiseExit(*let translate_types cfg m ts =
List.fold_right
(fun t (m,ts) -> let m,t = translate_type cfg m t in m, t::ts)
ts (m,[])*)(** [translate_pred_type cfg m t] tries to translate a Lambdapi term [t] of
the form [T a1 → .. → T an → Prop] to a Why3 type. *)lettranslate_pred_typecfg=letrecauxaccmt=ifLogger.log_enabled()thenlog"translate_pred_type %a [%a]"l2ymtermt;matchunfoldtwith|Symbs->ifs==cfg.symb_Propthenm,List.revaccelseraiseExit|Prod(a,b)->letm,a=translate_typecfgmainlet_,b=unbindbinaux(a::acc)mb|_->raiseExitinaux[](** [translate_fun_type cfg m t] tries to translate a Lambdapi term [t] of the
form [T a1 → .. → T an → T a] to a Why3 type. *)lettranslate_fun_typecfg=letrecauxaccmt=ifLogger.log_enabled()thenlog"translate_fun_type %a [%a]"l2ymtermt;matchunfoldtwith|Prod(a,b)->letm,a=translate_typecfgmainlet_,b=unbindbinaux(a::acc)mb|_->letm,a=translate_typecfgmtinm,List.revacc,ainaux[](** [translate_term cfg m t] tries to translate a Lambdapi term [t:T _] to a
Why3 term. *)letrectranslate_termcfgmt=ifLogger.log_enabled()thenlog"translate_term %a [%a]"l2ymtermt;matchget_argstwith|Symbs,ts->beginmatchList.assoc_eq_opt(==)sm.s2lswith|Some(_,true)->assertfalse|Some(s,false)->letm,ts=translate_termscfgmtsinm,Why3.Term.t_app_infersts|None->letm,tys,a=translate_fun_typecfgm!(s.sym_type)inletid=Why3.Ident.id_freshs.sym_nameinletf=Why3.Term.create_fsymbolidtysainifLogger.log_enabled()thenlog"add psymbol %a : %a → %a"Why3.Pretty.print_lsf(Debug.D.listWhy3.Pretty.print_ty)tysWhy3.Pretty.print_tya;letm={mwiths2ls=(s,(f,false))::m.s2ls}inletm,ts=translate_termscfgmtsinm,Why3.Term.t_app_inferftsend|Varix,ts->beginmatchList.assoc_eq_opteq_varsxm.v2vswith|Somev->ifts=[]thenm,Why3.Term.t_varvelseraiseExit|None->matchList.assoc_eq_opteq_varsxm.v2lswith|Some(_,true)->assertfalse|Some(s,false)->letm,ts=translate_termscfgmtsinm,Why3.Term.t_app_infersts|None->assertfalseend|_->raiseExitandtranslate_termscfgmts=List.fold_right(funt(m,ts)->letm,t=translate_termcfgmtinm,t::ts)ts(m,[])(** [translate_prop cfg m t] tries to translation a Lambdapi term [t:Prop] to
a Why3 proposition. *)letrectranslate_prop:config->l2y->term->l2y*Why3.Term.term=letdefaultmt=tryletsym=List.assoc_eq(Eval.eq_modulo[])tm.t2lsinm,Why3.Term.ps_appsym[]withNot_found->letsym=Why3.Term.create_psymbol(Why3.Ident.id_fresh"X")[]inifLogger.log_enabled()thenlog"abstract [%a] as psymbol %a"termtWhy3.Pretty.print_lssym;{mwitht2ls=(t,sym)::m.t2ls},Why3.Term.ps_appsym[]infuncfgmt->ifLogger.log_enabled()thenlog"translate_prop %a [%a]"l2ymtermt;matchget_argstwith|Symbs,[t1;t2]whens==cfg.symb_and->letm,t1=translate_propcfgmt1inletm,t2=translate_propcfgmt2inm,Why3.Term.t_andt1t2|Symbs,[t1;t2]whens==cfg.symb_or->letm,t1=translate_propcfgmt1inletm,t2=translate_propcfgmt2inm,Why3.Term.t_ort1t2|Symbs,[t1;t2]whens==cfg.symb_imp->letm,t1=translate_propcfgmt1inletm,t2=translate_propcfgmt2inm,Why3.Term.t_impliest1t2|Symbs,[t1;t2]whens==cfg.symb_eqv->letm,t1=translate_propcfgmt1inletm,t2=translate_propcfgmt2inm,Why3.Term.t_ifft1t2|Symbs,[t]whens==cfg.symb_not->letm,t=translate_propcfgmtinm,Why3.Term.t_nott|Symbs,[]whens==cfg.symb_bot->m,Why3.Term.t_false|Symbs,[]whens==cfg.symb_top->m,Why3.Term.t_true|Symbs,[a;Abst(_,t)]whens==cfg.symb_ex->letm,a=translate_setmaandx,t=unbindtinletid=Why3.Ident.id_fresh(base_namex)inletv=Why3.Term.create_vsymbolidainifLogger.log_enabled()thenlog"add vsymbol %a"Why3.Pretty.print_vsv;letm={mwithv2vs=(x,v)::m.v2vs}inletm,t=translate_propcfgmtin(* remove x from m.v2vs ? *)m,Why3.Term.t_exists_close[v][]t|Symbs,[a;Abst(_,t)]whens==cfg.symb_all->letm,a=translate_setmaandx,t=unbindtinletid=Why3.Ident.id_fresh(base_namex)inletv=Why3.Term.create_vsymbolidainifLogger.log_enabled()thenlog"add vsymbol %a"Why3.Pretty.print_vsv;letm={mwithv2vs=(x,v)::m.v2vs}inletm,t=translate_propcfgmtin(* remove x from m.v2vs ? *)m,Why3.Term.t_forall_close[v][]t|Varix,ts->beginmatchList.assoc_eq_opteq_varsxm.v2lswith|Some(_,false)->assertfalse|Some(s,true)->begintryletm,ts=translate_termscfgmtsinm,Why3.Term.ps_appstswithExit->defaultmtend|None->defaultmtend|Symbs,ts->beginmatchList.assoc_eq_opt(==)sm.s2lswith|Some(_,false)->assertfalse|Some(s,true)->begintryletm,ts=translate_termscfgmtsinm,Why3.Term.ps_appstswithExit->defaultmtend|None->begintryletm,tys=translate_pred_typecfgm!(s.sym_type)inletid=Why3.Ident.id_freshs.sym_nameinletf=Why3.Term.create_psymbolidtysinifLogger.log_enabled()thenlog"add psymbol %a : %a"Why3.Pretty.print_lsf(Debug.D.listWhy3.Pretty.print_ty)tys;letm={mwiths2ls=(s,(f,true))::m.s2ls}inletm,ts=translate_termscfgmtsinm,Why3.Term.ps_appftswithExit->defaultmtendend|_->defaultmt(** [translate_goal ss pos env g] translates the hypotheses [env] and the goal
[g] into a Why3 task. *)lettranslate_goal:Sig_state.t->Pos.popt->Env.env->term->Why3.Task.task=funssposenvg->letcfg=get_configssposin(* Translate environment. *)lettranslate_env_elt(name,(x,a,_))(m,hyps)=(*if Logger.log_enabled() then log "translate_env_elt %a %a %s : %a"
l2y m Debug.D.(list (pair string Why3.Pretty.print_term)) hyps
name term a;*)matchget_argsawith|Symbs,[]whens==cfg.symb_Set->(* type variable *)letid=Why3.Ident.id_freshnameinlettv=Why3.Ty.create_tvsymbolidinifLogger.log_enabled()thenlog"add tvsymbol %a"Why3.Pretty.print_tvtv;{mwithv2tv=(x,tv)::m.v2tv},hyps|Symbs,[t]whens==cfg.symb_T->(* object *)letm,t=translate_setmtinletid=Why3.Ident.id_freshnameinletf=Why3.Term.create_fsymbolid[]tinifLogger.log_enabled()thenlog"add fsymbol %a"Why3.Pretty.print_lsf;{mwithv2ls=(x,(f,false))::m.v2ls},hyps|Symbs,[t]whens==cfg.symb_P->(* assumption *)letm,t=translate_propcfgmtinm,(name,t)::hyps|_->(* predicate symbol *)letm,tys=translate_pred_typecfgmainletid=Why3.Ident.id_freshnameinletf=Why3.Term.create_psymbolidtysinifLogger.log_enabled()thenlog"add psymbol %a"Why3.Pretty.print_lsf;{mwithv2ls=(x,(f,true))::m.v2ls},hypsinlettranslate_env_eltbm=trytranslate_env_eltbmwithExit->minletm,hyps=List.fold_righttranslate_env_eltenv(empty_l2y,[])inifLogger.log_enabled()thenlog"hyps: %a"Debug.D.(list(pairstringWhy3.Pretty.print_term))hyps;(* Translate the goal. *)letm,g=matchget_argsgwith|Symbs,[t]whens==cfg.symb_P->begintrytranslate_propcfgmtwithExit->fatalpos"The goal cannot be translated to Why3."end|_->fatalpos"The goal is not of the form [%a _]."symcfg.symb_PinifLogger.log_enabled()thenlog"goal: %a"Why3.Pretty.print_termg;ifLogger.log_enabled()thenlog"map: %a"l2ym;(* Build the task. *)lettsk=Nonein(* Add the declarations of type symbols. *)letadd_s2ts_decltsk(_,tsym)=Why3.Task.add_ty_decltsktsyminlettsk=List.fold_leftadd_s2ts_decltskm.s2tsinletadd_t2ts_decltsk(_,tsym)=Why3.Task.add_ty_decltsktsyminlettsk=List.fold_leftadd_t2ts_decltskm.t2tsinifLogger.log_enabled()thenlog"%a"Why3.Pretty.print_tasktsk;(* Add the declarations of term symbols. *)letadd_s2ls_decltsk(_,(lsym,_))=Why3.Task.add_param_decltsklsyminlettsk=List.fold_leftadd_s2ls_decltskm.s2lsinletadd_v2ls_decltsk(_,(lsym,_))=Why3.Task.add_param_decltsklsyminlettsk=List.fold_leftadd_v2ls_decltskm.v2lsinletadd_t2ls_decltsk(_,lsym)=Why3.Task.add_param_decltsklsyminlettsk=List.fold_leftadd_t2ls_decltskm.t2lsin(* Add the declarations of assumptions. *)letadd_hyp_decltsk(name,prop)=letaxiom=Why3.Decl.create_prsymbol(Why3.Ident.id_freshname)inWhy3.Task.add_prop_decltskWhy3.Decl.Paxiomaxiompropinlettsk=List.fold_leftadd_hyp_decltskhypsin(* Add the goal. *)letgoal=Why3.Decl.create_prsymbol(Why3.Ident.id_fresh"G")inlettsk=Why3.Task.add_prop_decltskWhy3.Decl.PgoalgoalginifLogger.log_enabled()thenlog"%a"Why3.Pretty.print_tasktsk;tsk(** [run tsk pos prover_name] sends [tsk] to [prover_name]. *)letrun:Why3.Task.task->Pos.popt->string->bool=funtskposprover_name->(* Filter the set of why3 provers. *)letfilter=Why3.Whyconf.parse_filter_proverprover_nameinletprovers=Why3.Whyconf.filter_proverswhy3_configfilterin(* Fail if we did not find a matching prover. *)ifWhy3.Whyconf.Mprover.is_emptyproversthenbeginfatal_msg"Your prover might not be installed or detected.\n";fatal_msg"Remember to run \"why3 config detect\" \
after installing a prover.";fatal_msg"Why3 configuration read from \"%s\".\n"(Why3.Whyconf.get_conf_filewhy3_config);letprovers=Why3.Whyconf.get_proverswhy3_configinifWhy3.Whyconf.Mprover.is_emptyproversthenfatal_msg"There are no available provers.@."elsebeginfatal_msg"The available provers are:@.";letfp_=fatal_msg" - %a@."Why3.Whyconf.print_proverpinWhy3.Whyconf.Mprover.iterfproversend;fatalpos"prover \"%s\" not found.@."prover_name;end;(* Return the prover configuration and load the driver. *)letprover=snd(Why3.Whyconf.Mprover.max_bindingprovers)inletdriver=tryWhy3.Driver.load_driver_for_proverwhy3_mainwhy3_envproverwithe->fatalpos"Failed to load driver for \"%s\": %a"prover.prover.prover_nameWhy3.Exn_printer.exn_printerein(* Actually run the prover. *)letcommand=prover.Why3.Whyconf.commandandlimits={Why3.Call_provers.empty_limitswithlimit_time=float_of_int!timeout}inletcall=Why3.Driver.prove_task~command~config:why3_main~limitsdrivertskinWhy3.Call_provers.((wait_on_callcall).pr_answer=Valid)(** [handle ss pos prover_name gt] runs the Why3 prover corresponding to
[prover_name] (if given or a default one otherwise) on the goal type [gt],
and fails if no proof is found. *)lethandle:Sig_state.t->Pos.popt->stringoption->goal_typ->unit=funssposprover_name({goal_meta=_;goal_hyps=hyps;goal_type=t}asgt)->letg=TypgtinifLogger.log_enabled()thenlog"%a"Goal.ppg;(* Encode the goal in Why3. *)lettsk=translate_goalssposhypstin(* Get the name of the prover. *)letprover_name=Option.get!default_proverprover_nameinifLogger.log_enabled()thenlog"running with prover \"%s\""prover_name;(* Run the task with the prover named [prover_name]. *)ifnot(runtskposprover_name)thenfatalpos"\"%s\" did not find a proof"prover_name