123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588(**************************************************************************)(* *)(* 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.FmoduleF=Lang.FmoduleEnv=Plang.EnvmoduleImap=Qed.Intmaptype'aprinter=Format.formatter->'a->unittypev_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(* --- Hypotheses 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.Emptyinletlookup_predsap=ifF.is_subterma(F.e_propp)thenbeginpool:=Tactical.(Inside(Steps,a));raiseExit;endinletreclookup_sequenceahs=(*TODO: staged iter *)Conditions.iter(funstep->matchstep.conditionwith|(Typep|Initp|Havep|Whenp|Corep)->lookup_predstepap|Branch(p,sa,sb)->lookup_predstepap;lookup_sequenceasa;lookup_sequenceasb;|Eithercs->List.iter(lookup_sequencea)cs|State_->())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_wrapper=objectmethodwrap:termprinter->termprinterendclasstypeterm_selection=objectmethodis_focused:term->boolmethodis_visible:term->boolmethodis_targeted:term->boolendclassplang~(terms:#term_wrapper)~(focus:#term_wrapper)~(target:#term_wrapper)~(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_closedethenterms#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(* -------------------------------------------------------------------------- *)(* --- Condition Engine --- *)(* -------------------------------------------------------------------------- *)classtypepart_marker=objectmethodwrap:partprinter->partprintermethodmark:'a.part->'aprinter->'aprinterendclasstypestep_selection=objectmethodis_visible:F.term->boolmethodis_visible_step:step->boolendclasspcond~(parts:#part_marker)~(target:#part_marker)~(autofocus:#step_selection)~(plang:#Pcond.state)=object(self)inheritPcond.seqengineplangassuper(* All displayed entries *)valmutabledomain=Vars.emptyvalmutableellipsed=falsevalmutabletgt:part=Term(* empty *)methodset_targetp=tgt<-p(* Step Visibility Management *)methodvisiblestep=autofocus#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|_->parts#mark(Stepstep)super#pp_stepfmtstependelse(ifnotellipsedthenFormat.fprintffmt"@ [...]";ellipsed<-true)method!pp_goalfmtgoal=matchtgtwith|Goal->target#markGoalsuper#pp_goalfmtgoal|_->parts#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=domain<-Vars.empty;super#set_sequencehyps;ifself#get_statethenbeginself#domainhyps;plang#set_domaindomain;endend(* -------------------------------------------------------------------------- *)(* --- Sequent Engine --- *)(* -------------------------------------------------------------------------- *)typetarget=part*F.termoptiontypefocus=[`Transient|`Select|`Focus|`Extend|`Reset]classpseq~(autofocus:#autofocus)~(plang:#plang)~(pcond:#pcond)=object(self)valmutabledemon=[]valmutablesequent=Conditions.empty,F.p_truevalmutableselected_term=Nonevalmutableselected_part=Termmethodreset=selected_term<-None;selected_part<-Term;autofocus#resetmethodget_focus_mode=autofocus#get_autofocusmethodset_focus_mode=autofocus#set_autofocusmethodget_state_mode=pcond#get_statemethodset_state_mode=pcond#set_statemethodset_unmangledm=pcond#set_state(notm)methodset_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]methodprivateconvertpartterm=letinsideclauset=ifF.p_boolt==Tactical.headclausethenTactical.(Clauseclause)elseTactical.(Inside(clause,t))inmatchpart,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)tmethodtarget=selected_part,selected_termmethodresolve(p,t)=self#convertptmethodselection=self#convertselected_partselected_termmethodunselect=beginletp=selected_partinselected_part<-Term;lett=selected_terminselected_term<-None;autofocus#unfocus_last;p,tendmethodrestore~(focus:focus)(p,t)=beginselected_part<-p;selected_term<-t;letselected=matchfocuswith|`Transient->false|`Select->true|`Focus->Option.iter(autofocus#focus~extend:false)t;true|`Extend->Option.iter(autofocus#focus~extend:true)t;false|`Reset->autofocus#reset;trueinifselectedthenself#selectedendmethodset_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;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_sequentfmts=sequent<-s;ifautofocus#set_sequentsthenbeginselected_term<-None;selected_part<-Term;end;letenv=autofocus#envinifpcond#get_statethenEnv.set_indexed_varsenv;pcond#pp_esequentenvfmtsmethodpp_goalfmtw=Format.fprintffmt"@\n@{<wp:clause>Goal@} %a:@\n"Wpo.pp_titlew;let_,sequent=Wpo.computewinself#pp_sequentfmtsequentend(* -------------------------------------------------------------------------- *)