123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175(************************************************************************)(* * 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) *)(************************************************************************)letnot_ready_msg=ref(funname->Pp.strbrk("The value you are asking for ("^name^") is not ready yet. "^"Please wait or pass "^"the \"-async-proofs off\" option to CoqIDE to disable "^"asynchronous script processing and don't pass \"-vio\" to "^"coqc."))letnot_here_msg=ref(funname->Pp.strbrk("The value you are asking for ("^name^") is not available "^"in this process. If you really need this, pass "^"the \"-async-proofs off\" option to CoqIDE to disable "^"asynchronous script processing and don't pass \"-vio\" to "^"coqc."))exceptionNotReadyofstringexceptionNotHereofstringlet_=CErrors.register_handler(function|NotReadyname->Some(!not_ready_msgname)|NotHerename->Some(!not_here_msgname)|_->None)typefix_exn=Stateid.exn_infooptionleteval_fix_exnf(e,info)=matchfwith|None->(e,info)|Some{Stateid.id;valid}->matchStateid.getinfowith|Some_->(e,info)|None->letloc=Loc.get_locinfoinletmsg=CErrors.iprint(e,info)inlet()=Feedback.(feedback~id(Message(Error,loc,msg)))in(e,Stateid.addinfo~validid)moduleUUID=structtypet=intletinvalid=0letfresh=letcount=refinvalidinfun()->incrcount;!countletcompare=compareletequal=(==)endmoduleUUIDMap=Map.Make(UUID)moduleUUIDSet=Set.Make(UUID)type'aassignment=[`Valof'a|`ExnofExninfo.iexn|`Compof(unit->'a)](* Val is not necessarily a final state, so the
computation restarts from the state stocked into Val *)and'acomp=|Delegatedof(Mutex.t*Condition.t)option|Closureof(unit->'a)|Valof'a|ExnofExninfo.iexn(* Invariant: this exception is always "fixed" as in fix_exn *)and'acomputation=|Ongoingofstring*(UUID.t*fix_exn*'acompref)CEphemeron.keyletunnamed="unnamed"letcreate?(name=unnamed)?(uuid=UUID.fresh())~fix_exnx=Ongoing(name,CEphemeron.create(uuid,fix_exn,refx))letgetx=matchxwith|Ongoing(name,x)->tryletuuid,fix,c=CEphemeron.getxinname,uuid,fix,cwithCEphemeron.InvalidKey->name,UUID.invalid,None,ref(Exn(NotHerename,Exninfo.null))type'avalue=[`Valof'a|`ExnofExninfo.iexn]letis_overkx=let_,_,_,x=getkxinmatch!xwith|Val_|Exn_->true|Closure_|Delegated_->falseletis_exnkx=let_,_,_,x=getkxinmatch!xwith|Exn_->true|Val_|Closure_|Delegated_->falseletpeek_valkx=let_,_,_,x=getkxinmatch!xwith|Valv->Somev|Exn_|Closure_|Delegated_->Noneletuuidkx=let_,id,_,_=getkxinidletfrom_valv=create~fix_exn:None(Valv)letcreate_delegate?(blocking=true)~namefix_exn=letsync=ifblockingthenSome(Mutex.create(),Condition.create())elseNoneinletck=create~name~fix_exn(Delegatedsync)inletassignment=funv->let_,_,fix_exn,c=getckinletsync=match!cwithDelegateds->s|_->assertfalseinbeginmatchvwith|`Valv->c:=Valv|`Exne->c:=Exn(eval_fix_exnfix_exne)|`Compf->c:=Closurefend;letiter(lock,cond)=CThread.with_locklock~scope:(fun()->Condition.broadcastcond)inOption.iteritersyncinck,assignment(* TODO: get rid of try/catch to be stackless *)letreccomputeck:'avalue=letname,_,fix_exn,c=getckinmatch!cwith|Valx->`Valx|Exn(e,info)->`Exn(e,info)|DelegatedNone->raise(NotReadyname)|Delegated(Some(lock,cond))->CThread.with_locklock~scope:(fun()->Condition.waitcondlock);computeck|Closuref->tryletdata=f()inc:=Valdata;`Valdatawithe->lete=Exninfo.captureeinlete=eval_fix_exnfix_exneinmatchewith|(NotReady_,_)->`Exne|_->c:=Exne;`Exneletforcex=matchcomputexwith|`Valv->v|`Exne->Exninfo.iraiseeletchainckf=letname,uuid,fix_exn,c=getckincreate~uuid~name~fix_exn(match!cwith|Closure_|Delegated_->Closure(fun()->f(forceck))|Exn_asx->x|Valv->Val(fv))letcreate~fix_exnf=create~fix_exn(Closuref)letreplacekxy=let_,_,_,x=getkxinmatch!xwith|Exn_->x:=Closure(fun()->forcey)|_->CErrors.anomaly(Pp.str"A computation can be replaced only if is_exn holds.")letchainxf=lety=chainxfinifis_overxthenignore(forcey);yletprintfkx=letopenPpinletname,uid,_,x=getkxinletuid=ifUUID.equaluidUUID.invalidthenstr"[#:"++strname++str"]"elsestr"["++intuid++str":"++strname++str"]"inmatch!xwith|Delegated_->str"Delegated"++uid|Closure_->str"Closure"++uid|Valx->str"PureVal"++uid++spc()++hov0(fx)|Exn(e,_)->str"Exn"++uid++spc()++hov0(str(Printexc.to_stringe))