123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2024 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(* --- Server API for WP --- *)(* -------------------------------------------------------------------------- *)moduleP=Server.PackagemoduleD=Server.DatamoduleR=Server.RequestmoduleS=Server.StatesmoduleMd=MarkdownmoduleAST=Server.Kernel_astletpackage=P.package~plugin:"wp"~title:"WP Main Services"()(* -------------------------------------------------------------------------- *)(* --- WPO Index --- *)(* -------------------------------------------------------------------------- *)moduleINDEX=State_builder.Ref(Datatype.Make(structincludeDatatype.Undefinedtypet=(string,Wpo.t)Hashtbl.tletname="WpApi.INDEX.Datatype"letreprs=[Hashtbl.create0]letmem_project=Datatype.never_any_projectend))(structletname="WpApi.INDEX"letdependencies=[Ast.self]letdefault()=Hashtbl.create0end)letindexGoalg=letid=g.Wpo.po_gidinletindex=INDEX.get()inifnot(Hashtbl.memindexid)thenHashtbl.addindexidg;idmoduleGoal:D.Swithtypet=Wpo.t=structtypet=Wpo.tletjtype=D.declare~package~name:"goal"~descr:(Md.plain"Proof Obligations")(Jkey"wpo")letof_jsonjs=Hashtbl.find(INDEX.get())(Json.stringjs)letto_jsong=`String(indexGoalg)end(* -------------------------------------------------------------------------- *)(* --- VCS Provers --- *)(* -------------------------------------------------------------------------- *)moduleProver=structtypet=VCS.proverletjtype=D.declare~package~name:"prover"~descr:(Md.plain"Prover Identifier")(Jkey"prover")letto_jsonprv=`String(VCS.name_of_proverprv)letof_jsonjs=matchVCS.parse_prover@@Json.stringjswith|Someprv->prv|None->D.failure"Unknown prover name"endmoduleProvers=D.Jlist(Prover)letsignal=refNoneletprovers=refNoneletgetProvers()=match!proverswith|Someprvs->prvs|None->letcmdline=matchWp_parameters.Provers.get()with|[]->["Alt-Ergo"]|prvs->prvsinletparses=matchVCS.parse_proverswith|None->None|Some(Qed|Tactical)->None|Someprvasresult->ifVCS.is_autoprvthenresultelseNoneinletselection=List.filter_mapparsecmdlineinprovers:=Someselection;selectionletupdProversprv=provers:=SomeprvletsetProversprv=updProversprv;Option.iter(funs->R.emits)!signallet()=lets=S.register_state~package~name:"provers"~descr:(Md.plain"Selected Provers")~data:(moduleProvers)~get:getProvers~set:updProvers()insignal:=Somes(* -------------------------------------------------------------------------- *)(* --- Server Processes --- *)(* -------------------------------------------------------------------------- *)let_=S.register_state~package~name:"process"~descr:(Md.plain"Server Processes")~data:(moduleD.Jint)~get:Wp_parameters.Procs.get~set:(funprocs->Wp_parameters.Procs.setprocs;ignore@@ProverTask.server~procs())~add_hook:Wp_parameters.Procs.add_hook_on_update()(* -------------------------------------------------------------------------- *)(* --- Provers Timeout --- *)(* -------------------------------------------------------------------------- *)let_=S.register_state~package~name:"timeout"~descr:(Md.plain"Prover's Timeout")~data:(moduleD.Jint)~get:Wp_parameters.Timeout.get~set:Wp_parameters.Timeout.set~add_hook:Wp_parameters.Timeout.add_hook_on_update()(* -------------------------------------------------------------------------- *)(* --- Available Provers --- *)(* -------------------------------------------------------------------------- *)letget_name=function|VCS.Qed->"Qed"|VCS.Tactical->"Script"|VCS.Why3p->Why3Provers.namepletget_version=function|VCS.Qed|Tactical->System_config.Version.id_and_codename|Why3p->Why3Provers.versionpletiter_proversfn=List.iter(funp->ifWhy3Provers.is_autop&&Why3Provers.is_mainstreampthenfn(VCS.Why3p))@@Why3Provers.provers()let_:VCS.proverS.array=letmodel=S.model()inS.column~name:"name"~descr:(Md.plain"Prover Name")~data:(moduleD.Jalpha)~get:get_namemodel;S.column~name:"version"~descr:(Md.plain"Prover Version")~data:(moduleD.Jalpha)~get:get_versionmodel;S.column~name:"descr"~descr:(Md.plain"Prover Full Name (description)")~data:(moduleD.Jalpha)~get:(VCS.title_of_prover~version:true)model;S.register_array~package~name:"ProverInfos"~descr:(Md.plain"Available Provers")~key:VCS.name_of_prover~keyName:"prover"~keyType:Prover.jtype~iter:iter_proversmodel(* -------------------------------------------------------------------------- *)(* --- Results and Stats --- *)(* -------------------------------------------------------------------------- *)moduleResult=structtypet=VCS.resultletjtype=D.declare~package~name:"result"~descr:(Md.plain"Prover Result")(Jrecord["descr",Jstring;"cached",Jboolean;"verdict",Jstring;"solverTime",Jnumber;"proverTime",Jnumber;"proverSteps",Jnumber;])letof_json_=failwith"Not implemented"letto_json(r:VCS.result)=`Assoc["descr",`String(Pretty_utils.to_stringVCS.pp_resultr);"cached",`Boolr.cached;"verdict",`String(VCS.name_of_verdict~computing:truer.verdict);"solverTime",`Floatr.solver_time;"proverTime",`Floatr.prover_time;"proverSteps",`Intr.prover_steps;]endmoduleSTATUS=structtypet={smoke:bool;verdict:VCS.verdict}letjtype=D.declare~package~name:"status"~descr:(Md.plain"Test Status")(Junion[Jkey"NORESULT";Jkey"COMPUTING";Jkey"FAILED";Jkey"STEPOUT";Jkey"UNKNOWN";Jkey"VALID";Jkey"PASSED";Jkey"DOOMED";])letto_json{smoke;verdict}=`Stringbeginmatchverdictwith|Valid->ifsmokethen"DOOMED"else"VALID"|Invalid->ifsmokethen"PASSED"else"INVALID"|Unknown->ifsmokethen"PASSED"else"UNKNOWN"|Timeout->ifsmokethen"PASSED"else"TIMEOUT"|Stepout->ifsmokethen"PASSED"else"STEPOUT"|Failed->"FAILED"|NoResult->"NORESULT"|Computing_->"COMPUTING"endendmoduleSTATS=structtypet=Stats.statsletjtype=D.declare~package~name:"stats"~descr:(Md.plain"Prover Result")(Jrecord["summary",Jstring;"tactics",Jnumber;"proved",Jnumber;"total",Jnumber;])letto_jsoncs:Json.t=letsummary=Pretty_utils.to_string(Stats.pp_stats~shell:false~cache:Update)csin`Assoc["summary",`Stringsummary;"tactics",`Intcs.tactics;"proved",`Intcs.proved;"total",`Int(Stats.subgoalscs);]end(* -------------------------------------------------------------------------- *)(* --- Goal Array --- *)(* -------------------------------------------------------------------------- *)letgmodel:Wpo.tS.model=S.model()letget_propertyg=Printer_tag.PIP(WpPropId.property_of_idg.Wpo.po_pid)letget_markerg=matchg.Wpo.po_formula.sourcewith|Some(stmt,_)->Printer_tag.localizable_of_stmtstmt|None->letip=WpPropId.property_of_idg.Wpo.po_pidinmatchipwith|IPOther{io_loc=OLStmt(_,stmt)}->Printer_tag.localizable_of_stmtstmt|_->Printer_tag.PIPipletget_declg=matchg.Wpo.po_idxwith|Function(kf,_)->Some(Printer_tag.SFunctionkf)|Axiomatic_->None(* TODO *)letget_fctg=matchg.Wpo.po_idxwith|Function(kf,_)->Some(Kernel_function.get_namekf)|Axiomatic_->Noneletget_bhvg=matchg.Wpo.po_idxwith|Function(_,bhv)->bhv|Axiomatic_->Noneletget_thyg=matchg.Wpo.po_idxwith|Function_->None|Axiomaticax->axletget_statusg=STATUS.{smoke=Wpo.is_smoke_testg;verdict=(ProofEngine.consolidatedg).best;}let()=S.columngmodel~name:"marker"~descr:(Md.plain"Associated Marker")~data:(moduleAST.Marker)~get:get_markerlet()=S.columngmodel~name:"scope"~descr:(Md.plain"Associated declaration, if any")~data:(moduleD.Joption(AST.Decl))~get:get_decllet()=S.columngmodel~name:"property"~descr:(Md.plain"Property Marker")~data:(moduleAST.Marker)~get:get_propertylet()=S.optiongmodel~name:"fct"~descr:(Md.plain"Associated function name, if any")~data:(moduleD.Jstring)~get:get_fctlet()=S.optiongmodel~name:"bhv"~descr:(Md.plain"Associated behavior name, if any")~data:(moduleD.Jstring)~get:get_bhvlet()=S.optiongmodel~name:"thy"~descr:(Md.plain"Associated axiomatic name, if any")~data:(moduleD.Jstring)~get:get_thylet()=S.columngmodel~name:"name"~descr:(Md.plain"Informal Property Name")~data:(moduleD.Jstring)~get:(fung->g.Wpo.po_name)let()=S.columngmodel~name:"smoke"~descr:(Md.plain"Smoking (or not) goal")~data:(moduleD.Jbool)~get:Wpo.is_smoke_testlet()=S.columngmodel~name:"passed"~descr:(Md.plain"Valid or Passed goal")~data:(moduleD.Jbool)~get:Wpo.is_passedlet()=S.columngmodel~name:"status"~descr:(Md.plain"Verdict, Status")~data:(moduleSTATUS)~get:get_statuslet()=S.columngmodel~name:"stats"~descr:(Md.plain"Prover Stats Summary")~data:(moduleSTATS)~get:ProofEngine.consolidatedlet()=S.columngmodel~name:"proof"~descr:(Md.plain"Proof Tree")~data:(moduleD.Jbool)~get:ProofEngine.has_prooflet()=S.optiongmodel~name:"script"~descr:(Md.plain"Script File")~data:(moduleD.Jstring)~get:(funwpo->matchProofSession.getwpowith|NoScript->None|Scripta|Deprecateda->Some(a:>string))let()=S.columngmodel~name:"saved"~descr:(Md.plain"Saved Script")~data:(moduleD.Jbool)~get:(funwpo->ProofEngine.getwpo=`Saved)letfilterhookfn=hook(fung->ifnot@@Wpo.is_tacticgthenfng)let(++)h1h2fn=h1fn;h2fnletgoals=letadd_remove_hook=filterWpo.add_removed_hookinletadd_update_hook=filterWpo.add_modified_hook++ProofEngine.add_goal_hookinletadd_reload_hook=Wpo.add_cleared_hookinS.register_array~package~name:"goals"~descr:(Md.plain"Generated Goals")~key:indexGoal~keyName:"wpo"~keyType:Goal.jtype~iter:(filterWpo.iter_on_goals)~preload:ProofEngine.consolidate~add_remove_hook~add_update_hook~add_reload_hookgmodel(* -------------------------------------------------------------------------- *)(* --- Generate RTEs --- *)(* -------------------------------------------------------------------------- *)let()=R.register~package~kind:`EXEC~name:"generateRTEGuards"~descr:(Md.plain"Generate RTE guards for the function")~input:(moduleAST.Marker)~output:(moduleD.Junit)beginfunction|PVDecl(Somekf,_,_)->letsetup=Factory.parse(Wp_parameters.Model.get())inletdriver=Driver.load_driver()inletmodel=Factory.instancesetupdriverinWpRTE.generatemodelkf|_->()end(* -------------------------------------------------------------------------- *)(* --- Generate goals --- *)(* -------------------------------------------------------------------------- *)letis_callstmt=matchstmt.Cil_types.skindwith|Instr(Call_)|Instr(Local_init(_,ConsInit_,_))->true|_->falselet()=R.register~package~kind:`EXEC~name:"startProofs"~descr:(Md.plain"Generate goals and run provers")~input:(moduleAST.Marker)~output:(moduleD.Junit)beginfunction|PExp_|PTermLval_|PLval_|PGlobal_|PType_|PVDecl(None,_,_)->(* We cannot run anything here *)()|PStmtStart(_,stmt)|PStmt(_,stmt)whenis_callstmt->VC.command@@VC.generate_callstmt|PStmtStart(kf,stmt)|PStmt(kf,stmt)->letfold_ips_cabag=letids=WpPropId.mk_code_annot_idskfstmtcainletprops=Bag.ulist@@List.mapVC.generate_ip@@List.mapWpPropId.property_of_ididsinBag.concatbagpropsinVC.command@@Annotations.fold_code_annotfold_ipsstmtBag.empty|PVDecl(Somekf,_,_)->VC.command@@VC.generate_kfkf|PIPproperty->VC.command@@VC.generate_ippropertyend(* -------------------------------------------------------------------------- *)(* --- Proof Server --- *)(* -------------------------------------------------------------------------- *)letserverActivity=R.signal~package~name:"serverActivity"~descr:(Md.plain"Proof Server Activity")let()=letserver_sig=R.signature~input:(moduleD.Junit)()inletset_procs=R.resultserver_sig~name:"procs"~descr:(Md.plain"Max parallel tasks")(moduleD.Jint)inletset_active=R.resultserver_sig~name:"active"~descr:(Md.plain"Active tasks")(moduleD.Jint)inletset_done=R.resultserver_sig~name:"done"~descr:(Md.plain"Finished tasks")(moduleD.Jint)inletset_todo=R.resultserver_sig~name:"todo"~descr:(Md.plain"Remaining jobs")(moduleD.Jint)inR.register_sig~package~kind:`GET~name:"getScheduledTasks"~descr:(Md.plain"Scheduled tasks in proof server")~signals:[serverActivity]server_sigbeginletmonitored=reffalseinfunrq()->letserver=ProverTask.server()inifnot!monitoredthenbeginmonitored:=true;letsignal()=R.emitserverActivityinTask.on_server_activityserversignal;Task.on_server_startserversignal;Task.on_server_stopserversignal;end;set_procsrq(Task.get_procsserver);set_activerq(Task.runningserver);set_donerq(Task.terminatedserver);set_todorq(Task.remainingserver);endlet()=R.register~package~kind:`SET~name:"cancelProofTasks"~descr:(Md.plain"Cancel all scheduled proof tasks")~input:(moduleD.Junit)~output:(moduleD.Junit)(fun()->letserver=ProverTask.server()inTask.cancel_allserver)(* -------------------------------------------------------------------------- *)