123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)openConditionsopenLang.Ftypeenv=Plang.Env.tmoduleF=Lang.FmoduleEnv=Plang.EnvmoduleImap=Qed.Intmaptype'aprinter='aQed.Plib.printertypev_fold=[`Auto|`Visible|`Hidden]typev_term=[v_fold|`Shared|`Nameofstring]typepart=Term|Goal|Stepofstep[@@@warning"-32"]letpp_partfmt=function|Term->Format.fprintffmt"Term"|Goal->Format.fprintffmt"Goal"|Steps->Format.fprintffmt"Step #%d"s.idletpp_termfmte=Format.fprintffmt"E%03d"(F.QED.ide)letpp_targetfmt=function|None->Format.pp_print_stringfmt"-"|Somee->Format.fprintffmt"T%03d"(F.QED.ide)letpp_foldfmtu=Format.pp_print_stringfmt(matchuwith`Auto->"auto"|`Fold->"fold"|`Unfold->"unfold")[@@@warning"+32"](* -------------------------------------------------------------------------- *)(* --- Focus --- *)(* -------------------------------------------------------------------------- *)classautofocus=object(self)valmutableautofocus=true(* Term Visibility (forced by user) *)valmutablevterm:v_termTmap.t=Tmap.empty(* Step Visibility (forced by user) *)valmutablevstep:v_foldImap.t=Imap.empty(* Focused Terms ; lastly selected at head *)valmutablefocusring=[]valmutabletarget=F.e_true(* Memoization of focused terms and steps occurrence *)valmutableoccurs_term:boolTmap.t=Tmap.emptyvalmutableoccurs_step:boolImap.t=Imap.empty(* Currently displayed sequent *)valmutablesequent:Conditions.sequentoption=Nonemethodclear=beginsequent<-None;self#reset;endmethodreset=beginfocusring<-[];vterm<-Tmap.empty;vstep<-Imap.empty;self#clear_cache;endmethodprivateclear_cache=beginoccurs_term<-Tmap.empty;occurs_step<-Imap.empty;endmethodprivateclear_steps=occurs_step<-Imap.empty(* --- Environment --- *)methodenv=letenv=Env.create()inTmap.iter(funtv->matchvwith|`Auto->()|`Hidden->Env.defineenv"..."t|`Visible->Env.unfoldenvt|`Shared->letbase=F.basenametinletsanitizer=Plang.sanitizerinEnv.defineenv(Env.freshenv~sanitizerbase)t|`Namex->Env.defineenvxt)vterm;env(* --- Term Occurrence --- *)methodprivateoccurs_terme=tryTmap.findeoccurs_termwithNot_found->letoccurs=tryifList.memqefocusringthenraiseExit;ife!=F.e_true&&e==targetthenraiseExit;F.lc_iter(fune->ifself#occurs_termethenraiseExit)e;falsewithExit->trueinoccurs_term<-Tmap.addeoccursoccurs_term;occursmethodprivateoccurs_seqseq=tryConditions.iter(funs->ifself#occurs_stepsthenraiseExit)seq;falsewithExit->truemethodprivateoccurs_states=tryMstate.iter(fun_mv->ifself#occurs_termvthenraiseExit)s;falsewithExit->truemethodprivateoccurs_stepstep=trystep.id<0(* defensive *)||Imap.findstep.idoccurs_stepwithNot_found->letoccurs=matchstep.conditionwith|When_->true|States->self#occurs_states|Initp|Havep|Typep|Corep->self#occurs_term(F.e_propp)|Branch(p,sa,sb)->self#occurs_term(F.e_propp)||self#occurs_seqsa||self#occurs_seqsb|Eithercs->List.existsself#occurs_seqcsinoccurs_step<-Imap.addstep.idoccursoccurs_step;occurs(* --- Term Visibility --- *)methodset_termt=function|`Auto->ifTmap.memtvtermthen(vterm<-Tmap.removetvterm;self#clear_cache)|v->letsame=tryv=Tmap.findtvtermwithNot_found->falseinifnotsamethen(vterm<-Tmap.addtvvterm;self#clear_cache)methodget_termt=tryTmap.findtvtermwithNot_found->`Automethodset_targete=target<-emethodclear_target=target<-F.e_truemethodfocus~extende=ifF.lc_closedethenbeginletring=ifextendthen(List.filter(fune0->e0!=e)focusring)else[]infocusring<-e::ring;self#clear_cache;endmethodunfocuse=beginfocusring<-List.filter(fune0->e0!=e)focusring;self#clear_cache;endmethodunfocus_last=beginmatchfocusringwith|[]->()|_::es->focusring<-es;self#clear_cacheendmethodis_selectede=matchfocusringwithe0::_->e0==e|[]->falsemethodis_focusede=List.memqefocusringmethodis_visiblee=ifautofocusthenself#occurs_termeelsetruemethodis_targetede=autofocus&&self#occurs_termemethodset_autofocusflag=autofocus<-flag;ifflagthenself#clear_cacheelseself#resetmethodget_autofocus=autofocusmethodis_autofocused=autofocus&&Tmap.is_emptyvterm(* --- Sequent Management --- *)methodset_steps=function|`Auto->ifImap.mems.idvstepthen(vstep<-Imap.removes.idvstep;self#clear_steps)|v->letsame=tryv=Imap.finds.idvstepwithNot_found->falseinifnotsamethen(vstep<-Imap.adds.idvvstep;self#clear_steps)methodget_steps=tryImap.finds.idvstepwithNot_found->`Automethodis_visible_step(s:step)=matchself#get_stepswith|`Auto->ifautofocusthenself#occurs_stepselsetrue|`Visible->true|`Hidden->falsemethodlocatea=matchsequentwith|None->Tactical.Empty|Some(hs,goal)->ifF.is_subterma(F.e_propgoal)thenTactical.(Inside(Goalgoal,a))elseletpool=refTactical.Emptyinletreclookup_sequenceahs=Conditions.iter(funstep->matchstep.conditionwith|(Havep|Whenp|Branch(p,_,_))whenF.is_subterma(F.e_propp)->pool:=Tactical.(Inside(Stepstep,a));raiseExit|Branch(_,sa,sb)->lookup_sequenceasa;lookup_sequenceasb;|Eithercs->List.iter(lookup_sequencea)cs|State_|Type_|Init_|Have_|When_|Core_->())hsin(trylookup_sequenceahswithExit->());!pool(* ---- Global ----- *)methodset_sequent(s:sequent)=letupdated=matchsequentwithNone->true|Somes0->s0!=sinifupdatedthenbeginsequent<-Somes;Conditions.indexs;vstep<-Imap.empty;self#clear_cache;end;updatedend(* -------------------------------------------------------------------------- *)(* --- Term Engine --- *)(* -------------------------------------------------------------------------- *)classtypeterm_selection=objectmethodis_focused:term->boolmethodis_visible:term->boolmethodis_targeted:term->boolendclassplang~(term:termWtext.marker)~(focus:termWtext.marker)~(target:termWtext.marker)(autofocus:term_selection)=object(self)inheritPcond.stateassupermethod!shareablee=autofocus#is_targetede||super#shareableevalmutabletgt=F.e_truemethodset_targett=tgt<-tmethodclear_target=tgt<-F.e_truemethodprivatewrapppfmte=ife!=F.e_true&&e==tgtthentarget#wrapppfmteelseifautofocus#is_focusedethenfocus#wrapppfmteelseifF.lc_closedethenterm#wrapppfmteelseppfmtemethod!pp_atfmtlbl=Format.fprintffmt"@{<wp:label>@@%a@}"super#pp_labellblmethod!pp_labelfmtlbl=Format.fprintffmt"@{<wp:label>%a@}"super#pp_labellblmethod!pp_varfmtx=Format.fprintffmt"@{<wp:var>%s@}"xmethod!pp_flowfmte=self#wrapsuper#pp_flowfmtemethod!pp_atomfmte=self#wrapsuper#pp_atomfmteend(* -------------------------------------------------------------------------- *)(* --- Sequent Engine --- *)(* -------------------------------------------------------------------------- *)classtypestep_selection=objectmethodis_visible:term->boolmethodis_visible_step:step->boolendclasspcond~(part:partWtext.marker)~(target:partWtext.marker)(focus:step_selection)(plang:Pcond.state)=object(self)inheritPcond.seqengineplangassuper(* All displayed entries *)valmutabledomain=Vars.emptyvalmutableellipsed=falsevalmutableparts:partWtext.entrylist=[]valmutabletgt:part=Term(* empty *)(* Register displayed entries *)initializerpart#on_add(funentry->parts<-entry::parts)methodset_targetp=tgt<-pmethodpartpq=trylet(_,_,part)=List.find(fun(a,b,_)->a<=p&&q<=b)(List.revparts)inpart(* find the tightest step, which was added first *)withNot_found->Term(* Step Visibility Management *)methodvisiblestep=focus#is_visible_stepstep||matchtgtwith|Term|Goal->false|Steps->s.id=step.idmethodprivatedomainseq=Conditions.iter(funstep->ifself#visiblestep&¬(Vars.subsetstep.varsdomain)thenbeginmatchstep.conditionwith|State_->()|Havep|Initp|Corep|Whenp|Typep->domain<-Vars.union(F.varspp)domain|Branch(p,a,b)->domain<-Vars.union(F.varspp)domain;self#domaina;self#domainb|Eithercs->List.iterself#domaincsend)seq(* local-variable marking ; not hover/clickable marks *)method!mark(m:F.marks)s=ifself#visiblesthensuper#markmsmethod!pp_stepfmtstep=ifself#visiblestepthenbeginellipsed<-false;matchtgtwith|Step{condition=State_}->super#pp_stepfmtstep|Stepswhens==step->target#mark(Stepstep)super#pp_stepfmtstep|_->part#mark(Stepstep)super#pp_stepfmtstependelse(ifnotellipsedthenFormat.fprintffmt"@ [...]";ellipsed<-true)method!pp_goalfmtgoal=matchtgtwith|Goal->target#markGoalsuper#pp_goalfmtgoal|_->part#markGoalsuper#pp_goalfmtgoalmethod!pp_block~clausefmtseq=tryConditions.iter(funstep->ifself#visiblestepthenraiseExit)seq;Format.fprintffmt"@ %a { ... }"self#pp_clauseclausewithExit->beginellipsed<-false;super#pp_block~clausefmtseq;ellipsed<-false;end(* Global Call *)method!set_sequencehyps=parts<-[];domain<-Vars.empty;super#set_sequencehyps;ifself#get_statethenbeginself#domainhyps;plang#set_domaindomain;endend(* -------------------------------------------------------------------------- *)(* --- Printer --- *)(* -------------------------------------------------------------------------- *)typetarget=part*F.termoptionclassfocused(wtext:Wtext.text)=letparts:partWtext.marker=wtext#markerinletterms:termWtext.marker=wtext#markerinletfocus:termWtext.marker=wtext#markerinletbutton:(unit->unit)Wtext.marker=wtext#markerinlettarget_term:termWtext.marker=wtext#markerinlettarget_part:partWtext.marker=wtext#markerinletautofocus=newautofocusinletterm_selection=(autofocus:>term_selection)inletstep_selection=(autofocus:>step_selection)inletplang=newplang~term:terms~focus:focus~target:target_termterm_selectioninletpcond=newpcond~part:parts~target:target_partstep_selection(plang:>Pcond.state)inletpopup=newWidget.popup()inobject(self)valmutabledemon=[]valmutableitems=[]valmutablesequent=Conditions.empty,F.p_truevalmutableselected_term=Nonevalmutableselected_part=Termvalmutabletargeted=[]initializerbeginwtext#set_font"Monospace";wtext#set_css["wp:clause",[`WEIGHT`BOLD];"wp:comment",[`FOREGROUND"darkgreen"];"wp:property",[`FOREGROUND"blue"];"wp:label",[`FOREGROUND"darkgreen"];"wp:stmt",[`WEIGHT`BOLD;`FOREGROUND"darkgreen"];"wp:var",[`STYLE`ITALIC];];terms#set_hover[`BACKGROUND"lightblue"];parts#set_hover[`BACKGROUND"lightgreen"];focus#set_style[`BACKGROUND"wheat"];button#set_style[`BACKGROUND"lightblue"];button#set_hover[`BACKGROUND"orange"];button#on_click(fun(_,_,cb)->cb());target_part#set_style[`BACKGROUND"orange"];target_term#set_style[`BACKGROUND"orange"];parts#on_clickself#on_part;parts#on_right_clickself#on_popup_part;terms#on_click(self#on_term~extend:false);terms#on_shift_click(self#on_term~extend:true);terms#on_right_clickself#on_popup_term;focus#on_clickself#on_select;focus#on_right_clickself#on_popup_term;target_part#on_right_clickself#on_popup_part;target_term#on_right_clickself#on_popup_term;target_part#on_add(fun(p,q,_)->self#added_zonepq);target_term#on_add(fun(p,q,_)->self#added_zonepq);endmethodreset=selected_term<-None;selected_part<-Term;targeted<-[];autofocus#resetmethodprivateadded_zonepq=targeted<-(p,q)::targetedmethodprivatetarget_zone=tryList.find(fun(p,q)->matchselected_part,pcond#partpqwith|Goal,Goal->true|Steps,Steps'->s.id=s'.id|_->false)targetedwithNot_found->0,0methodget_focus_mode=autofocus#get_autofocusmethodset_focus_mode=autofocus#set_autofocusmethodget_state_mode=pcond#get_statemethodset_state_mode=pcond#set_statemethodset_iformat=plang#set_iformatmethodget_iformat=plang#get_iformatmethodset_rformat=plang#set_rformatmethodget_rformat=plang#get_rformatmethodselected=beginself#set_targetself#selection;List.iter(funf->f())demon;endmethodon_selectionf=demon<-demon@[f]methodon_popup(f:Widget.popup->unit)=items<-items@[f]methodprivateitem~label~callback=letcallback()=let()=callback()inself#selectedinpopup#add_item~label~callbackmethodprivatepopup_terme=matchautofocus#get_termewith|`Auto->beginifautofocus#is_focusedethenself#item~label:"Un-focus Term"~callback:(fun()->autofocus#unfocuse);self#item~label:"Hide Term"~callback:(fun()->autofocus#set_terme`Hidden);self#item~label:"Don't Share"~callback:(fun()->autofocus#set_terme`Visible);end|`Hidden->self#item~label:"Show Term"~callback:(fun()->autofocus#set_terme`Auto)|`Visible|`Name_|`Shared->self#item~label:"Autofocus"~callback:(fun()->autofocus#set_terme`Auto)methodprivatepopup_part=function|Goal|Term->self#item~label:"Reset Autofocus"~callback:(fun()->autofocus#reset)|Stepstep->ifautofocus#is_visible_stepstepthenself#item~label:"Hide Clause"~callback:(fun()->autofocus#set_stepstep`Hidden)elseself#item~label:"Show Clause"~callback:(fun()->autofocus#set_stepstep`Visible)methodpopup=beginpopup#clear;beginmatchselected_termwith|Somee->self#popup_terme|None->self#popup_partselected_partend;popup#add_separator;List.iter(funf->fpopup)items;popup#run();endmethodselection=letinsideclauset=ifF.p_boolt==Tactical.headclausethenTactical.(Clauseclause)elseTactical.(Inside(clause,t))inmatchselected_part,selected_termwith|Term,None->Tactical.Empty|Goal,None->Tactical.(Clause(Goal(sndsequent)))|Steps,None->Tactical.(Clause(Steps))|Term,Somet->autofocus#locatet|Goal,Somet->insideTactical.(Goal(sndsequent))t|Steps,Somet->insideTactical.(Steps)tmethodunselect=beginletp=selected_partinselected_part<-Term;lett=selected_terminselected_term<-None;autofocus#unfocus_last;p,tendmethodrestore(p,t)=beginselected_part<-p;selected_term<-t;self#set_targetself#selection;endmethodset_targettgt=matchtgtwith|Tactical.Empty|Tactical.Compose_|Tactical.Multi_->beginpcond#set_targetTerm;plang#clear_target;autofocus#clear_target;end|Tactical.Inside(_,t)->beginpcond#set_targetTerm;plang#set_targett;autofocus#set_targett;end|Tactical.Clause(Tactical.Goal_)->beginpcond#set_targetGoal;plang#clear_target;autofocus#clear_target;end|Tactical.Clause(Tactical.Steps)->beginpcond#set_target(Steps);plang#clear_target;autofocus#clear_target;endmethodprivateon_term~extend(p,q,e)=ifF.lc_closedethen(* defensive *)beginselected_term<-Somee;selected_part<-pcond#partpq;autofocus#focus~extende;self#selected;endmethodprivateon_select(p,q,e)=ifF.lc_closedethen(* defensive *)beginselected_term<-Somee;selected_part<-pcond#partpq;self#selected;endmethodprivateon_part(_,_,part)=beginselected_term<-None;selected_part<-part;autofocus#reset;self#selected;endmethodprivateon_popup_term(p,q,e)=ifF.lc_closedethen(* defensive *)beginselected_term<-Somee;selected_part<-pcond#partpq;self#popup;endmethodprivateon_popup_part(_,_,part)=beginselected_term<-None;selected_part<-part;self#popup;endmethodpp_termfmte=plang#pp_sortfmtemethodpp_predfmtp=plang#pp_predfmtpmethodpp_selectionfmt=function|Tactical.Empty->Format.fprintffmt" - "|Tactical.Compose(Tactical.Range(a,b))->Format.fprintffmt"%d..%d"ab|sel->self#pp_termfmt(Tactical.selectedsel)methodsequent=sequentmethodpp_sequentsfmt=sequent<-s;ifautofocus#set_sequentsthenbeginselected_term<-None;selected_part<-Term;end;targeted<-[];letenv=autofocus#envinifpcond#get_statethenEnv.set_indexed_varsenv;pcond#pp_esequentenvfmts;letp,q=self#target_zoneinifp>0&&q>pthen(Wutil.later(fun()->wtext#select~scroll:truepq))methodgoalwfmt=letopenWpoinmatchw.po_formulawith|GoalLemma_->Format.fprintffmt"@\n@{<wp:clause>Lemma@} %a:@\n"Wpo.pp_titlew;let_,sequent=Wpo.computewinself#pp_sequentsequentfmt|GoalAnnot_->Format.fprintffmt"@\n@{<wp:clause>Goal@} %a:@\n"Wpo.pp_titlew;let_,sequent=Wpo.computewinself#pp_sequentsequentfmtmethodbutton~title~callbackfmt=letpp_titlefmttitle=Format.fprintffmt" %s "titleinFormat.fprintffmt"[%a]"(button#markcallbackpp_title)titleend