123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(** This file defines the datatypes used as internal states by the
tactic monad, and specialises the [Logic_monad] to these type. *)(** {6 Trees/forest for traces} *)moduleTrace=struct(** The intent is that an ['a forest] is a list of messages of type
['a]. But messages can stand for a list of more precise
messages, hence the structure is organised as a tree. *)type'aforest='atreelistand'atree=Seqof'a*'aforest(** To build a trace incrementally, we use an intermediary data
structure on which we can define an S-expression like language
(like a simplified xml except the closing tags do not carry a
name). Note that nodes are built from right to left in ['a
incr], the result is mirrored when returning so that in the
exposed interface, the forest is read from left to right.
Concretely, we want to add a new tree to a forest: and we are
building it by adding new trees to the left of its left-most
subtrees which is built the same way. *)type'aincr={head:'aforest;opened:'atreelist}(** S-expression like language as ['a incr] transformers. It is the
responsibility of the library builder not to use [close] when no
tag is open. *)letempty_incr={head=[];opened=[]}letopna{head;opened}={head;opened=Seq(a,[])::opened}letclose{head;opened}=matchopenedwith|[a]->{head=a::head;opened=[]}|a::Seq(b,f)::opened->{head;opened=Seq(b,a::f)::opened}|[]->assertfalseletleafas=close(opnas)(** Returning a forest. It is the responsibility of the library
builder to close all the tags. *)(* spiwack: I may want to close the tags instead, to deal with
interruptions. *)letrecmirrorf=List.rev_mapmirror_treefandmirror_tree(Seq(a,f))=Seq(a,mirrorf)letto_tree=function|{head;opened=[]}->mirrorhead|{head;opened=_::_}->assertfalseend(** {6 State types} *)(** We typically label nodes of [Trace.tree] with messages to
print. But we don't want to compute the result. *)typelazy_msg=unit->Pp.t(** Info trace. *)moduleInfo=struct(** The type of the tags for [info]. *)typetag=|Msgoflazy_msg(** A simple message *)|Tacticoflazy_msg(** A tactic call *)|Dispatch(** A call to [tclDISPATCH]/[tclEXTEND] *)|DBranch(** A special marker to delimit individual branch of a dispatch. *)typestate=tagTrace.incrtypetree=tagTrace.forestletpr_in_commentsm=Pp.(str"(* "++m()++str" *)")letunbranch=function|Trace.Seq(DBranch,brs)->brs|_->assertfalseletis_empty_branch=letopenTraceinfunction|Seq(DBranch,[])->true|_->false(** Dispatch with empty branches are (supposed to be) equivalent to
[idtac] which need not appear, so they are removed from the
trace. *)letdispatchbrs=letopenTraceinifCList.for_allis_empty_branchbrsthenNoneelseSome(Seq(Dispatch,brs))letconstr=letopenTraceinfunction|Dispatch->dispatch|t->funbr->Some(Seq(t,br))letreccompress_tree=letopenTraceinfunction|Seq(t,f)->constrt(compressf)andcompressf=CList.map_filtercompress_treef(** [with_sep] is [true] when [Tactic m] must be printed with a
trailing semi-colon. *)letrecpr_treewith_sep=letopenTraceinfunction|Seq(Msgm,[])->pr_in_commentsm|Seq(Tacticm,_)->lettail=ifwith_septhenPp.str";"elsePp.mt()inPp.(m()++tail)|Seq(Dispatch,brs)->lettail=ifwith_septhenPp.str";"elsePp.mt()inPp.(pr_dispatchbrs++tail)|Seq(Msg_,_::_)|Seq(DBranch,_)->assertfalseandpr_dispatchbrs=letopenPpinletbrs=List.mapunbranchbrsinmatchbrswith|[br]->pr_forestbr|_->letsep()=spc()++str"|"++spc()inletbranches=prlist_with_sepseppr_forestbrsinstr"[>"++spc()++branches++spc()++str"]"andpr_forest=function|[]->Pp.mt()|[tr]->pr_treefalsetr|tr::l->Pp.(pr_treetruetr++pr_forestl)letprint_env_sigmaf=pr_forest(compressf)letreccollapse_treent=letopenTraceinmatchn,twith|0,t->[t]|_,(Seq(Tactic_,[])ast)->[t]|n,Seq(Tactic_,f)->collapse(predn)f|n,Seq(Dispatch,brs)->[Seq(Dispatch,(collapsenbrs))]|n,Seq(DBranch,br)->[Seq(DBranch,(collapsenbr))]|_,(Seq(Msg_,_)ast)->[t]andcollapsenf=CList.map_append(collapse_treen)fendmoduleStateStore=Store.Make()(* let (set_state, get_state) = StateDyn.Easy.make_dyn "goal_state" *)typegoal=Evar.ttypegoal_with_state=Evar.t*StateStore.tletdrop_state=fstletget_state=sndletgoal_with_stategs=(g,s)letwith_empty_stateg=(g,StateStore.empty)letmap_goal_with_statef(g,s)=(fg,s)(** Type of proof views: current [evar_map] together with the list of
focused goals. *)typeproofview={solution:Evd.evar_map;comb:goal_with_statelist;}(** {6 Instantiation of the logic monad} *)(** Parameters of the logic monads *)moduleP=structtypes=proofview*Environ.env(** Recording info trace (true) or not. *)typee={trace:bool;name:Names.Id.t;poly:bool}(** Status (safe/unsafe) * shelved goals * given up *)typew=boolletwunit=trueletwprodb1b2=b1&&b2typeu=Info.stateletuunit=Trace.empty_increndmoduleLogical=Logic_monad.Logical(P)(** {6 Lenses to access to components of the states} *)moduletypeState=sigtypetvalget:tLogical.tvalset:t->unitLogical.tvalmodify:(t->t)->unitLogical.tendmoduletypeReader=sigtypetvalget:tLogical.tendmoduletypeWriter=sigtypetvalput:t->unitLogical.tendmodulePv:Statewithtypet:=proofview=structletget=Logical.(mapfstget)letsetp=Logical.modify(fun(_,e)->(p,e))letmodifyf=Logical.modify(fun(p,e)->(fp,e))endmoduleSolution:Statewithtypet:=Evd.evar_map=structletget=Logical.map(fun{solution}->solution)Pv.getletsets=Pv.modify(funpv->{pvwithsolution=s})letmodifyf=Pv.modify(funpv->{pvwithsolution=fpv.solution})endmoduleComb:Statewithtypet=goal_with_statelist=struct(* spiwack: I don't know why I cannot substitute ([:=]) [t] with a type expression. *)typet=goal_with_statelistletget=Logical.map(fun{comb}->comb)Pv.getletsetc=Pv.modify(funpv->{pvwithcomb=c})letmodifyf=Pv.modify(funpv->{pvwithcomb=fpv.comb})endmoduleEnv:Statewithtypet:=Environ.env=structletget=Logical.(mapsndget)letsete=Logical.modify(fun(p,_)->(p,e))letmodifyf=Logical.modify(fun(p,e)->(p,fe))endmoduleStatus:Writerwithtypet:=bool=structletputs=Logical.putsend(** Lens and utilities pertaining to the info trace *)moduleInfoL=structletrecording=Logical.(map(fun{P.trace}->trace)current)letif_recordingt=letopenLogicalinrecording>>=funr->ifrthentelsereturn()letrecord_tracet=Logical.(current>>=funs->local{swithP.trace=true}t)letraw_update=Logical.updateletupdatef=if_recording(raw_updatef)letopna=update(Trace.opna)letclose=updateTrace.closeletleafa=update(Trace.leafa)lettagat=letopenLogicalinrecording>>=funr->ifrthenbeginraw_update(Trace.opna)>>t>>=funa->raw_updateTrace.close>>returnaendelsetend