123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282(************************************************************************)(* * The Rocq Prover / The Rocq 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) *)(************************************************************************)openUtilopenPpopenCErrorsopenNamesopenProofview.NotationsopenTac2expropenTac2valopenTac2btexceptionLtacError=Tac2ffi.LtacErrortypeenvironment=Tac2env.environment={env_ist:valexprId.Map.t;}letempty_environment={env_ist=Id.Map.empty;}typeclosure={mutableclos_env:valexprId.Map.t;(** Mutable so that we can implement recursive functions imperatively *)clos_var:Name.tlist;(** Bound variables *)clos_exp:glb_tacexpr;(** Body *)clos_ref:ltac_constantoption;(** Global constant from which the closure originates *)}letpush_idistidv={env_ist=Id.Map.addidvist.env_ist}letpush_nameistidv=matchidwith|Anonymous->ist|Nameid->push_idistidvletget_varistid=tryId.Map.findidist.env_istwithNot_found->anomaly(str"Unbound variable "++Id.printid)letreturn=Proofview.tclUNITexceptionNoMatchletmatch_ctor_againstctorv=matchctor,vwith|{cindx=Openctor},ValOpn(ctor',vs)->ifKerName.equalctorctor'thenvselseraiseNoMatch|{cindx=Open_},_->assertfalse|{cnargs=0;cindx=Closedi},ValInti'->ifInt.equalii'then[||]elseraiseNoMatch|{cnargs=0;cindx=Closed_},ValBlk_->raiseNoMatch|_,ValInt_->raiseNoMatch|{cindx=Closedi},ValBlk(i',vs)->ifInt.equalii'thenvselseraiseNoMatch|{cindx=Closed_},ValOpn_->assertfalse|_,(ValStr_|ValCls_|ValExt_)->assertfalseletcheck_atom_againstatmv=matchatm,vwith|AtmIntn,ValIntn'->ifnot(Int.equalnn')thenraiseNoMatch|AtmStrs,ValStrs'->ifnot(String.equals(Bytes.unsafe_to_strings'))thenraiseNoMatch|(AtmInt_|AtmStr_),_->assertfalseletrecmatch_pattern_againstistpatv=matchpatwith|GPatVarx->push_nameistxv|GPatAtmatm->check_atom_againstatmv;ist|GPatAs(p,x)->match_pattern_against(push_nameist(Namex)v)pv|GPatRef(ctor,pats)->letvs=match_ctor_againstctorvinList.fold_left_i(funiistpat->match_pattern_againstistpatvs.(i))0istpats|GPatOrpats->match_pattern_against_oristpatsvandmatch_pattern_against_oristpatsv=matchpatswith|[]->raiseNoMatch|pat::pats->trymatch_pattern_againstistpatvwithNoMatch->match_pattern_against_oristpatsvleteval_glb_extist(Tac2dyn.Arg.Glb(tag,e))=lettpe=Tac2env.interp_ml_objecttaginwith_frame(FrExtn(tag,e))(tpe.Tac2env.ml_interpiste)letrecinterp(ist:environment)=function|GTacAtm(AtmIntn)->return(Tac2ffi.of_intn)|GTacAtm(AtmStrs)->return(Tac2ffi.of_strings)|GTacVarid->return(get_varistid)|GTacRefkn->return(eval_globalkn)|GTacFun(ids,e)->letcls={clos_ref=None;clos_env=ist.env_ist;clos_var=ids;clos_exp=e}inletf=interp_closureclsinreturnf|GTacApp(f,args)->interpistf>>=funf->Proofview.Monad.List.map(fune->interpiste)args>>=funargs->Tac2val.apply_valfargs|GTacLet(false,el,e)->letfoldaccu(na,e)=interpiste>>=fune->return(push_nameaccunae)inProofview.Monad.List.fold_leftfoldistel>>=funist->interpiste|GTacLet(true,el,e)->letist=push_let_recist.env_istelininterp{env_ist=ist}e|GTacCst(_,n,[])->return(Valexpr.make_intn)|GTacCst(_,n,el)->Proofview.Monad.List.map(fune->interpiste)el>>=funel->return(Valexpr.make_blockn(Array.of_listel))|GTacCse(e,_,cse0,cse1)->interpiste>>=fune->interp_caseistecse0cse1|GTacWth{opn_match=e;opn_branch=cse;opn_default=def}->interpiste>>=fune->interp_withistecsedef|GTacFullMatch(e,brs)->interpiste>>=fune->interp_full_matchistebrs|GTacPrj(_,e,p)->interpiste>>=fune->interp_projistep|GTacSet(_,e,p,r)->interpiste>>=fune->interpistr>>=funr->interp_setistepr|GTacOpn(kn,el)->Proofview.Monad.List.map(fune->interpiste)el>>=funel->return(Tac2ffi.of_open(kn,Array.of_listel))|GTacPrmml->return(Tac2env.interp_primitiveml)|GTacExt(tag,e)->eval_glb_extist(Glb(tag,e))andpush_let_recistel=letmap(na,e)=matchewith|GTacFun(ids,e)->letcls={clos_ref=None;clos_env=ist;clos_var=ids;clos_exp=e}inletf=interp_closureclsinna,cls,f|_->anomaly(str"Ill-formed recursive function")inletfixs=List.mapmapelinletfoldaccu(na,_,cls)=matchnawith|Anonymous->accu|Nameid->Id.Map.addidclsaccuinletist=List.fold_leftfoldistfixsin(* Hack to make a cycle imperatively in the environment *)letiter(_,e,_)=e.clos_env<-istinlet()=List.iteriterfixsinistandinterp_closuref=letans=funargs->let{clos_env=ist;clos_var=ids;clos_exp=e;clos_ref=kn}=finletframe=matchknwith|None->FrAnone|Somekn->FrLtackninletist={env_ist=ist}inletist=List.fold_left2push_nameistidsargsinwith_frameframe(interpiste)inTac2ffi.(of_closure(abstract(List.lengthf.clos_var)ans))andinterp_caseistecse0cse1=ifValexpr.is_intetheninterpistcse0.(Tac2ffi.to_inte)elselet(n,args)=Tac2ffi.to_blockeinlet(ids,e)=cse1.(n)inletist=CArray.fold_left2push_nameistidsargsininterpisteandinterp_withistecsedef=let(kn,args)=Tac2ffi.to_openeinletbr=trySome(KNmap.findkncse)withNot_found->Noneinbeginmatchbrwith|None->let(self,def)=definletist=push_nameistselfeininterpistdef|Some(self,ids,p)->letist=push_nameistselfeinletist=CArray.fold_left2push_nameistidsargsininterpistpendandinterp_full_matchiste=function|[]->CErrors.anomalyPp.(str"ltac2 match not exhaustive")|(pat,br)::rest->beginmatchmatch_pattern_againstistpatewith|exceptionNoMatch->interp_full_matchisterest|ist->interpistbrendandinterp_projistep=return(Valexpr.fieldep)andinterp_setistepr=let()=Valexpr.set_fieldeprinreturn(Valexpr.make_int0)andeval_globalkn=matchTac2env.get_compiled_globalknwith|Some(_info,v)->v|None->matchTac2env.interp_globalknwith|exceptionNot_found->anomaly(str"Unbound reference"++KerName.printkn)|{gdata_expr=e}->eval_pureId.Map.empty(Somekn)eandeval_purebndkn=function|GTacVarid->Id.Map.getidbnd|GTacAtm(AtmIntn)->Valexpr.make_intn|GTacRefkn->eval_globalkn|GTacFun(na,e)->letcls={clos_ref=kn;clos_env=bnd;clos_var=na;clos_exp=e}ininterp_closurecls|GTacCst(_,n,[])->Valexpr.make_intn|GTacCst(_,n,el)->Valexpr.make_blockn(eval_pure_argsbndel)|GTacOpn(kn,el)->Tac2ffi.of_open(kn,eval_pure_argsbndel)|GTacLet(false,vals,body)->letfoldaccu(na,e)=matchnawith|Anonymous->(* No need to evaluate, we know this is a value *)accu|Nameid->letv=eval_purebndNoneeinId.Map.addidvaccuinletbnd=List.fold_leftfoldbndvalsineval_purebndknbody|GTacLet(true,el,body)->letbnd=push_let_recbndelineval_purebndknbody|GTacPrj(_,e,i)->letv=eval_purebndkneinValexpr.fieldvi|GTacPrmml->Tac2env.interp_primitiveml|GTacAtm(AtmStr_)|GTacSet_|GTacApp_|GTacCse_|GTacExt_|GTacWth_|GTacFullMatch_->anomaly(Pp.str"Term is not a syntactical value")andeval_pure_argsbndargs=letmape=eval_purebndNoneeinArray.map_of_listmapargsletinterp_valueisttac=eval_pureist.env_istNonetac(** Cross-boundary hacks. *)openGeninterpletval_env:environmentVal.typ=Val.create"ltac2:env"letenv_ref=Id.of_string_soft"@@ltac2_env@@"letextract_env(Val.Dyn(tag,v)):environment=matchVal.eqtagval_envwith|None->assertfalse|SomeRefl->vletget_envist=tryextract_env(Id.Map.findenv_refist)withNot_found->empty_environmentletset_envenvist=Id.Map.addenv_ref(Val.Dyn(val_env,env))ist