123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246(************************************************************************)(* * 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) *)(************************************************************************)openUtilopenPpopenCErrorsopenNamesopenProofview.NotationsopenTac2expropenTac2ffiexceptionLtacError=Tac2ffi.LtacErrorletbacktrace:backtraceEvd.Store.field=Evd.Store.field()letprint_ltac2_backtrace=reffalseletget_backtrace=Proofview.tclEVARMAP>>=funsigma->matchEvd.Store.get(Evd.get_extra_datasigma)backtracewith|None->Proofview.tclUNIT[]|Somebt->Proofview.tclUNITbtletset_backtracebt=Proofview.tclEVARMAP>>=funsigma->letstore=Evd.get_extra_datasigmainletstore=Evd.Store.setstorebacktracebtinletsigma=Evd.set_extra_datastoresigmainProofview.Unsafe.tclEVARSsigmaletwith_frameframetac=if!print_ltac2_backtracethenget_backtrace>>=funbt->set_backtrace(frame::bt)>>=fun()->tac>>=funans->set_backtracebt>>=fun()->Proofview.tclUNITanselsetactypeenvironment=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_nameistidv=matchidwith|Anonymous->ist|Nameid->{env_ist=Id.Map.addidvist.env_ist}letget_varistid=tryId.Map.findidist.env_istwithNot_found->anomaly(str"Unbound variable "++Id.printid)letget_refistkn=tryletdata=Tac2env.interp_globalknindata.Tac2env.gdata_exprwithNot_found->anomaly(str"Unbound reference"++KerName.printkn)letreturn=Proofview.tclUNITletrecinterp(ist:environment)=function|GTacAtm(AtmIntn)->return(Tac2ffi.of_intn)|GTacAtm(AtmStrs)->return(Tac2ffi.of_string(Bytes.of_strings))|GTacVarid->return(get_varistid)|GTacRefkn->letdata=get_refistkninreturn(eval_pureId.Map.empty(Somekn)data)|GTacFun(ids,e)->letcls={clos_ref=None;clos_env=ist.env_ist;clos_var=ids;clos_exp=e}inletf=interp_appclsinreturn(Tac2ffi.of_closuref)|GTacApp(f,args)->interpistf>>=funf->Proofview.Monad.List.map(fune->interpiste)args>>=funargs->Tac2ffi.apply(Tac2ffi.to_closuref)args|GTacLet(false,el,e)->letfoldaccu(na,e)=interpiste>>=fune->return(push_nameaccunae)inProofview.Monad.List.fold_leftfoldistel>>=funist->interpiste|GTacLet(true,el,e)->letmap(na,e)=matchewith|GTacFun(ids,e)->letcls={clos_ref=None;clos_env=ist.env_ist;clos_var=ids;clos_exp=e}inletf=Tac2ffi.of_closure(interp_appcls)inna,cls,f|_->anomaly(str"Ill-formed recursive function")inletfixs=List.mapmapelinletfoldaccu(na,_,cls)=matchnawith|Anonymous->accu|Nameid->{env_ist=Id.Map.addidclsaccu.env_ist}inletist=List.fold_leftfoldistfixsin(* Hack to make a cycle imperatively in the environment *)letiter(_,e,_)=e.clos_env<-ist.env_istinlet()=List.iteriterfixsininterpiste|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|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))|GTacPrm(ml,el)->Proofview.Monad.List.map(fune->interpiste)el>>=funel->with_frame(FrPrimml)(Tac2ffi.apply(Tac2env.interp_primitiveml)el)|GTacExt(tag,e)->lettpe=Tac2env.interp_ml_objecttaginwith_frame(FrExtn(tag,e))(tpe.Tac2env.ml_interpiste)andinterp_appf=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.abstract(List.lengthf.clos_var)ansandinterp_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_projistep=return(Valexpr.fieldep)andinterp_setistepr=let()=Valexpr.set_fieldeprinreturn(Valexpr.make_int0)andeval_purebndkn=function|GTacVarid->Id.Map.getidbnd|GTacAtm(AtmIntn)->Valexpr.make_intn|GTacRefkn->let{Tac2env.gdata_expr=e}=tryTac2env.interp_globalknwithNot_found->assertfalseineval_purebnd(Somekn)e|GTacFun(na,e)->letcls={clos_ref=kn;clos_env=bnd;clos_var=na;clos_exp=e}inletf=interp_appclsinTac2ffi.of_closuref|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(isrec,vals,body)->let()=assert(notisrec)inletfoldaccu(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|GTacAtm(AtmStr_)|GTacSet_|GTacApp_|GTacCse_|GTacPrj_|GTacPrm_|GTacExt_|GTacWth_->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