123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)(* -------------------------------------------------------------------------- *)(* --- WP Lower Panel --- *)(* -------------------------------------------------------------------------- *)openDesignopenWidgetopenPropertyopenGuiSource(* -------------------------------------------------------------------------- *)(* --- Build the Reactive Behavior of GUI --- *)(* -------------------------------------------------------------------------- *)typescope=[`All|`Module|`Select]typefilter=[`ToProve|`Scripts|`Smoke|`All]typecard=[`List|`Goal]typefocus=[`All|`IndexofWpo.index|`CallofGuiSource.call|`PropertyofProperty.t]letindex_of_lemmal=matchLogicUsage.section_of_lemmal.il_namewith|LogicUsage.Toplevel_->Wpo.AxiomaticNone|LogicUsage.Axiomatica->Wpo.Axiomatic(Somea.LogicUsage.ax_name)letfocus_of_selectionselectionscope=matchselection,scopewith|S_none,_|_,`All->`All|S_callc,`Select->`Callc|S_callc,`Module->`Index(Wpo.Function(c.s_caller,None))|S_funkf,(`Select|`Module)->`Index(Wpo.Function(kf,None))|S_prop(IPLemmailem),`Module->`Index(index_of_lemmailem)|S_prop(IPAxiomatic{iax_name=name}),_->`Index(Wpo.Axiomatic(Somename))|S_propip,`Select->`Propertyip|S_propip,`Module->beginmatchProperty.get_kfipwith|None->`All|Somekf->`Index(Wpo.Function(kf,None))endexceptionFIRSTofWpo.tletfirstiter=tryiter(funw->raise(FIRSTw));NonewithFIRSTw->Somewletiter_kfkff=Wpo.iter~index:(Wpo.Function(kf,None))~on_goal:f()letiter_ipipf=Wpo.iter~ip~on_goal:f()letiter_ipsipsf=List.iter(funip->Wpo.iter~ip~on_goal:f())ipsletcallsc=List.mapsnd(Statuses_by_call.all_call_preconditions_at~warn_missing:falsec.s_callerc.s_stmt)letgoal_of_selection=function|S_none->None|S_propip->first(iter_ipip)|S_callc->first(iter_ips(callsc))|S_funkf->first(iter_kfkf)classbehavior~(main:Design.main_window_extension_points)~(scope:scopeWidget.selector)~(filter:filterWidget.selector)~(next:Widget.button)~(prev:Widget.button)~(index:Widget.button)~(clear:Widget.button)~(card:cardWidget.selector)~(list:GuiList.pane)~(provers:GuiConfig.provers)~(goal:GuiGoal.pane)~(source:GuiSource.highlighter)~(popup:GuiSource.popup)=object(self)initializerletmoduleCfg=Gtk_helper.ConfigurationinbeginCfg.config_values~key:"wp.navigator.scope"~values:[`All,"all";`Module,"module";`Select,"select"]~default:`Modulescope;Cfg.config_values~key:"wp.navigator.filter"~values:[`All,"all";`Smoke,"smoketests";`Scripts,"scripts";`ToProve,"toprove"]~default:`ToProvefilter;filter#on_eventself#reload;endvalmutablefocus:focus=`Allvalmutablecurrentgoal:Wpo.toption=Nonemethodupdate()=beginlist#update_all;source#update;goal#update;endmethodreload()=beginlist#reload;letto_proveg=not(Wpo.is_smoke_testg)&¬(Wpo.is_validg||Wpo.reduceg)inlethas_proofg=matchProofEngine.getgwith|`None->false|`Proof|`Script|`Saved->trueinleton_goalg=letok=matchfilter#getwith|`All->true|`Smoke->Wpo.is_smoke_testg|`Scripts->has_proofg|`ToProve->to_proveg&&(Wpo.has_unknowng||has_proofg)inifokthenlist#addginbeginmatchfocuswith|`All->Wpo.iter~on_goal()|`Indexindex->Wpo.iter~index~on_goal()|`Propertyip->Wpo.iter~ip~on_goal()|`Callc->iter_ips(callsc)on_goalend;letn=list#sizeinletk=matchcurrentgoalwith|None->(-1)|Somew->trylist#indexwwithNot_found->(-1)inindex#set_enabled(n>0);ifn=0thencard#set`List;letsrc=ifn=1&&k=0then(card#set`Goal;clear#set_enabledfalse;true)elsefalseinifk<0thenself#navigatorfalseNoneelseself#navigatorsrc(Some(list#getk));endmethodprivateset_focusf=focus<-f;self#reload()methodprivateset_scopef=matchf,currentgoalwith|`Module,Somew->self#set_focus(`Index(Wpo.get_indexw))|`Select,Somew->self#set_focus(`Property(Wpo.get_propertyw))|_,_->self#set_focus`Allmethodprivateset_selections=letf=scope#getincurrentgoal<-goal_of_selections;self#set_focus(focus_of_selectionsf)(* -------------------------------------------------------------------------- *)(* --- Navigation from Next/Prev/List --- *)(* -------------------------------------------------------------------------- *)methodprivatedetails=matchcard#get,currentgoalwith|`List,Somew->list#showw|`List,None->()|`Goal,sw->goal#selectswmethodprivatenavigatorsrc=function|None->begincurrentgoal<-None;next#set_enabledfalse;prev#set_enabledfalse;source#setNone;self#details;end|(Somew)assw->trycurrentgoal<-sw;letn=list#sizeinletk=list#indexwinprev#set_enabled(k>0);next#set_enabled(succk<n);source#set(ifsrcthenswelseNone);self#details;withNot_found->self#navigatorfalseNonemethodprivatenext()=self#movesuccmethodprivateprev()=self#movepredmethodprivatemovedir=trymatchcurrentgoalwith|None->()|Somew->beginself#navigatortrueNone;letk=list#indexwinletw=list#get(dirk)inself#navigatortrue(Somew);endwithNot_found->self#navigatortrueNonemethodprivateprove?modewprover=beginletrefreshw=matchcard#getwith|`List->list#updatew|`Goal->goal#updateinletresultw_prv_res=refreshwinletsuccessw_res=refreshwinletscheduletask=letthread=Task.threadtaskinletkill()=Wpo.set_resultwproverVCS.no_result;Task.cancelthread;inWpo.set_resultwprover(VCS.computingkill);letserver=ProverTask.server()inTask.spawnserverthread;Task.launchserverinifnot(VCS.is_valid(Wpo.get_resultwVCS.Qed))&¬(VCS.is_computing(Wpo.get_resultwprover))thenmatchproverwith|VCS.Tactical->beginmatchmode,ProverScript.getwwith|(None|SomeVCS.Batch),`Script->schedule(ProverScript.prove~successw)|_->card#set`Goal;clear#set_enabledfalse;self#navigatortrue(Somew);end|_->letmode=matchmode,proverwith|Somem,_->m|_->ifVCS.is_autoproverthenVCS.BatchelseVCS.Fixinschedule(Prover.provew~mode~resultprover);refreshwendmethodprivateclear()=beginlettitle="Delete Proof Obligations"inlettext=Printf.sprintf"Confirm deletion of %d proof obligation(s)"list#count_selectedinleticon=GMisc.image~stock:`DELETE()inletresponse=GToolbox.question_box~title~buttons:["Delete POs";"Cancel"]~default:1~icontextinifresponse=1thenbeginlist#iter_selectedWpo.remove;self#reload();endend(* -------------------------------------------------------------------------- *)(* --- Popup on Goals --- *)(* -------------------------------------------------------------------------- *)valpopup_qed=newWidget.popup()valpopup_tip=newWidget.popup()valpopup_why3_auto=newWidget.popup()valpopup_why3_inter=newWidget.popup()valmutablepopup_target=Nonemethodprivatepopup_delete()=matchpopup_targetwith|Some(w,_)->(popup_target<-None;Wpo.removew;self#reload())|None->()methodprivatepopup_delete_script()=matchpopup_targetwith|Some(w,_)->ProofEngine.clearw;ProofSession.removew|None->()methodprivatepopup_runmode()=matchpopup_targetwith|Some(w,Somep)->(popup_target<-None;self#prove~modewp)|_->popup_target<-Nonemethodprivateadd_popup_deletepopup=beginpopup#add_separator;popup#add_item~label:"Delete Goal"~callback:self#popup_delete;endmethodprivateadd_popup_proofmodespopupmodes=List.iter(fun(label,mode)->popup#add_item~label~callback:(self#popup_runmode))modesinitializerletopenVCSinbeginpopup_tip#add_item~label:"Run Script"~callback:(self#popup_runBatch);popup_tip#add_item~label:"Edit Proof"~callback:(self#popup_runEdit);popup_tip#add_item~label:"Delete Script"~callback:(self#popup_delete_script);popup_why3_auto#add_item~label:"Run Prover"~callback:(self#popup_runVCS.Batch);popup_why3_inter#add_item~label:"Check Script"~callback:(self#popup_runVCS.Batch);popup_why3_inter#add_item~label:"Edit Script"~callback:(self#popup_runVCS.Edit);popup_why3_inter#add_item~label:"Fixup Script"~callback:(self#popup_runVCS.FixUpdate);endmethodprivatepopupwp=letopenVCSinbeginpopup_target<-Some(w,p);matchpwith|None|SomeTactical->popup_tip#run()|SomeQed->popup_qed#run()|Some(Why3_asp)->ifVCS.is_autopthenpopup_why3_auto#run()elsepopup_why3_inter#run()endmethodprivateactionwp=matchpwith|None->begincard#set`Goal;clear#set_enabledfalse;self#navigatortrue(Somew);end|Somep->beginself#navigatortrue(Somew);self#provewp;list#updatew;end(* -------------------------------------------------------------------------- *)(* --- Popup on Goals --- *)(* -------------------------------------------------------------------------- *)initializerbeginclear#set_enabledfalse;next#connectself#next;prev#connectself#prev;index#connect(fun()->card#set`List);list#on_click(funw_p->self#navigatortrue(Somew));list#on_right_click(funwp->beginself#navigatortrue(Somew);self#popupwp;list#updatew;end);list#on_double_clickself#action;list#on_selection(funn->clear#set_enabled(n>0));card#connect(fun_->self#details);scope#connectself#set_scope;popup#on_clickself#set_selection;popup#on_prove(GuiPanel.run_and_provemainprovers);clear#connectself#clear;endend(* -------------------------------------------------------------------------- *)(* --- Model Info for Variables --- *)(* -------------------------------------------------------------------------- *)letmodel_varinfo:GMenu.menuGMenu.factory->Design.main_window_extension_points->button:int->Pretty_source.localizable->unit=fun_menumain~buttonitem->letopenCil_typesinmatchitemwith|PLval(Somekf,_,(Varx,NoOffset))|PTermLval(Somekf,_,_,(TVar{lv_origin=Somex},TNoOffset))whenbutton=1&&RefUsage.is_computed()->beginletinit=CfgInfos.is_entry_pointkfinletacc=RefUsage.get~kf~initxinletmodel=matchaccwith|RefUsage.NoAccess->"any"|RefUsage.ByValue->"'var'"|RefUsage.ByRef->"'ref'"|RefUsage.ByArraywhenx.vformal&&Cil.isPointerTypex.vtype->"'caveat'"|_->"'typed'"inmain#pretty_information"Is is accessed as %t and fits in %s wp-model@."(RefUsage.printxacc)model;end|_->()(* -------------------------------------------------------------------------- *)(* --- Make Panel and Extend Frama-C GUI --- *)(* -------------------------------------------------------------------------- *)letmake(main:main_window_extension_points)=begin(* -------------------------------------------------------------------------- *)(* --- Provers --- *)(* -------------------------------------------------------------------------- *)letprovers=newGuiConfig.proversinletdp_chooser=newGuiConfig.dp_chooser~main~proversin(* -------------------------------------------------------------------------- *)(* --- Focus Bar --- *)(* -------------------------------------------------------------------------- *)letscope=newWidget.menu~default:`Module~options:[`All,"Global";`Module,"Module";`Select,"Property";]()inletfilter=newWidget.menu~default:`ToProve~options:[`ToProve,"Not Proved (yet)";`Scripts,"All Scripts";`Smoke,"Smoke Tests";`All,"All Goals";]()inletprev=newWidget.button~icon:`GO_BACK~tooltip:"Previous goal"()inletnext=newWidget.button~icon:`GO_FORWARD~tooltip:"Next goal"()inletindex=newWidget.button~icon:`INDEX~tooltip:"List of goals"()inletnavigation=Wbox.hgroup[(prev:>widget);(index:>widget);(next:>widget);]inletpvrs=newWidget.button~label:"Provers..."()inletclear=newWidget.button~label:"Clear"~icon:`DELETE()inletfocusbar=GPack.hbox~spacing:0()inbeginfocusbar#pack~padding:0~expand:falsenavigation#coerce;focusbar#pack~padding:20~expand:falsescope#coerce;focusbar#pack~padding:20~expand:falsefilter#coerce;focusbar#pack~from:`END~expand:falseclear#coerce;focusbar#pack~from:`END~expand:falsepvrs#coerce;pvrs#connectdp_chooser#run;end;(* -------------------------------------------------------------------------- *)(* --- List/Goal view --- *)(* -------------------------------------------------------------------------- *)letbook=newWpane.notebook~default:`List()inletlist=newGuiList.paneproversinletgoal=newGuiGoal.paneproversinbeginbook#add`Listlist#coerce;book#add`Goalgoal#coerce;end;(* -------------------------------------------------------------------------- *)(* --- Source Feedback --- *)(* -------------------------------------------------------------------------- *)letsource=newGuiSource.highlightermaininletpopup=newGuiSource.popup()in(* -------------------------------------------------------------------------- *)(* --- Panel Behavior --- *)(* -------------------------------------------------------------------------- *)letcard=(book:>_Widget.selector)inletscope=(scope:>_Widget.selector)inletfilter=(filter:>_Widget.selector)inletbehavior=newbehavior~main~next~prev~index~scope~filter~clear~list~provers~card~goal~source~popupinGuiPanel.on_reloadbehavior#reload;GuiPanel.on_updatebehavior#update;(* -------------------------------------------------------------------------- *)(* --- Panel view --- *)(* -------------------------------------------------------------------------- *)letpanel=GPack.vbox~homogeneous:false()inpanel#pack~expand:falsefocusbar#coerce;panel#pack~expand:true~fill:truebook#coerce;lettab_label=(GMisc.label~text:"WP Goals"())#coerceinignore(panel#misc#connect#after#realize~callback:behavior#reload);ignore(main#lower_notebook#append_page~tab_labelpanel#coerce);main#register_source_highlightersource#highlight;main#register_source_selectorpopup#register;main#register_source_selectormodel_varinfo;GuiPanel.register~main~configure_provers:dp_chooser#run;endlet()=Design.register_extensionmakelet()=Design.register_reset_extension(funmain->main#protect~cancelable:falseGuiPanel.reload)