123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)openTactical(* -------------------------------------------------------------------------- *)(* --- Composer --- *)(* -------------------------------------------------------------------------- *)classtypecomposer=objectmethodtitle:stringmethoddescr:stringmethodtarget:selectionmethodranged:boolmethodis_valid:selection->boolmethodget_value:selectionmethodset_value:selection->unitendclasstypebrowser=objectmethodtitle:stringmethoddescr:stringmethodtarget:selectionmethodsearch:(unitnamed->unit)->int->boolmethodchoose:stringoption->unitend(* -------------------------------------------------------------------------- *)(* --- Field Widget --- *)(* -------------------------------------------------------------------------- *)classvirtualwfield=object(self)methodwfield=(self:>wfield)valmutabletarget=Emptymethodtarget=targetmethodselecttgt=target<-tgtmethodcompose_with(_:composer->unit)=()methodbrowse_with(_:browser->unit)=()methodclear=self#reset;target<-Emptymethodvirtualreset:unitmethodvirtualconnect:(unit->unit)->unitmethodvirtualupdate:?enabled:bool->?title:string->?tooltip:string->?range:bool->?vmin:int->?vmax:int->?filter:(Lang.F.term->bool)->string->unitend(* -------------------------------------------------------------------------- *)(* --- Checkbox Widget --- *)(* -------------------------------------------------------------------------- *)classcheckbox(tac:Tactical.t)(form:Wpane.form)(field:boolfield)=lets=Tactical.signaturefieldinletbutton=newWidget.checkbox~label:s.title~tooltip:s.descr()inobjectinheritwfieldinitializerbeginform#add_field~field:`Compactbutton#coerce;button#connect(tac#set_fieldfield);endmethodreset=button#sets.valuemethodconnect=button#on_eventmethodupdate?enabled?title?tooltip?range?vmin?vmax?filterid=ifid=Tactical.identfieldthenbeginWutil.onenabledbutton#set_visible;Wutil.ontooltipbutton#set_tooltip;Wutil.ontitlebutton#set_label;ignorefilter;ignorevmin;ignorevmax;ignorerange;endend(* -------------------------------------------------------------------------- *)(* --- Spinner Widget --- *)(* -------------------------------------------------------------------------- *)classspinner(tac:Tactical.t)(form:Wpane.form)(field:intfield)(range:intrange)=lets=Tactical.signaturefieldinletspin=newWidget.spinner?min:range.vmin?max:range.vmax~step:range.vstep~value:s.value~tooltip:s.descr()inobjectinheritwfieldinitializerbeginform#add_field~label:s.title~field:`Compactspin#coerce;spin#connect(tac#set_fieldfield);endmethodreset=spin#sets.valuemethodconnect=spin#on_eventmethodupdate?enabled?title?tooltip?range?vmin?vmax?filterid=ifid=Tactical.identfieldthenbeginWutil.onenabledspin#set_visible;Wutil.ontooltipspin#set_tooltip;Wutil.onvminspin#set_min;Wutil.onvmaxspin#set_max;ignoretitle;ignorerange;ignorefilter;endend(* -------------------------------------------------------------------------- *)(* --- Composer Widget --- *)(* -------------------------------------------------------------------------- *)classmkcomposer(tac:Tactical.t)(form:Wpane.form)(field:selectionfield)(accept:Lang.F.term->bool)(pp:Format.formatter->Tactical.selection->unit)=lets=Tactical.signaturefieldinlethead=newWidget.label~style:`Label~align:`Left()inletedit=newWidget.button~icon:`EDIT~tooltip:s.descr()inlethbox=Wbox.(hbox[hhead;w~padding:8edit])inobject(self)inheritwfieldinitializerform#add_rowhbox#coercevalmutablewtitle=s.titlevalmutablewdescr=s.descrvalmutablewvalid=acceptvalmutableranged=falsevalmutabledemon=[]methodprivateupdated=matchtac#get_fieldfieldwith|Empty->Pretty_utils.ksfprintfhead#set_text"%s: -"wtitle|value->lettext=Format.asprintf"@[<hov 2>%s: %a@]"wtitleppvalueinletmsg=ifString.lengthtext<=20thentextelseString.subtext017^"..."inhead#set_textmsg(* --- Composer API ---- *)methodcomposer=(self:>composer)methodtitle=wtitlemethoddescr=wdescrmethodranged=rangedmethodis_valid=function|Empty->false|Compose(Range(a,b))->ranged&&(a<=b)|_ass->trywvalid(Tactical.selecteds)with_->falsemethodget_value=tac#get_fieldfieldmethodset_valuev=tac#set_fieldfieldv;self#updated;List.iter(funf->f())demonmethod!compose_withf=edit#connect(fun()->fself#composer)(* --- Wfield API ---- *)methodreset=wtitle<-s.title;wdescr<-s.descr;wvalid<-accept;tac#set_fieldfieldTactical.Empty;self#updatedmethodconnectf=demon<-demon@[f]methodupdate?enabled?title?tooltip?range?vmin?vmax?filterid=ifid=Tactical.identfieldthenbeginWutil.onenabledhbox#set_visible;Wutil.ontitle(funs->wtitle<-s);Wutil.ontooltip(fund->wdescr<-d);Wutil.onfilter(funf->wvalid<-f);Wutil.onrange(funr->ranged<-r);ignorevmin;ignorevmax;self#updatedendend(* -------------------------------------------------------------------------- *)(* --- Search Widget --- *)(* -------------------------------------------------------------------------- *)exceptionStopLookupclass['a]mksearch(tac:Tactical.t)(form:Wpane.form)(field:'anamedoptionfield)(browser:'aTactical.browser)=lets=Tactical.signaturefieldinlethead=newWidget.label~style:`Label~align:`Left()inletedit=newWidget.button~icon:`FIND~tooltip:s.descr()inlethbox=Wbox.(hbox[hhead;w~padding:8edit])inobject(self)inheritwfieldinitializerform#add_rowhbox#coerce;valmutablewtitle=s.titlevalmutablewdescr=s.descrvalitems:(string,'anamed)Hashtbl.t=Hashtbl.create7valmutabledemon=[]methodprivateupdated=matchtac#get_fieldfieldwith|None->Pretty_utils.ksfprintfhead#set_text"%s: -"wtitle|Someitem->beginlettext=item.titleinletmsg=ifString.lengthtext<=20thentextelseString.subtext017^"..."inhead#set_textmsg;head#set_tooltipitem.descr;end(* --- Browser API --- *)methodbrowser=(self:>browser)methodchooseitem=letvalue=matchitemwith|Someid->(trySome(Hashtbl.finditemsid)withNot_found->None)|None->Noneintac#set_fieldfieldvalue;self#updated;List.iter(funf->f())demonmethodsearchfn=letcount=refninHashtbl.clearitems;trybrowser(funitem->if!count<=0thenraiseStopLookup;Hashtbl.additemsitem.viditem;f{itemwithvalue=()};decrcount;)target;truewithStopLookup->falsemethod!browse_withf=edit#connect(fun()->fself#browser)(* --- Wfield API --- *)methodtitle=wtitlemethoddescr=wdescrmethodreset=wtitle<-s.title;wdescr<-s.descr;tac#set_fieldfieldNone;Hashtbl.clearitems;self#updated;methodconnectf=demon<-demon@[f]methodupdate?enabled?title?tooltip?range?vmin?vmax?filterid=ifid=Tactical.identfieldthenbeginWutil.onenabledhbox#set_visible;Wutil.ontitle(funs->wtitle<-s);Wutil.ontooltip(fund->wdescr<-d);ignorefilter;ignorerange;ignorevmin;ignorevmax;endend(* -------------------------------------------------------------------------- *)(* --- Selector Widget --- *)(* -------------------------------------------------------------------------- *)class['a]selector(tac:Tactical.t)(form:Wpane.form)(field:'afield)(options:'aTactical.namedlist)(equal:'a->'a->bool)=lets=Tactical.signaturefieldinletlookupa=tryList.find(funv->equalv.valuea)optionswithNot_found->{title="";descr="(unknown item)";vid="unknown";value=a}inletdefault=lookups.valueinletrenderitem=item.titleinletcombo=newWidget.menu~default~render~items:options()inobjectinheritwfieldinitializerbeginform#add_field~label:s.title~field:`Compactcombo#coerce;combo#connect(funopt->tac#set_fieldfieldopt.value);endmethodreset=combo#setdefaultmethodconnect=combo#on_eventmethodupdate?enabled?title?tooltip?range?vmin?vmax?filterid=ifid=Tactical.identfieldthenbeginWutil.onenabledcombo#widget#set_visible;Wutil.ontooltipcombo#set_tooltip;ignorefilter;ignoretitle;ignorevmin;ignorevmax;ignorerange;endend(* -------------------------------------------------------------------------- *)(* --- Dispatcher --- *)(* -------------------------------------------------------------------------- *)letwfieldtacformpp=function|Checkboxfd->(newcheckboxtacformfd)#wfield|Spinner(fd,r)->(newspinnertacformfdr)#wfield|Selector(fd,opt,eq)->(newselectortacformfdopteq)#wfield|Composer(fd,f)->(newmkcomposertacformfdfpp)#wfield|Search(fd,browser,_)->(newmksearchtacformfdbrowser)#wfield(* -------------------------------------------------------------------------- *)(* --- Tactic Widget --- *)(* -------------------------------------------------------------------------- *)typeedited={tree:ProofEngine.tree;target:selection;browser:(browser->unit);composer:(composer->unit);process:(tactical->selection->process->unit);}classtactic(tac:tactical)(pp:Format.formatter->Tactical.selection->unit)=letform=newWpane.form()inletdescr=newWidget.label~style:`Descr~width:24~align:`Left()inobject(self)valmutabletitle=tac#titlevalmutablewfields:wfieldlist=[]valmutableedited:editedoption=Nonevalmutablehints=Fmap.create()valmutableerror=falseinheritWpalette.tool~content:form#widget()asdongleinitializerbeginform#add_row~xpadding:4~ypadding:2~field:`Compactdescr#coerce;self#set_action();wfields<-List.map(wfieldtacformpp)tac#params;List.iter(funfd->fd#connectself#updated)wfields;List.iter(funfd->fd#compose_withself#compose)wfields;List.iter(funfd->fd#browse_withself#browse)wfields;self#set_tooltip(ifwfields=[]then"Tactic Details"else"Configure Tactic");end(* -------------------------------------------------------------------------- *)(* --- Panel API --- *)(* -------------------------------------------------------------------------- *)method!set_label=funmsg->title<-msg;dongle#set_labelmsgmethodset_title:'a.'aformatter=funmsg->Pretty_utils.ksfprintfself#set_labelmsgmethodset_descr:'a.'aformatter=funmsg->Pretty_utils.ksfprintfdescr#set_textmsg(* -------------------------------------------------------------------------- *)(* --- Feedback API --- *)(* -------------------------------------------------------------------------- *)methodpool=matcheditedwith|None->assertfalse|Some{tree}->ProofEngine.pooltreemethodinteractive=self#is_activemethodget_title=titlemethodhas_error=errormethodset_error:'a.'aformatter=beginfunmsg->error<-true;descr#set_fg(`NAME"red");Pretty_utils.ksfprintfdescr#set_textmsg;endmethodupdate_field:'a.?enabled:bool->?title:string->?tooltip:string->?range:bool->?vmin:int->?vmax:int->?filter:(Lang.F.term->bool)->'afield->unit=fun?enabled?title?tooltip?range?vmin?vmax?filterfield->letid=Tactical.identfieldinList.iter(fun(fd:wfield)->fd#update?enabled?title?tooltip?range?vmin?vmax?filterid)wfields(* -------------------------------------------------------------------------- *)(* --- Widget Behavior --- *)(* -------------------------------------------------------------------------- *)methodprivatereset_dongle=beginself#set_labeltac#title;descr#set_texttac#descr;iferrorthendescr#set_fg`NORMAL;error<-false;edited<-None;endmethodprivatereset_fields=List.iter(funfd->fd#clear)wfieldsmethodprivatecomposewidget=matcheditedwith|None->()|Someedited->self#set_action();edited.composerwidgetmethodprivatebrowsewidget=matcheditedwith|None->()|Someedited->self#set_action();edited.browserwidgetmethodprivateupdated()=matcheditedwith|None->()|Some{process;composer;browser;target;tree}->self#select~process~composer~browser~treetargetmethodclear=beginself#reset_dongle;self#reset_fields;self#set_status`FIND;self#set_action();endmethodtargeted=matcheditedwithNone->false|Some_->truemethodprivatestatustarget=List.iter(funfd->fd#selecttarget)wfields;tryLang.local~pool:self#pool(tac#select(self:>feedback))targetwithNot_found|Exit->Not_applicablemethodselect~process~browser~composer~tree(target:selection)=beginself#reset_dongle;edited<-Some{process;composer;browser;target;tree};letstatus=self#statustargetinmatchstatus,errorwith|Not_applicable,_->self#set_visiblefalse;self#set_status`FIND;self#set_action();|Not_configured,_|Applicable_,true->self#set_visibletrue;self#set_status`DIALOG_WARNING;self#set_action();|Applicableproc,false->self#set_visibletrue;self#set_status`APPLY;letcallback()=processtactargetprocinself#set_action~callback();endend(* -------------------------------------------------------------------------- *)(* --- Strategies --- *)(* -------------------------------------------------------------------------- *)moduleUser=Gtk_helper.Configurationtypehform={search:Strategy.heuristic;widget:Widget.checkbox;}lethcomparefg=String.comparef.search#titleg.search#titleletspinner~(form:Wpane.form)~default~label~tooltip=letconfig="wp.strategies."^labelinletvalue=User.find_int~defaultconfiginletspinner=newWidget.spinner~min:1~value~tooltip()inspinner#connect(User.set_intconfig);form#add_field~labelspinner#coerce;spinnerletcheckbox~(form:Wpane.form)~default~label~tooltip=letconfig="wp.strategies."^labelinletvalue=User.find_bool~defaultconfiginletcheckbox=newWidget.checkbox~label~tooltip()incheckbox#setvalue;checkbox#connect(User.set_boolconfig);form#add_field~labelcheckbox#coerce;checkboxtypeauto_callback=depth:int->width:int->Strategy.heuristiclist->unitclassautosearch()=letform=newWpane.form()inletdepth=spinner~form~default:1~label:"Depth"~tooltip:"Limit the number of nested strategies"inletwidth=spinner~form~default:16~label:"Width"~tooltip:"Limit the number of pending goals"inobject(self)inheritWpalette.tool~content:form#widget~label:"Auto"~tooltip:"Automated proof search (-wp-auto)"()valmutablehforms:hformlist=[]valmutabledemon:auto_callbackoption=Nonemethodregister(search:Strategy.heuristic)=beginletwidget=newWidget.checkbox~label:search#title~tooltip:search#descr()inletconfig="wp.strategies."^search#idinletdefault=User.find_bool~default:trueconfiginwidget#setdefault;widget#connect(User.set_boolconfig);widget#on_eventself#update;form#add_rowwidget#coerce;lethform={search;widget}inhforms<-List.mergehcompare[hform]hformsendmethodprivateupdate()=matchdemonwith|None->self#set_visiblefalse|Some_->self#set_visibletrue;ifList.exists(funh->h.widget#get)hformsthenbeginself#set_status`APPLY;self#set_action~callback:self#callback();endelsebeginself#set_status`INDEX;self#set_action()endmethodprivatecallback()=matchdemonwith|Somef->leths=List.fold_right(funhhs->ifh.widget#getthenh.search::hselsehs)hforms[]inf~depth:depth#get~width:width#geths|None->()methodconnectf=demon<-f;self#update()end(* -------------------------------------------------------------------------- *)(* --- Proof Strategies --- *)(* -------------------------------------------------------------------------- *)typecallback=(depth:int->ProofStrategy.strategyoption->unit)typestrategy={strategy:ProofStrategy.strategy;button:Widget.button;}classstrategies()=letform=newWpane.form()inletdepth=spinner~form~default:1~label:"Auto depth"~tooltip:"Depth of exploration"inlethints=checkbox~form~default:true~label:"Hints only"~tooltip:"Display hints for the current goal"inobject(self)inheritWpalette.tool~content:form#widget~label:"Strategies"~tooltip:"Run the full Proof Strategy Engine (-wp-strategy)"()valmutableregistered=falsevalmutableproofhints:ProofStrategy.strategylist=[]valmutablestrategies:strategylist=[]valmutablecallback:callbackoption=Noneinitializerhints#connect(fun_->self#update)methodregister(s:ProofStrategy.strategy)=beginregistered<-true;letlabel=ProofStrategy.namesinlettooltip=Format.asprintf"%a: strategy %s (single step)"Filepath.pp_pos(fst@@ProofStrategy.locs)labelinletbutton=newWidget.button~icon:`MEDIA_PLAY~label~tooltip()inbutton#set_visiblefalse;button#connect(self#strategys);endmethodconnect?(hints=[])(cb:callbackoption)=callback<-cb;proofhints<-hints;self#updatemethodprivatestrategy(s:ProofStrategy.strategy)()=Option.iter(funfn->fn~depth:depth#get(Somes))callbackmethodprivateexplore()=Option.iter(funfn->fn~depth:depth#getNone)callbackmethodprivatesetvisible?(filter=false)?(rank=0)(s:strategy)=letshow=notfilter||rank>0ins.button#set_visibleshow;ifshowthenletname=ProofStrategy.names.strategyinifrank=0thens.button#set_labelnameelsePretty_utils.ksfprintfs.button#set_label"%s (#%d)"namerankmethodprivatesetrank(s:strategy)=letfilter=hints#getinletrecapply(s:strategy)rank=function|[]->self#setvisibles~filter|h::hs->ifs.strategy==hthenself#setvisibles~rankelseself#setvisibles~filter;applys(succrank)hsinapplys1proofhintsmethodprivateupdate=ifcallback=None||notregisteredthenself#set_visiblefalseelsebeginself#set_visibletrue;self#set_status`APPLY;self#set_action~callback:self#explore();List.iterself#setrankstrategiesendend(* -------------------------------------------------------------------------- *)