1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054(************************************************************************)(* * 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) *)(************************************************************************)openNamesopenModPathopenTermopenDeclarationsopenNamegenopenLibobjectopenGoptionsopenLibnamesopenGlobnamesopenCErrorsopenUtilopenPpopenMiniml(*s Extraction Blacklist of filenames not to use while extracting *)letblacklist_table=Summary.refId.Set.empty~name:"ExtrBlacklist"(** Sets and maps for [global_reference] that use the "user" [kernel_name]
instead of the canonical one *)moduleGlobOrd=structtypet=globalletcompareg1g2=letc=GlobRef.UserOrd.compareg1.globg2.globinifInt.equalc0thenInfvInst.compareg1.instg2.instelsecendmoduleRefmap'=CMap.Make(GlobOrd)moduleRefset'=Set.Make(GlobOrd)(*S Utilities about [module_path] and [kernel_names] and [global_reference] *)letoccur_kn_in_refknr=letopenGlobRefinmatchr.globwith|IndRef(kn',_)|ConstructRef((kn',_),_)->MutInd.CanOrd.equalknkn'|ConstRef_|VarRef_->false(* Return the "canonical" name used for declaring a name *)letrepr_of_rr=letopenGlobRefinmatchr.globwith|ConstRefkn->Constant.userkn|IndRef(kn,_)|ConstructRef((kn,_),_)->MutInd.userkn|VarRefv->Lib.make_knvletmodpath_of_rr=KerName.modpath(repr_of_rr)letlabel_of_rr=KerName.label(repr_of_rr)letrecbase_mp=function|MPdot(mp,l)->base_mpmp|mp->mpletis_modfile=function|MPfile_->true|_->falseletraw_string_of_modfile=function|MPfilef->String.capitalize_ascii(Id.to_string(List.hd(DirPath.reprf)))|_->assertfalseletextraction_current_mp()=fst(Safe_typing.flatten_env(Global.safe_env()))letis_toplevelmp=ModPath.equalmp(extraction_current_mp())letat_toplevelmp=is_modfilemp||is_toplevelmpletmp_lengthmp=letmp0=extraction_current_mp()inletreclen=function|mpwhenModPath.equalmpmp0->1|MPdot(mp,_)->1+lenmp|_->1inlenmpletrecprefixes_mpmp=matchmpwith|MPdot(mp',_)->MPset.addmp(prefixes_mpmp')|_->MPset.singletonmpletrecget_nth_label_mpn=function|MPdot(mp,l)->ifInt.equaln1thenlelseget_nth_label_mp(n-1)mp|_->failwith"get_nth_label: not enough MPdot"letcommon_prefix_from_listmp0mpl=letprefixes=prefixes_mpmp0inletrecf=function|[]->None|mp::l->ifMPset.memmpprefixesthenSomempelseflinfmplletrecparse_labels2ll=function|MPdot(mp,l)->parse_labels2(l::ll)mp|mp->mp,llletlabels_of_refr=letmp,l=KerName.repr(repr_of_rr)inparse_labels2[l]mp(*S The main table: constants, inductives, records, ... *)(* This table is not registered within coq save/undo mechanism
since we set its contents at each run of Extraction *)(* We use [constant_body] (resp. [mutual_inductive_body]) as checksum
to ensure that the table contents aren't outdated. *)moduleInfvMap=Map.Make(InfvInst)typetable={typedefs:(constant_body*ml_type)InfvMap.tCmap_env.t;cst_types:(constant_body*ml_schema)InfvMap.tCmap_env.t;inductives:(mutual_inductive_body*ml_ind)InfvMap.tMindmap_env.t;inductive_kinds:inductive_kindInfvMap.tMindmap_env.t;recursors:KNset.t;(* recursors: we can use the equivalence between canonical and user constant names. *)projs:(inductive*int)GlobRef.Map.t;(* projs: working modulo name equivalence is ok *)info_axioms:Refset'.t;log_axioms:Refset'.t;symbols:Label.tlistRefmap'.t;opaques:Refset'.t;modfile_ids:Id.Set.t;modfile_mps:pp_tagMPmap.t;}typet=tablerefletempty_table={typedefs=Cmap_env.empty;cst_types=Cmap_env.empty;inductives=Mindmap_env.empty;inductive_kinds=Mindmap_env.empty;recursors=KNset.empty;projs=GlobRef.Map.empty;info_axioms=Refset'.empty;log_axioms=Refset'.empty;symbols=Refmap'.empty;opaques=Refset'.empty;modfile_ids=Id.Set.empty;modfile_mps=MPmap.empty;}letmake_table()=ref{empty_tablewithmodfile_ids=!blacklist_table}letadd_typedeftablekninstcbt=letupd=function|None->Some(InfvMap.singletoninst(cb,t))|Somemap->Some(InfvMap.addinst(cb,t)map)intable:={!tablewithtypedefs=Cmap_env.updateknupd!table.typedefs}letlookup_typedeftablekninstcb=trylet(cb0,t)=InfvMap.findinst(Cmap_env.findkn!table.typedefs)inifcb0==cbthenSometelseNonewithNot_found->Noneletadd_cst_typetablekninstcbs=letupd=function|None->Some(InfvMap.singletoninst(cb,s))|Somemap->Some(InfvMap.addinst(cb,s)map)intable:={!tablewithcst_types=Cmap_env.updateknupd!table.cst_types}letlookup_cst_typetablekninstcb=trylet(cb0,s)=InfvMap.findinst(Cmap_env.findkn!table.cst_types)inifcb0==cbthenSomeselseNonewithNot_found->Noneletadd_indtablekninstmibml_ind=letupd=function|None->Some(InfvMap.singletoninst(mib,ml_ind))|Somemap->Some(InfvMap.addinst(mib,ml_ind)map)intable:={!tablewithinductives=Mindmap_env.updateknupd!table.inductives}letlookup_indtablekninstmib=trylet(mib0,ml_ind)=InfvMap.findinst(Mindmap_env.findkn!table.inductives)inifmib==mib0thenSomeml_indelseNonewithNot_found->Noneletadd_inductive_kindtablekninstk=letupd=function|None->Some(InfvMap.singletoninstk)|Somemap->Some(InfvMap.addinstkmap)intable:={!tablewithinductive_kinds=Mindmap_env.updateknupd!table.inductive_kinds}letis_coinductivetabler=letkn=letopenGlobRefinmatchr.globwith|ConstructRef((kn,_),_)->kn|IndRef(kn,_)->kn|_->assertfalseintryInfvMap.findr.inst(Mindmap_env.findkn!table.inductive_kinds)==CoinductivewithNot_found->falseletis_coinductive_typetable=function|Tglob(r,_)->is_coinductivetabler|_->falseletget_record_fieldstabler=letkn=letopenGlobRefinmatchr.globwith|ConstructRef((kn,_),_)->kn|IndRef(kn,_)->kn|_->assertfalseintrymatchInfvMap.findr.inst(Mindmap_env.findkn!table.inductive_kinds)with|Recordf->f|_->[]withNot_found->[]letrecord_fields_of_typetable=function|Tglob(r,_)->get_record_fieldstabler|_->[]letadd_recursorstableenvind=letkn=MutInd.canonicalindinletmk_knid=KerName.make(KerName.modpathkn)(Label.of_idid)inletmib=Environ.lookup_mindindenvinArray.iter(funmip->letid=mip.mind_typenameinletkn_rec=mk_kn(Nameops.add_suffixid"_rec")andkn_rect=mk_kn(Nameops.add_suffixid"_rect")intable:={!tablewithrecursors=KNset.addkn_rec(KNset.addkn_rect!table.recursors)})mib.mind_packetsletis_recursortabler=matchr.globwith|GlobRef.ConstRefc->KNset.mem(Constant.canonicalc)!table.recursors|_->falseletadd_projectiontablenknip=table:={!tablewithprojs=GlobRef.Map.add(GlobRef.ConstRefkn)(ip,n)!table.projs}letis_projectiontabler=GlobRef.Map.memr.glob!table.projs(*s Table of used axioms *)letadd_info_axiomtabler=table:={!tablewithinfo_axioms=Refset'.addr!table.info_axioms}letremove_info_axiomtabler=table:={!tablewithinfo_axioms=Refset'.remover!table.info_axioms}letadd_log_axiomtabler=table:={!tablewithlog_axioms=Refset'.addr!table.log_axioms}letadd_symboltabler=table:={!tablewithsymbols=Refmap'.updater(functionSomel->Somel|_->Some[])!table.symbols}letadd_symbol_ruletablerl=table:={!tablewithsymbols=Refmap'.updater(functionSomelst->Some(l::lst)|_->Some[l])!table.symbols}letadd_opaquetabler=table:={!tablewithopaques=Refset'.addr!table.opaques}letremove_opaquetabler=table:={!tablewithopaques=Refset'.remover!table.opaques}(*s Extraction modes: modular or monolithic, library or minimal ?
Nota:
- Recursive Extraction : monolithic, minimal
- Separate Extraction : modular, minimal
- Extraction Library : modular, library
*)(*s Printing. *)(* The following functions work even on objects not in [Global.env ()].
Warning: for inductive objects, this only works if an [extract_inductive]
have been done earlier, otherwise we can only ask the Nametab about
currently visible objects. *)letsafe_basename_of_global_gentabler=letlast_chancer(kn,pos)=tryNametab.basename_of_globalrwithNot_found->letid=Id.to_string(Label.to_id(MutInd.labelkn))inId.of_string(id^"_"^String.concat"_"(List.mapstring_of_intpos))inletunsafe_lookup_indtablekn=snd(InfvMap.findr.inst(Mindmap_env.findkn!table.inductives))inletopenGlobRefinmatchr.globwith|ConstRefkn->Label.to_id(Constant.labelkn)|IndRef(kn,0)->Label.to_id(MutInd.labelkn)|IndRef(kn,i)->letr=r.globinbeginmatchtablewith|None->last_chancer(kn,[i])|Sometable->try(unsafe_lookup_indtablekn).ind_packets.(i).ip_typenamewithNot_found->last_chancer(kn,[i])end|ConstructRef((kn,i),j)->letr=r.globinbeginmatchtablewith|None->last_chancer(kn,[i;j])|Sometable->try(unsafe_lookup_indtablekn).ind_packets.(i).ip_consnames.(j-1)withNot_found->last_chancer(kn,[i])end|VarRefv->vletsafe_basename_of_globaltabler=safe_basename_of_global_gen(Sometable)rletstring_of_globalr=trystring_of_qualid(Nametab.shortest_qualid_of_globalId.Set.emptyr.glob)withNot_found->Id.to_string(safe_basename_of_global_genNoner)letsafe_pr_globalr=str(string_of_globalr)(* idem, but with qualification, and only for constants. *)letsafe_pr_long_globalr=tryPrinter.pr_globalr.globwithNot_found->matchr.globwith|GlobRef.ConstRefkn->letmp,l=KerName.repr(Constant.userkn)instr((ModPath.to_stringmp)^"."^(Label.to_stringl))|_->assertfalseletpr_long_mpmp=letsp=Nametab.path_of_modulempinLibnames.pr_pathspletpr_long_globalref=pr_path(Nametab.path_of_globalref)(*S Warning and Error messages. *)leterr?locs=user_err?locsletwarn_extraction_axiom_to_realize=CWarnings.create~name:"extraction-axiom-to-realize"~category:CWarnings.CoreCategories.extraction(funaxioms->lets=ifInt.equal(List.lengthaxioms)1then"axiom"else"axioms"instrbrk("The following "^s^" must be realized in the extracted code:")++hov1(spc()++prlist_with_sepspcsafe_pr_globalaxioms)++str"."++fnl())letwarn_extraction_logical_axiom=CWarnings.create~name:"extraction-logical-axiom"~category:CWarnings.CoreCategories.extraction(funaxioms->lets=ifInt.equal(List.lengthaxioms)1then"axiom was"else"axioms were"in(strbrk("The following logical "^s^" encountered:")++hov1(spc()++prlist_with_sepspcsafe_pr_globalaxioms++str".\n")++strbrk"Having invalid logical axiom in the environment when extracting"++spc()++strbrk"may lead to incorrect or non-terminating ML terms."++fnl()))letwarn_extraction_symbols=letpp_symb_with_rules(symb,rules)=safe_pr_globalsymb++ifList.is_emptyrulesthenstr" (no rules)"elsestr":"++spc()++prlist_with_sepspcLabel.printrulesinCWarnings.create~name:"extraction-symbols"~category:CWarnings.CoreCategories.extraction(funsymbols->strbrk("The following symbols and rules were encountered:")++fnl()++prlist_with_sepfnlpp_symb_with_rulessymbols++fnl()++strbrk"The symbols must be realized such that the rewrite rules apply,"++spc()++strbrk"or extraction may lead to incorrect or non-terminating ML terms."++fnl())letwarning_axiomstable=letinfo_axioms=Refset'.elements!table.info_axiomsinifnot(List.is_emptyinfo_axioms)thenwarn_extraction_axiom_to_realizeinfo_axioms;letlog_axioms=Refset'.elements!table.log_axiomsinifnot(List.is_emptylog_axioms)thenwarn_extraction_logical_axiomlog_axioms;letsymbols=Refmap'.bindings!table.symbolsinifnot(List.is_emptysymbols)thenwarn_extraction_symbolssymbolsletwarn_extraction_opaque_accessed=CWarnings.create~name:"extraction-opaque-accessed"~category:CWarnings.CoreCategories.extraction(funlst->strbrk"The extraction is currently set to bypass opacity, "++strbrk"the following opaque constant bodies have been accessed :"++lst++str"."++fnl())letwarn_extraction_opaque_as_axiom=CWarnings.create~name:"extraction-opaque-as-axiom"~category:CWarnings.CoreCategories.extraction(funlst->strbrk"The extraction now honors the opacity constraints by default, "++strbrk"the following opaque constants have been extracted as axioms :"++lst++str"."++fnl()++strbrk"If necessary, use \"Set Extraction AccessOpaque\" to change this."++fnl())letwarning_opaquestableaccessed=letopaques=Refset'.elements!table.opaquesinifnot(List.is_emptyopaques)thenletlst=hov1(spc()++prlist_with_sepspcsafe_pr_globalopaques)inifaccessedthenwarn_extraction_opaque_accessedlstelsewarn_extraction_opaque_as_axiomlstletwarning_ambiguous_name=CWarnings.create_with_quickfix~name:"extraction-ambiguous-name"~category:CWarnings.CoreCategories.extraction(fun(q,mp,r)->strbrk"The name "++pr_qualidq++strbrk" is ambiguous, "++strbrk"do you mean module "++pr_long_mpmp++strbrk" or object "++pr_long_globalr++str" ?"++fnl()++strbrk"First choice is assumed, for the second one please use "++strbrk"fully qualified name."++fnl())letwarning_ambiguous_name?loc(_,mp,rasx)=matchlocwith|None->warning_ambiguous_namex|Someloc->warning_ambiguous_name~loc~quickfix:(List.map(Quickfix.make~loc)[pr_long_mpmp;pr_long_globalr])xleterror_axiom_scheme?locri=err?loc(str"The type scheme axiom "++spc()++safe_pr_globalr++spc()++str"needs "++inti++str" type variable(s).")letcheck_inside_section()=ifLib.sections_are_opened()thenerr(str"You can't do that within a section."++fnl()++str"Close it and try again.")letwarn_extraction_reserved_identifier=CWarnings.create~name:"extraction-reserved-identifier"~category:CWarnings.CoreCategories.extraction(funs->strbrk("The identifier "^s^" contains __ which is reserved for the extraction"))letwarning_ids=warn_extraction_reserved_identifiersleterror_constant?locr=err?loc(safe_pr_globalr++str" is not a constant.")leterror_inductive?locr=err?loc(safe_pr_globalr++spc()++str"is not an inductive type.")leterror_nb_cons()=err(str"Not the right number of constructors.")leterror_module_clashmp1mp2=err(str"The Rocq modules "++pr_long_mpmp1++str" and "++pr_long_mpmp2++str" have the same ML name.\n"++str"This is not supported yet. Please do some renaming first.")leterror_no_module_exprmp=err(str"The module "++pr_long_mpmp++str" has no body, it probably comes from\n"++str"some Declare Module outside any Module Type.\n"++str"This situation is currently unsupported by the extraction.")leterror_singleton_become_propind=(* Should be fine, only used for printing and with template poly inductives *)letind={glob=IndRefind;inst=InfvInst.empty}inerr(str"The informative inductive type "++safe_pr_globalind++str" has a Prop instance"++str"."++fnl()++str"This happens when a sort-polymorphic singleton inductive type\n"++str"has logical parameters, such as (I,I) : (True * True) : Prop.\n"++str"Extraction cannot handle this situation yet.\n"++str"Instead, use a sort-monomorphic type such as (True /\\ True)\n"++str"or extract to Haskell.")leterror_unknown_module?locm=err?loc(str"Module"++spc()++pr_qualidm++spc()++str"not found.")leterror_scheme()=err(str"No Scheme modular extraction available yet.")leterror_not_visibler=err(safe_pr_globalr++str" is not directly visible.\n"++str"For example, it may be inside an applied functor.\n"++str"Use Recursive Extraction to get the whole environment.")leterror_MPfile_as_modmpb=lets1=ifbthen"asked"else"required"inlets2=ifbthen"extract some objects of this module or\n"else""inerr(str("Extraction of file "^(raw_string_of_modfilemp)^".v as a module is "^s1^".\n"^"Monolithic Extraction cannot deal with this situation.\n"^"Please "^s2^"use (Recursive) Extraction Library instead.\n"))letargnames_of_globalr=letenv=Global.env()inlettyp,_=Typeops.type_of_global_in_contextenvr.globinletrels,_=decompose_prod(Reduction.whd_allenvtyp)inList.rev_map(funx->Context.binder_name(fstx))relsletmsg_of_implicit=function|Kimplicit(r,i)->letname=match(List.nth(argnames_of_globalr)(i-1))with|Anonymous->""|Nameid->"("^Id.to_stringid^") "in(String.ordinali)^" argument "^name^"of "^(string_of_globalr)|Ktype|Kprop->""leterror_remaining_implicitk=lets=msg_of_implicitkinerr(str("An implicit occurs after extraction : "^s^".")++fnl()++str"Please check your Extraction Implicit declarations."++fnl()++str"You might also try Unset Extraction SafeImplicits to force"++fnl()++str"the extraction of unsafe code and review it manually.")letwarn_extraction_remaining_implicit=CWarnings.create~name:"extraction-remaining-implicit"~category:CWarnings.CoreCategories.extraction(funs->strbrk("At least an implicit occurs after extraction : "^s^".")++fnl()++strbrk"Extraction SafeImplicits is unset, extracting nonetheless,"++strbrk"but this code is potentially unsafe, please review it manually.")letwarning_remaining_implicitk=lets=msg_of_implicitkinwarn_extraction_remaining_implicitsletcheck_loaded_modfilemp=matchbase_mpmpwith|MPfiledp->ifnot(Library.library_is_loadeddp)thenbeginmatchbase_mp(extraction_current_mp())with|MPfiledp'whennot(DirPath.equaldpdp')->err(str"Please load library "++DirPath.printdp++str" first.")|_->()end|_->()letinfo_filef=Flags.if_verboseFeedback.msg_info(str("The file "^f^" has been created by extraction."))(*S The Extraction auxiliary commands *)(* The objects defined below should survive an arbitrary time,
so we register them to coq save/undo mechanism. *)letmy_bool_optionnamevalue=let{Goptions.get}=declare_bool_option_and_ref~key:["Extraction";name]~value()inget(*s Extraction Output Directory *)letwarn_using_current_directory=CWarnings.(create~name:"extraction-default-directory"~category:CoreCategories.extraction)(funs->Pp.(strbrk"Setting extraction output directory by default to \""++strs++strbrk"\". Use \""++str"Set Extraction Output Directory"++strbrk"\" or command line option \"-output-directory\" to "++strbrk"set a different directory for extracted files to appear in."))letoutput_directory_key=["Extraction";"Output";"Directory"]let{Goptions.get=output_directory}=declare_stringopt_option_and_ref~stage:Summary.Stage.Interp~value:None~key:output_directory_key()letoutput_directory()=matchoutput_directory(),!Flags.output_directorywith|Somedir,_|None,Somedir->(* Ensure that the directory exists *)System.mkdirdir;dir|None,None->letpwd=Sys.getcwd()inwarn_using_current_directorypwd;(* Note: in case of error in the caller of output_directory, the effect of the setting will be undo *)set_string_option_value~stage:Summary.Stage.Interpoutput_directory_keypwd;pwd(*s Extraction AccessOpaque *)letaccess_opaque=my_bool_option"AccessOpaque"true(*s Extraction AutoInline *)letauto_inline=my_bool_option"AutoInline"false(*s Extraction TypeExpand *)lettype_expand=my_bool_option"TypeExpand"true(*s Extraction KeepSingleton *)letkeep_singleton=my_bool_option"KeepSingleton"false(*s Extraction Optimize *)typeopt_flag={opt_kill_dum:bool;(* 1 *)opt_fix_fun:bool;(* 2 *)opt_case_iot:bool;(* 4 *)opt_case_idr:bool;(* 8 *)opt_case_idg:bool;(* 16 *)opt_case_cst:bool;(* 32 *)opt_case_fun:bool;(* 64 *)opt_case_app:bool;(* 128 *)opt_let_app:bool;(* 256 *)opt_lin_let:bool;(* 512 *)opt_lin_beta:bool}(* 1024 *)letkth_digitnk=not(Int.equal(nland(1lslk))0)letflag_of_intn={opt_kill_dum=kth_digitn0;opt_fix_fun=kth_digitn1;opt_case_iot=kth_digitn2;opt_case_idr=kth_digitn3;opt_case_idg=kth_digitn4;opt_case_cst=kth_digitn5;opt_case_fun=kth_digitn6;opt_case_app=kth_digitn7;opt_let_app=kth_digitn8;opt_lin_let=kth_digitn9;opt_lin_beta=kth_digitn10}(* For the moment, we allow by default everything except :
- the type-unsafe optimization [opt_case_idg], which anyway
cannot be activated currently (cf [Mlutil.branch_as_fun])
- the linear let and beta reduction [opt_lin_let] and [opt_lin_beta]
(may lead to complexity blow-up, subsumed by finer reductions
when inlining recursors).
*)letint_flag_init=1+2+4+8(*+ 16*)+32+64+128+256(*+ 512 + 1024*)letint_flag_ref=refint_flag_initletopt_flag_ref=ref(flag_of_intint_flag_init)letchg_flagn=int_flag_ref:=n;opt_flag_ref:=flag_of_intnletoptims()=!opt_flag_reflet()=declare_option~kind:BoolKind~no_summary:true(* synchronization handled by Extraction Flag *){optstage=Summary.Stage.Interp;optdepr=None;optkey=["Extraction";"Optimize"];optread=(fun()->not(Int.equal!int_flag_ref0));optwrite=(funb->chg_flag(ifbthenint_flag_initelse0))}let()=declare_int_option{optstage=Summary.Stage.Interp;optdepr=None;optkey=["Extraction";"Flag"];optread=(fun_->Some!int_flag_ref);optwrite=(function|None->chg_flag0|Somei->chg_flag(maxi0))}(* This option controls whether "dummy lambda" are removed when a
toplevel constant is defined. *)let{Goptions.get=conservative_types}=declare_bool_option_and_ref~key:["Extraction";"Conservative";"Types"]~value:false()(* Allows to print a comment at the beginning of the output files *)let{Goptions.get=file_comment}=declare_string_option_and_ref~key:["Extraction";"File";"Comment"]~value:""()(*s Extraction Lang *)typelang=Ocaml|Haskell|Scheme|JSONletlang_ref=Summary.refOcaml~name:"ExtrLang"letlang()=!lang_refletextr_lang:lang->obj=declare_object@@superglobal_object_nodischarge"Extraction Lang"~cache:(funl->lang_ref:=l)~subst:Noneletextraction_languagex=Lib.add_leaf(extr_langx)(*s Extraction Inline/NoInline *)letempty_inline_table=(Refset'.empty,Refset'.empty)letinline_table=Summary.refempty_inline_table~name:"ExtrInline"letto_inliner=Refset'.memr(fst!inline_table)(* Extension for supporting foreign function call extraction. *)letempty_foreign_set=Refset'.emptyletforeign_set=Summary.refempty_foreign_set~name:"ExtrForeign"letto_foreignr=Refset'.memr!foreign_set(* End of Extension for supporting foreign function call extraction. *)(* Extension for supporting callback registration extraction. *)(* A map from qualid to string opt (alias) *)letempty_callback_map=Refmap'.emptyletcallback_map=Summary.refempty_callback_map~name:"ExtrCallback"(* End of Extension for supporting callback registration extraction. *)letto_keepr=Refset'.memr(snd!inline_table)letadd_inline_entriesbl=letfb=ifbthenRefset'.addelseRefset'.removeinleti,k=!inline_tableininline_table:=(List.fold_right(fb)li),(List.fold_right(f(notb))lk)letadd_foreign_entriesl=foreign_set:=List.fold_right(Refset'.add)l!foreign_set(* Adds the qualid_ref and alias opt to the callback_map. *)letadd_callback_entryalias_optqualid_ref=callback_map:=Refmap'.addqualid_refalias_opt!callback_map(* Registration of operations for rollback. *)letsubst_globalsg={glob=fst(subst_globalsg.glob);inst=g.inst}letinline_extraction:bool*globallist->obj=declare_object@@superglobal_object"Extraction Inline"~cache:(fun(b,l)->add_inline_entriesbl)~subst:(Some(fun(s,(b,l))->(b,(List.map(funx->subst_globalsx)l))))~discharge:(funx->Somex)letforeign_extraction:globallist->obj=declare_object@@superglobal_object"Extraction Foreign"~cache:(funl->add_foreign_entriesl)~subst:(Some(fun(s,l)->(List.map(funx->subst_globalsx)l)))~discharge:(funx->Somex)letcallback_extraction:stringoption*global->obj=declare_object@@superglobal_object"Extraction Callback"~cache:(fun(alias,x)->add_callback_entryaliasx)~subst:(Some(fun(s,(alias,x))->(alias,subst_globalsx)))~discharge:(funx->Somex)(* Grammar entries. *)letmono_global_with_aliasqid=letgr=Smartlocate.global_with_aliasqidinletinst=Environ.universes_of_global(Global.env())grinList.map(funinst->{glob=gr;inst})(InfvInst.generateinst)letextraction_inlinebl=letrefs=List.map_appendmono_global_with_aliaslinList.iter(funr->matchr.globwith|GlobRef.ConstRef_->()|_->error_constantr)refs;Lib.add_leaf(inline_extraction(b,refs))(* Printing part *)letprint_extraction_inline()=let(i,n)=!inline_tableinleti'=Refset'.filter(function{glob=GlobRef.ConstRef_}->true|_->false)iin(str"Extraction Inline:"++fnl()++Refset'.fold(funrp->(p++str" "++safe_pr_long_globalr++fnl()))i'(mt())++str"Extraction NoInline:"++fnl()++Refset'.fold(funrp->(p++str" "++safe_pr_long_globalr++fnl()))n(mt()))(* Reset part *)letreset_inline:unit->obj=declare_object@@superglobal_object_nodischarge"Reset Extraction Inline"~cache:(fun()->inline_table:=empty_inline_table)~subst:Noneletreset_foreign:unit->obj=declare_object@@superglobal_object_nodischarge"Reset Extraction Foreign"~cache:(fun()->foreign_set:=empty_foreign_set)~subst:Noneletreset_callback:unit->obj=declare_object@@superglobal_object_nodischarge"Reset Extraction Callback"~cache:(fun()->callback_map:=empty_callback_map)~subst:Noneletreset_extraction_inline()=Lib.add_leaf(reset_inline())letreset_extraction_foreign()=Lib.add_leaf(reset_foreign())letreset_extraction_callback()=Lib.add_leaf(reset_callback())(*s Extraction Implicit *)letsafe_implicit=my_bool_option"SafeImplicits"trueleterr_or_warn_remaining_implicitk=ifsafe_implicit()thenerror_remaining_implicitkelsewarning_remaining_implicitktypeint_or_id=ArgIntofint|ArgIdofId.tletimplicits_table=Summary.refRefmap'.empty~name:"ExtrImplicit"letimplicits_of_globalr=tryRefmap'.findr!implicits_tablewithNot_found->Int.Set.emptyletadd_implicitsrl=letnames=argnames_of_globalrinletn=List.lengthnamesinletadd_args=function|ArgInti->if1<=i&&i<=nthenInt.Set.addiselseerr(inti++str" is not a valid argument number for "++safe_pr_globalr)|ArgIdid->tryleti=List.indexName.equal(Nameid)namesinInt.Set.addiswithNot_found->err(str"No argument "++Id.printid++str" for "++safe_pr_globalr)inletints=List.fold_leftadd_argInt.Set.emptylinimplicits_table:=Refmap'.addrints!implicits_table(* Registration of operations for rollback. *)letimplicit_extraction:global*int_or_idlist->obj=declare_object@@superglobal_object_nodischarge"Extraction Implicit"~cache:(fun(r,l)->add_implicitsrl)~subst:(Some(fun(s,(r,l))->(subst_globalsr,l)))(* Grammar entries. *)letextraction_implicitrl=check_inside_section();letr=mono_global_with_aliasrinList.iter(funr->Lib.add_leaf(implicit_extraction(r,l)))rletstring_of_modfiletablemp=tryMPmap.findmp!table.modfile_mpswithNot_found->letid=Id.of_string(raw_string_of_modfilemp)inletid'=next_ident_awayid!table.modfile_idsinlets'=Id.to_stringid'intable:={!tablewithmodfile_ids=Id.Set.addid'!table.modfile_ids;modfile_mps=MPmap.addmps'!table.modfile_mps;};s'(* same as [string_of_modfile], but preserves the capital/uncapital 1st char *)letfile_of_modfiletablemp=lets0=matchmpwith|MPfilef->Id.to_string(List.hd(DirPath.reprf))|_->assertfalseinString.mapi(funic->ifi=0thens0.[0]elsec)(string_of_modfiletablemp)letadd_blacklist_entriesl=blacklist_table:=List.fold_right(funs->Id.Set.add(Id.of_string(String.capitalize_asciis)))l!blacklist_table(* Registration of operations for rollback. *)letblacklist_extraction:stringlist->obj=declare_object@@superglobal_object_nodischarge"Extraction Blacklist"~cache:add_blacklist_entries~subst:None(* Grammar entries. *)letextraction_blacklistl=letl=List.revlinLib.add_leaf(blacklist_extractionl)(* Printing part *)letprint_extraction_blacklist()=prlist_with_sepfnlId.print(Id.Set.elements!blacklist_table)(* Reset part *)letreset_blacklist:unit->obj=declare_object@@superglobal_object_nodischarge"Reset Extraction Blacklist"~cache:(fun()->blacklist_table:=Id.Set.empty)~subst:Noneletreset_extraction_blacklist()=Lib.add_leaf(reset_blacklist())(*s Extract Constant/Inductive. *)(* UGLY HACK: to be defined in [extraction.ml] *)let(use_type_scheme_nb_args,type_scheme_nb_args_hook)=Hook.make()letcustoms=Summary.refRefmap'.empty~name:"ExtrCustom"letadd_customridss=customs:=Refmap'.addr(ids,s)!customsletis_customr=Refmap'.memr!customsletis_inline_customr=(is_customr)&&(to_inliner)letis_foreign_customr=(is_customr)&&(to_foreignr)letfind_callbackr=Refmap'.findr!callback_mapletfind_customr=snd(Refmap'.findr!customs)letfind_type_customr=Refmap'.findr!customsletcustom_matchs=Summary.refRefmap'.empty~name:"ExtrCustomMatchs"letadd_custom_matchrs=custom_matchs:=Refmap'.addrs!custom_matchsletindref_of_matchpv=ifArray.is_emptypvthenraiseNot_found;let(_,pat,_)=pv.(0)inmatchpatwith|Pusual{glob=GlobRef.ConstructRef(ip,_);inst}->{glob=GlobRef.IndRefip;inst}|Pcons({glob=GlobRef.ConstructRef(ip,_);inst},_)->{glob=GlobRef.IndRefip;inst}|_->raiseNot_foundletis_custom_matchpv=tryRefmap'.mem(indref_of_matchpv)!custom_matchswithNot_found->falseletfind_custom_matchpv=Refmap'.find(indref_of_matchpv)!custom_matchs(* Printing entries *)letprint_constref_extractionsref_setval_lookup_fsection_str=leti'=Refset'.filter(function{glob=GlobRef.ConstRef_}->true|_->false)ref_setin(strsection_str++fnl()++Refset'.fold(funrp->(p++str" "++safe_pr_long_globalr++str" => \""++str(val_lookup_fr)++str"\""++fnl()))i'(mt()))letprint_extraction_foreign()=print_constref_extractions!foreign_set(find_custom)"Extraction Foreign Constant:"letprint_extraction_callback()=letkeys=Refmap'.domain!callback_mapinprint_constref_extractionskeys(funr->matchfind_callbackrwith|None->"no custom alias"|Somes->s)"Extraction Callbacks for Constants:"(* Registration of operations for rollback. *)letin_customs:global*stringlist*string->obj=declare_object@@superglobal_object_nodischarge"ML extractions"~cache:(fun(r,ids,s)->add_customridss)~subst:(Some(fun(s,(r,ids,str))->(subst_globalsr,ids,str)))letin_custom_matchs:global*string->obj=declare_object@@superglobal_object_nodischarge"ML extractions custom matches"~cache:(fun(r,s)->add_custom_matchrs)~subst:(Some(fun(subs,(r,s))->(subst_globalsubsr,s)))(* Grammar entries. *)letextract_callbackoptstrx=iflang()!=OcamlthenCErrors.user_err(Pp.str"Extract Callback is supported only for OCaml extraction.");letrefs=mono_global_with_aliasxinList.iterbeginfunqualid_ref->matchqualid_ref.globwith(* Add the alias and qualid_ref to callback extraction.*)|GlobRef.ConstRef_->Lib.add_leaf(callback_extraction(optstr,qualid_ref))|_->error_constant?loc:x.CAst.locqualid_refendrefsletextract_constant_genericridssarity_handler(is_redef,redef_msg)extr_type=check_inside_section();letg=mono_global_with_aliasrinList.iterbeginfung->matchg.globwith|GlobRef.ConstRefkn->letenv=Global.env()in(* FIXME: substitute ground instance *)lettyp,_=Typeops.type_of_global_in_contextenv(GlobRef.ConstRefkn)inlettyp=Reduction.whd_allenvtypinifReduction.is_arityenvtypthenarity_handlerenvtypg;ifis_redefgthenCErrors.user_err((str"The term ")++safe_pr_long_globalg++(str" is already defined as ")++(strredef_msg)++(str" custom constant."));Lib.add_leaf(extr_typeg);Lib.add_leaf(in_customs(g,ids,s));|_->error_constant?loc:r.CAst.locgendgletextract_constant_inlineinlineridss=letarity_handlerenvtypg=letnargs=Hook.getuse_type_scheme_nb_argsenvtypinifnot(Int.equal(List.lengthids)nargs)thenerror_axiom_scheme?loc:r.CAst.locgnargsinextract_constant_genericridss(arity_handler)(is_foreign_custom,"foreign")(fung->inline_extraction(inline,[g]))(* const_name : qualid -> replacement : string*)letextract_constant_foreignrs=iflang()!=OcamlthenCErrors.user_err(Pp.str"Extract Foreign Constant is supported only for OCaml extraction.");letarity_handlerenvtypg=CErrors.user_err(Pp.str"Extract Foreign Constant is supported only for functions.")inextract_constant_genericr[]s(arity_handler)(is_inline_custom,"inline")(fung->foreign_extraction[g])letextract_inductiversloptstr=check_inside_section();letg=mono_global_with_aliasrinList.iterbeginfung->Dumpglob.add_glob?loc:r.CAst.locg.glob;matchg.globwith|GlobRef.IndRef((kn,i)asip)->letmib=Global.lookup_mindkninletn=Array.lengthmib.mind_packets.(i).mind_consnamesinifnot(Int.equaln(List.lengthl))thenerror_nb_cons();Lib.add_leaf(inline_extraction(true,[g]));Lib.add_leaf(in_customs(g,[],s));Option.iter(funs->Lib.add_leaf(in_custom_matchs(g,s)))optstr;List.iteri(funjs->letg={glob=GlobRef.ConstructRef(ip,succj);inst=g.inst}inLib.add_leaf(inline_extraction(true,[g]));Lib.add_leaf(in_customs(g,[],s)))l|_->error_inductive?loc:r.CAst.locgendg