123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763(************************************************************************)(* * 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) *)(************************************************************************)openMinimlopenConstropenDeclarationsopenNamesopenModPathopenLibnamesopenPpopenCErrorsopenUtilopenTableopenExtractionopenModutilopenCommon(***************************************)(*S Part I: computing Coq environment. *)(***************************************)lettoplevel_env()=letmp,struc=Safe_typing.flatten_env(Global.safe_env())inmp,List.revstrucletenvironment_untildir_opt=letrecparse=function|[]whenOption.is_emptydir_opt->[toplevel_env()]|[]->[]|d::l->letmeb=Modops.destr_nofunctor(MPfiled)(Global.lookup_module(MPfiled)).mod_typeinmatchdir_optwith|Somed'whenDirPath.equaldd'->[MPfiled,meb]|_->(MPfiled,meb)::(parsel)inparse(Library.loaded_libraries())(*s Visit:
a structure recording the needed dependencies for the current extraction *)moduletypeVISIT=sig(* Reset the dependencies by emptying the visit lists *)valreset:unit->unit(* Add the module_path and all its prefixes to the mp visit list.
We'll keep all fields of these modules. *)valadd_mp_all:ModPath.t->unit(* Add reference / ... in the visit lists.
These functions silently add the mp of their arg in the mp list *)valadd_ref:GlobRef.t->unitvaladd_kn:KerName.t->unitvaladd_decl_deps:ml_decl->unitvaladd_spec_deps:ml_spec->unit(* Test functions:
is a particular object a needed dependency for the current extraction ? *)valneeded_ind:MutInd.t->boolvalneeded_cst:Constant.t->boolvalneeded_mp:ModPath.t->boolvalneeded_mp_all:ModPath.t->boolendmoduleVisit:VISIT=structtypemust_visit={mutablekn:KNset.t;mutablemp:MPset.t;mutablemp_all:MPset.t}(* the imperative internal visit lists *)letv={kn=KNset.empty;mp=MPset.empty;mp_all=MPset.empty}(* the accessor functions *)letreset()=v.kn<-KNset.empty;v.mp<-MPset.empty;v.mp_all<-MPset.emptyletneeded_indi=KNset.mem(MutInd.useri)v.knletneeded_cstc=KNset.mem(Constant.userc)v.knletneeded_mpmp=MPset.memmpv.mp||MPset.memmpv.mp_allletneeded_mp_allmp=MPset.memmpv.mp_allletadd_mpmp=check_loaded_modfilemp;v.mp<-MPset.union(prefixes_mpmp)v.mpletadd_mp_allmp=check_loaded_modfilemp;v.mp<-MPset.union(prefixes_mpmp)v.mp;v.mp_all<-MPset.addmpv.mp_allletadd_knkn=v.kn<-KNset.addknv.kn;add_mp(KerName.modpathkn)letadd_ref=letopenGlobRefinfunction|ConstRefc->add_kn(Constant.userc)|IndRef(ind,_)|ConstructRef((ind,_),_)->add_kn(MutInd.userind)|VarRef_->assertfalseletadd_decl_deps=decl_iter_referencesadd_refadd_refadd_refletadd_spec_deps=spec_iter_referencesadd_refadd_refadd_refendletadd_field_labelmp=function|(lab,(SFBconst_|SFBmind_))->Visit.add_kn(KerName.makemplab)|(lab,(SFBmodule_|SFBmodtype_))->Visit.add_mp_all(MPdot(mp,lab))letrecadd_labelsmp=function|MoreFunctor(_,_,m)->add_labelsmpm|NoFunctorsign->List.iter(add_field_labelmp)signexceptionImpossibleletcheck_arityenvcb=lett=cb.const_typeinifReduction.is_arityenvtthenraiseImpossibleletget_bodylbody=EConstr.of_constrlbodyletcheck_fixenvsgcbi=matchcb.const_bodywith|Deflbody->(matchEConstr.kindsg(get_bodylbody)with|Fix((_,j),recd)whenInt.equalij->check_arityenvcb;(true,recd)|CoFix(j,recd)whenInt.equalij->check_arityenvcb;(false,recd)|_->raiseImpossible)|Undef_|OpaqueDef_|Primitive_->raiseImpossibleletprec_declaration_equalsg(na1,ca1,ta1)(na2,ca2,ta2)=Array.equal(Context.eq_annotName.equal)na1na2&&Array.equal(EConstr.eq_constrsg)ca1ca2&&Array.equal(EConstr.eq_constrsg)ta1ta2letfactor_fixenvsglcbmsb=let_,recdascheck=check_fixenvsgcb0inletn=Array.length(letfi,_,_=recdinfi)inifInt.equaln1then[|l|],recd,msbelsebeginifList.lengthmsb<n-1thenraiseImpossible;letmsb',msb''=List.chop(n-1)msbinletlabels=Array.makenlinList.iteri(funj->function|(l,SFBconstcb')->letcheck'=check_fixenvsgcb'(j+1)inifnot((fstcheck:bool)==(fstcheck')&&prec_declaration_equalsg(sndcheck)(sndcheck'))thenraiseImpossible;labels.(j+1)<-l;|_->raiseImpossible)msb';labels,recd,msb''end(** Expanding a [module_alg_expr] into a version without abbreviations
or functor applications. This is done via a detour to entries
(hack proposed by Elie)
*)letexpand_mexprenvmpme=letinl=Some(Flags.get_inline_level())inletstate=((Environ.universesenv,Univ.Constraints.empty),Reductionops.inferred_universes)inletmb,(_,cst)=Mod_typing.translate_modulestateenvmpinl(MExpr([],me,None))inmb.mod_type,mb.mod_deltaletexpand_modtypeenvmpme=letinl=Some(Flags.get_inline_level())inletstate=((Environ.universesenv,Univ.Constraints.empty),Reductionops.inferred_universes)inletmtb,_cst=Mod_typing.translate_modtypestateenvmpinl([],me)inmtbletno_delta=Mod_subst.empty_delta_resolverletflatten_modtypeenvmpme_algstruc_opt=matchstruc_optwith|Someme->me,no_delta|None->letmtb=expand_modtypeenvmpme_alginmtb.mod_type,mtb.mod_delta(** Ad-hoc update of environment, inspired by [Mod_typing.check_with_aux_def].
*)letenv_for_mtb_with_defenvmpmeresoidl=letstruc=Modops.destr_nofunctormpmeinletl=Label.of_id(List.hdidl)inletspot=function(l',SFBconst_)->Label.equalll'|_->falseinletbefore=fst(List.split_whenspotstruc)inModops.add_structurempbeforeresoenvletmake_cstresolvermpl=Mod_subst.constant_of_delta_knresolver(KerName.makempl)letmake_mindresolvermpl=Mod_subst.mind_of_delta_knresolver(KerName.makempl)(* From a [structure_body] (i.e. a list of [structure_field_body])
to specifications. *)letrecextract_structure_specenvmpreso=function|[]->[]|(l,SFBconstcb)::msig->letc=make_cstresomplinlets=extract_constant_specenvccbinletspecs=extract_structure_specenvmpresomsiginiflogical_specsthenspecselsebeginVisit.add_spec_depss;(l,Specs)::specsend|(l,SFBmind_)::msig->letmind=make_mindresomplinlets=Sind(mind,extract_inductiveenvmind)inletspecs=extract_structure_specenvmpresomsiginiflogical_specsthenspecselsebeginVisit.add_spec_depss;(l,Specs)::specsend|(l,SFBmodulemb)::msig->letspecs=extract_structure_specenvmpresomsiginletspec=extract_mbody_specenvmb.mod_mpmbin(l,Smodulespec)::specs|(l,SFBmodtypemtb)::msig->letspecs=extract_structure_specenvmpresomsiginletspec=extract_mbody_specenvmtb.mod_mpmtbin(l,Smodtypespec)::specs(* From [module_expression] to specifications *)(* Invariant: the [me_alg] given to [extract_mexpr_spec] and
[extract_mexpression_spec] should come from a [mod_type_alg] field.
This way, any encountered [MEident] should be a true module type. *)andextract_mexpr_specenvmp1(me_struct_o,me_alg)=matchme_algwith|MEidentmp->Visit.add_mp_allmp;MTidentmp|MEwith(me',WithDef(idl,(c,ctx)))->letme_struct,delta=flatten_modtypeenvmp1me'me_struct_oinletenv'=env_for_mtb_with_defenvmp1me_structdeltaidlinletmt=extract_mexpr_specenvmp1(None,me')inletsg=Evd.from_envenvin(matchextract_with_typeenv'sg(EConstr.of_constrc)with(* cb may contain some kn *)|None->mt|Some(vl,typ)->type_iter_referencesVisit.add_reftyp;MTwith(mt,ML_With_type(idl,vl,typ)))|MEwith(me',WithMod(idl,mp))->Visit.add_mp_allmp;MTwith(extract_mexpr_specenvmp1(None,me'),ML_With_module(idl,mp))|MEapply_->(* No higher-order module type in OCaml : we use the expanded version *)letme_struct,delta=flatten_modtypeenvmp1me_algme_struct_oinextract_msignature_specenvmp1deltame_structandextract_mexpression_specenvmp1(me_struct,me_alg)=matchme_algwith|MEMoreFunctorme_alg'->letmbid,mtb,me_struct'=matchme_structwith|MoreFunctor(mbid,mtb,me')->(mbid,mtb,me')|_->assertfalseinletmp=MPboundmbidinletenv'=Modops.add_module_typempmtbenvinMTfunsig(mbid,extract_mbody_specenvmpmtb,extract_mexpression_specenv'mp1(me_struct',me_alg'))|MENoFunctorm->extract_mexpr_specenvmp1(Someme_struct,m)andextract_msignature_specenvmp1reso=function|NoFunctorstruc->letenv'=Modops.add_structuremp1strucresoenvinMTsig(mp1,extract_structure_specenv'mp1resostruc)|MoreFunctor(mbid,mtb,me)->letmp=MPboundmbidinletenv'=Modops.add_module_typempmtbenvinMTfunsig(mbid,extract_mbody_specenvmpmtb,extract_msignature_specenv'mp1resome)andextract_mbody_spec:'a._->_->'ageneric_module_body->_=funenvmpmb->matchmb.mod_type_algwith|Somety->extract_mexpression_specenvmp(mb.mod_type,ty)|None->extract_msignature_specenvmpmb.mod_deltamb.mod_type(* From a [structure_body] (i.e. a list of [structure_field_body])
to implementations.
NB: when [all=false], the evaluation order of the list is
important: last to first ensures correct dependencies.
*)letrecextract_structureenvmpreso~all=function|[]->[]|(l,SFBconstcb)::struc->(tryletsg=Evd.from_envenvinletvl,recd,struc=factor_fixenvsglcbstrucinletvc=Array.map(make_cstresomp)vlinletms=extract_structureenvmpreso~allstrucinletb=Array.existsVisit.needed_cstvcinifall||bthenletd=extract_fixpointenvsgvcrecdinif(notb)&&(logical_decld)thenmselsebeginVisit.add_decl_depsd;(l,SEdecld)::msendelsemswithImpossible->letms=extract_structureenvmpreso~allstrucinletc=make_cstresomplinletb=Visit.needed_cstcinifall||bthenletd=extract_constantenvccbinif(notb)&&(logical_decld)thenmselsebeginVisit.add_decl_depsd;(l,SEdecld)::msendelsems)|(l,SFBmindmib)::struc->letms=extract_structureenvmpreso~allstrucinletmind=make_mindresomplinletb=Visit.needed_indmindinifall||bthenletd=Dind(mind,extract_inductiveenvmind)inif(notb)&&(logical_decld)thenmselsebeginVisit.add_decl_depsd;(l,SEdecld)::msendelsems|(l,SFBmodulemb)::struc->letms=extract_structureenvmpreso~allstrucinletmp=MPdot(mp,l)inletall'=all||Visit.needed_mp_allmpinifall'||Visit.needed_mpmpthen(l,SEmodule(extract_moduleenvmp~all:all'mb))::mselsems|(l,SFBmodtypemtb)::struc->letms=extract_structureenvmpreso~allstrucinletmp=MPdot(mp,l)inifall||Visit.needed_mpmpthen(l,SEmodtype(extract_mbody_specenvmpmtb))::mselsems(* From [module_expr] and [module_expression] to implementations *)andextract_mexprenvmp=function|MEwith_->assertfalse(* no 'with' syntax for modules *)|mewhenlang()!=Ocaml||Table.is_extrcompute()->(* In Haskell/Scheme, we expand everything.
For now, we also extract everything, dead code will be removed later
(see [Modutil.optimize_struct]. *)letsign,delta=expand_mexprenvmpmeinextract_msignatureenvmpdelta~all:truesign|MEidentmp->ifis_modfilemp&¬(modular())thenerror_MPfile_as_modmpfalse;Visit.add_mp_allmp;Miniml.MEidentmp|MEapply(me,arg)->Miniml.MEapply(extract_mexprenvmpme,extract_mexprenvmp(MEidentarg))andextract_mexpressionenvmpmty=function|MENoFunctorme->extract_mexprenvmpme|MEMoreFunctorme->let(mbid,mtb,mty)=matchmtywith|MoreFunctor(mbid,mtb,mty)->(mbid,mtb,mty)|NoFunctor_->assertfalseinletmp1=MPboundmbidinletenv'=Modops.add_module_typemp1mtbenvinMiniml.MEfunctor(mbid,extract_mbody_specenvmp1mtb,extract_mexpressionenv'mpmtyme)andextract_msignatureenvmpreso~all=function|NoFunctorstruc->letenv'=Modops.add_structurempstrucresoenvinMiniml.MEstruct(mp,extract_structureenv'mpreso~allstruc)|MoreFunctor(mbid,mtb,me)->letmp1=MPboundmbidinletenv'=Modops.add_module_typemp1mtbenvinMiniml.MEfunctor(mbid,extract_mbody_specenvmp1mtb,extract_msignatureenv'mpreso~allme)andextract_moduleenvmp~allmb=(* A module has an empty [mod_expr] when :
- it is a module variable (for instance X inside a Module F [X:SIG])
- it is a module assumption (Declare Module).
Since we look at modules from outside, we shouldn't have variables.
But a Declare Module at toplevel seems legal (cf #2525). For the
moment we don't support this situation. *)letimpl=matchmb.mod_exprwith|Abstract->error_no_module_exprmp|Algebraicme->extract_mexpressionenvmpmb.mod_typeme|Structsign->(* This module has a signature, otherwise it would be FullStruct.
We extract just the elements required by this signature. *)let()=add_labelsmpmb.mod_typeinletsign=Modops.annotate_struct_bodysignmb.mod_typeinextract_msignatureenvmpmb.mod_delta~all:falsesign|FullStruct->extract_msignatureenvmpmb.mod_delta~allmb.mod_typein(* Slight optimization: for modules without explicit signatures
([FullStruct] case), we build the type out of the extracted
implementation *)lettyp=matchmb.mod_exprwith|FullStruct->assert(Option.is_emptymb.mod_type_alg);mtyp_of_mexprimpl|_->extract_mbody_specenvmpmbin{ml_mod_expr=impl;ml_mod_type=typ}letmono_environmentrefsmpl=Visit.reset();List.iterVisit.add_refrefs;List.iterVisit.add_mp_allmpl;letenv=Global.env()inletl=List.rev(environment_untilNone)inList.rev_map(fun(mp,struc)->mp,extract_structureenvmpno_delta~all:(Visit.needed_mp_allmp)struc)l(**************************************)(*S Part II : Input/Output primitives *)(**************************************)letdescr()=matchlang()with|Ocaml->Ocaml.ocaml_descr|Haskell->Haskell.haskell_descr|Scheme->Scheme.scheme_descr|JSON->Json.json_descr(* From a filename string "foo.ml" or "foo", builds "foo.ml" and "foo.mli"
Works similarly for the other languages. *)letdefault_id=Id.of_string"Main"letmono_filenamef=letd=descr()inmatchfwith|None->None,None,default_id|Somef->letf=ifFilename.check_suffixfd.file_suffixthenFilename.chop_suffixfd.file_suffixelsefinletid=iflang()!=Haskellthendefault_idelsetryId.of_string(Filename.basenamef)withUserError_->user_errPp.(str"Extraction: provided filename is not a valid identifier")inSome(f^d.file_suffix),Option.map((^)f)d.sig_suffix,id(* Builds a suitable filename from a module id *)letmodule_filenamemp=letf=file_of_modfilempinletd=descr()inletp=d.file_namingmp^d.file_suffixinSomep,Option.map((^)f)d.sig_suffix,Id.of_stringf(*s Extraction of one decl to stdout. *)letprint_one_declstrucmpdecl=letd=descr()inreset_renaming_tablesAllButExternal;set_phasePre;ignore(d.pp_structstruc);set_phaseImpl;push_visiblemp[];letans=d.pp_decldeclinpop_visible();v0ans(*s Extraction of a ml struct to a file. *)(** For Recursive Extraction, writing directly on stdout
won't work with coqide, we use a buffer instead *)letbuf=Buffer.create1000letformatterdryfile=letft=ifdrythenFormat.make_formatter(fun___->())(fun_->())elsematchfilewith|Somef->Topfmt.with_output_tof|None->Format.formatter_of_bufferbufin(* XXX: Fixme, this shouldn't depend on Topfmt *)(* We never want to see ellipsis ... in extracted code *)Format.pp_set_max_boxesftmax_int;(* We reuse the width information given via "Set Printing Width" *)(matchTopfmt.get_margin()with|None->()|Somei->Format.pp_set_marginfti;Format.pp_set_max_indentft(i-10));(* note: max_indent should be < margin above, otherwise it's ignored *)ftletget_comment()=lets=file_comment()inifString.is_emptysthenNoneelseletsplit_comment=Str.split(Str.regexp"[ \t\n]+")sinSome(prlist_with_sepspcstrsplit_comment)letprint_structure_to_file(fn,si,mo)drystruc=Buffer.clearbuf;letd=descr()inreset_renaming_tablesAllButExternal;letunsafe_needs={mldummy=struct_ast_searchMlutil.isMLdummystruc;tdummy=struct_type_searchMlutil.isTdummystruc;tunknown=struct_type_search((==)Tunknown)struc;magic=iflang()!=Haskellthenfalseelsestruct_ast_search(functionMLmagic_->true|_->false)struc}in(* First, a dry run, for computing objects to rename or duplicate *)set_phasePre;ignore(d.pp_structstruc);letopened=opened_libraries()in(* Print the implementation *)letcout=ifdrythenNoneelseOption.mapopen_outfninletft=formatterdrycoutinletcomment=get_comment()inbegintry(* The real printing of the implementation *)set_phaseImpl;pp_withft(d.preamblemocommentopenedunsafe_needs);pp_withft(d.pp_structstruc);Format.pp_print_flushft();Option.iterclose_outcout;withreraise->Format.pp_print_flushft();Option.iterclose_outcout;raisereraiseend;ifnotdrythenOption.iterinfo_filefn;(* Now, let's print the signature *)Option.iter(funsi->letcout=open_outsiinletft=formatterfalse(Somecout)inbegintryset_phaseIntf;pp_withft(d.sig_preamblemocommentopenedunsafe_needs);pp_withft(d.pp_sig(signature_of_structurestruc));Format.pp_print_flushft();close_outcout;withreraise->Format.pp_print_flushft();close_outcout;raisereraiseend;info_filesi)(ifdrythenNoneelsesi);(* Print the buffer content via Coq standard formatter (ok with coqide). *)ifnot(Int.equal(Buffer.lengthbuf)0)thenbeginFeedback.msg_notice(str(Buffer.contentsbuf));Buffer.resetbufend(*********************************************)(*s Part III: the actual extraction commands *)(*********************************************)letreset()=Visit.reset();reset_tables();reset_renaming_tablesEverythingletinit?(compute=false)?(inner=false)modularlibrary=ifnotinnerthencheck_inside_section();set_keywords(descr()).keywords;set_modularmodular;set_librarylibrary;set_extrcomputecompute;reset();ifmodular&&lang()==Schemethenerror_scheme()letwarns()=warning_opaques(access_opaque());warning_axioms()(* From a list of [reference], let's retrieve whether they correspond
to modules or [global_reference]. Warn the user if both is possible. *)letreclocate_ref=function|[]->[],[]|qid::l->letmpo=trySome(Nametab.locate_moduleqid)withNot_found->Noneandro=trySome(Smartlocate.global_with_aliasqid)withNametab.GlobalizationError_|UserError_->Noneinmatchmpo,rowith|None,None->Nametab.error_global_not_found~info:Exninfo.nullqid|None,Somer->letrefs,mps=locate_reflinr::refs,mps|Somemp,None->letrefs,mps=locate_reflinrefs,mp::mps|Somemp,Somer->warning_ambiguous_name(qid,mp,r);letrefs,mps=locate_reflinrefs,mp::mps(*s Recursive extraction in the Coq toplevel. The vernacular command is
\verb!Recursive Extraction! [qualid1] ... [qualidn]. Also used when
extracting to a file with the command:
\verb!Extraction "file"! [qualid1] ... [qualidn]. *)letfull_extrf(refs,mps)=initfalsefalse;List.iter(funmp->ifis_modfilempthenerror_MPfile_as_modmptrue)mps;letstruc=optimize_struct(refs,mps)(mono_environmentrefsmps)inwarns();print_structure_to_file(mono_filenamef)falsestruc;reset()letfull_extractionflr=full_extrf(locate_reflr)(*s Separate extraction is similar to recursive extraction, with the output
decomposed in many files, one per Coq .v file *)letseparate_extractionlr=inittruefalse;letrefs,mps=locate_reflrinletstruc=optimize_struct(refs,mps)(mono_environmentrefsmps)inlet()=List.iter(function|MPfile_,_->()|(MPdot_|MPbound_),_->user_err(str"Separate Extraction from inside a module is not supported."))strucinwarns();letprint=function|(MPfiledirasmp,sel)ase->print_structure_to_file(module_filenamemp)false[e]|(MPdot_|MPbound_),_->assertfalseinList.iterprintstruc;reset()(*s Simple extraction in the Coq toplevel. The vernacular command
is \verb!Extraction! [qualid]. *)letsimple_extractionr=matchlocate_ref[r]with|([],[mp])asp->full_extrNonep|[r],[]->initfalsefalse;letstruc=optimize_struct([r],[])(mono_environment[r][])inletd=get_decl_in_structurerstrucinwarns();letflag=ifis_customrthenstr"(** User defined extraction *)"++fnl()elsemt()inletans=flag++print_one_declstruc(modpath_of_rr)dinreset();Feedback.msg_noticeans|_->assertfalse(*s (Recursive) Extraction of a library. The vernacular command is
\verb!(Recursive) Extraction Library! [M]. *)letextraction_libraryis_recCAst.{loc;v=m}=inittruetrue;letdir_m=letq=qualid_of_identmintryNametab.full_name_moduleqwithNot_found->error_unknown_module?locqinVisit.add_mp_all(MPfiledir_m);letenv=Global.env()inletl=List.rev(environment_until(Somedir_m))inletselectl(mp,struc)=ifVisit.needed_mpmpthen(mp,extract_structureenvmpno_delta~all:truestruc)::lelselinletstruc=List.fold_leftselect[]linletstruc=optimize_struct([],[])strucinwarns();letprint=function|(MPfiledirasmp,sel)ase->letdry=notis_rec&¬(DirPath.equaldirdir_m)inprint_structure_to_file(module_filenamemp)dry[e]|_->assertfalseinList.iterprintstruc;reset()(** For extraction compute, we flatten all the module structure,
getting rid of module types or unapplied functors *)letflatten_structurestruc=letrecflatten_elem(lab,elem)=matchelemwith|SEdecld->[d]|SEmodtype_->[]|SEmodulem->matchm.ml_mod_exprwith|MEfunctor_->[]|MEident_|MEapply_->assertfalse(* should be expanded *)|MEstruct(_,elems)->flatten_elemselemsandflatten_elemsl=List.flatten(List.mapflatten_eleml)inflatten_elems(List.flatten(List.mapsndstruc))letstructure_for_computeenvsgc=initfalsefalse~compute:true;letast,mlt=Extraction.extract_constrenvsgcinletast=Mlutil.normalizeastinletrefs=refGlobRef.Set.emptyinletadd_refr=refs:=GlobRef.Set.addr!refsinlet()=ast_iter_referencesadd_refadd_refadd_refastinletrefs=GlobRef.Set.elements!refsinletstruc=optimize_struct(refs,[])(mono_environmentrefs[])in(flatten_structurestruc),ast,mlt(* For the test-suite :
extraction to a temporary file + run ocamlc on it *)letcompilef=tryletargs=["ocamlc";"-package";"zarith";"-I";Filename.dirnamef;"-c";f^"i";f]inletres=CUnix.sys_command(Envars.ocamlfind())argsinmatchreswith|Unix.WEXITED0->()|Unix.WEXITEDn|Unix.WSIGNALEDn|Unix.WSTOPPEDn->CErrors.user_errPp.(str"Compilation of file "++strf++str" failed with exit code "++intn)withUnix.Unix_error(e,_,_)->CErrors.user_errPp.(str"Compilation of file "++strf++str" failed with error "++str(Unix.error_messagee))letremovef=ifSys.file_existsfthenSys.removefletextract_and_compilel=iflang()!=OcamlthenCErrors.user_err(Pp.str"This command only works with OCaml extraction");letf=Filename.temp_file"testextraction"".ml"inlet()=full_extraction(Somef)linlet()=compilefinlet()=removef;remove(f^"i")inletbase=Filename.chop_suffixf".ml"inlet()=remove(base^".cmo");remove(base^".cmi")inFeedback.msg_notice(str"Extracted code successfully compiled")(* Show the extraction of the current ongoing proof *)letshow_extraction~pstate=init~inner:truefalsefalse;letprf=Declare.Proof.getpstateinletsigma,env=Declare.Proof.get_current_contextpstateinlettrms=Proof.partial_proofprfinletextr_termt=letast,ty=extract_constrenvsigmatinletmp=Lib.current_mp()inletl=Label.of_id(Declare.Proof.get_namepstate)inletfake_ref=GlobRef.ConstRef(Constant.make2mpl)inletdecl=Dterm(fake_ref,ast,ty)inprint_one_decl[]mpdeclinFeedback.msg_notice(Pp.prlist_with_sepPp.fnlextr_termtrms)