123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189(************************************************************************)(* * 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) *)(************************************************************************)exceptionEmptyletinvalid_args=raise(Invalid_argument("Document."^s))type'asentence={mutablestate_id:Stateid.toption;data:'a}typeid=Stateid.tclasstype['a]signals=objectmethodpopped:callback:('a->('alist*'alist)option->unit)->unitmethodpushed:callback:('a->('alist*'alist)option->unit)->unitendclass['a]signal()=objectvalmutableattached:('a->unit)list=[]methodcall(x:'a)=letiterf=tryfxwith_->()inList.iteriterattachedmethodconnectf=attached<-f::attachedendtype'adocument={mutablestack:'asentencelist;mutablecontext:('asentencelist*'asentencelist)option;pushed_sig:('a*('alist*'alist)option)signal;popped_sig:('a*('alist*'alist)option)signal;}letconnectd:'asignals=objectmethodpushed~callback=d.pushed_sig#connect(fun(x,ctx)->callbackxctx)methodpopped~callback=d.popped_sig#connect(fun(x,ctx)->callbackxctx)endletcreate()={stack=[];context=None;pushed_sig=newsignal();popped_sig=newsignal();}letrepr_contexts=matchs.contextwith|None->None|Some(cl,cr)->letmaps=s.datainSome(List.mapmapcl,List.mapmapcr)(* Invariant, only the tip is a allowed to have state_id = None *)letinvariantl=l=[]||(List.hdl).state_id<>Nonelettip=function|{stack=[]}->raiseEmpty|{stack={state_id=Someid}::_}->id|{stack={state_id=None}::_}->invalid_arg"tip"lettip_data=function|{stack=[]}->raiseEmpty|{stack={data}::_}->dataletpushdx=assert(invariantd.stack);d.stack<-{data=x;state_id=None}::d.stack;d.pushed_sig#call(x,repr_contextd)letpop=function|{stack=[]}->raiseEmpty|{stack={data}::xs}ass->s.stack<-xs;s.popped_sig#call(data,repr_contexts);dataletfocusd~cond_top:c_start~cond_bot:c_stop=assert(invariantd.stack);ifd.context<>Nonetheninvalid_arg"focus";letrecaux(a,s,b)grab=function|[]->invalid_arg"focus"|{state_id=Someid;data}asx::xswhennotgrab->ifc_startiddatathenaux(a,s,b)true(x::xs)elseaux(x::a,s,b)grabxs|{state_id=Someid;data}asx::xs->ifc_stopiddatathenList.reva,List.rev(x::s),xselseaux(a,x::s,b)grabxs|_->assertfalseinleta,s,b=aux([],[],[])falsed.stackind.stack<-s;d.context<-Some(a,b)letunfocus=function|{context=None}->invalid_arg"unfocus"|{context=Some(a,b);stack}asd->assert(invariantstack);d.context<-None;d.stack<-a@stack@bletfocused{context}=context<>Noneletto_lists=function|{context=None;stack=s}->[],s,[]|{context=Some(a,b);stack=s}->a,s,bletflatfb=funx->fbx.state_idx.dataletfinddf=leta,s,b=to_listsdin(tryList.find(flatffalse)awithNot_found->tryList.find(flatftrue)swithNot_found->List.find(flatffalse)b).dataletfind_mapdf=leta,s,b=to_listsdintryCList.find_map(flatffalse)awithNot_found->tryCList.find_map(flatftrue)swithNot_found->CList.find_map(flatffalse)bletis_empty=function|{stack=[];context=None}->true|_->falseletcontextd=lettop,_,bot=to_listsdinletpair_xy=tryOption.getx,ywithOption.IsNone->assertfalseinList.map(flatpairtrue)top,List.map(flatpairtrue)botletstateid_opt_equal=Option.equalStateid.equalletis_in_focusdid=let_,focused,_=to_listsdinList.exists(fun{state_id}->stateid_opt_equalstate_id(Someid))focusedletprintdf=lettop,mid,bot=to_listsdinletopenPpinv0(List.fold_right(funiacc->acc++cut()++flatffalsei)top(List.fold_right(funiacc->acc++cut()++flatftruei)mid(List.fold_right(funiacc->acc++cut()++flatffalsei)bot(mt()))))letassign_tip_iddid=matchdwith|{stack={state_id=None}astop::_}->top.state_id<-Someid|_->invalid_arg"assign_tip_id"letcut_atdid=letaux(n,zone){state_id;data}=ifstateid_opt_equalstate_id(Someid)thenCSig.Stop(n,zone)elseCSig.Cont(n+1,data::zone)inletn,zone=CList.fold_left_untilaux(0,[])d.stackinfor_i=1tondoignore(popd)done;List.revzoneletfind_iddf=lettop,focus,bot=to_listsdinletpred=function|{state_id=Someid;data}whenfiddata->Someid|_->NoneintryCList.find_mappredtop,truewithNot_found->tryCList.find_mappredfocus,falsewithNot_found->CList.find_mappredbot,trueletbefore_tipd=let_,focused,rest=to_listsdinmatchfocusedwith|_::{state_id=Someid}::_->id,false|_::{state_id=None}::_->assertfalse|[]->raiseNot_found|[_]->matchrestwith|{state_id=Someid}::_->id,true|{state_id=None}::_->assertfalse|[]->raiseNot_foundletfold_alldaf=lettop,focused,bot=to_listsdinleta=List.fold_left(funa->flat(fa)false)atopinleta=List.fold_left(funa->flat(fa)true)afocusedinleta=List.fold_left(funa->flat(fa)false)abotina