12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049(************************************************************************)(* * 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',_)->ModPath.Set.addmp(prefixes_mpmp')|_->ModPath.Set.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->ifModPath.Set.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:KerName.Set.t;(* recursors: we can use the equivalence between canonical and user constant names. *)projs:GlobRef.Set_env.t;(* projs: working modulo name equivalence is ok *)info_axioms:Refset'.t;log_axioms:Refset'.t;symbols:Id.tlistRefmap'.t;opaques:Refset'.t;modfile_ids:Id.Set.t;modfile_mps:stringDirPath.Map.t;}typet=tablerefletempty_table={typedefs=Cmap_env.empty;cst_types=Cmap_env.empty;inductives=Mindmap_env.empty;inductive_kinds=Mindmap_env.empty;recursors=KerName.Set.empty;projs=GlobRef.Set_env.empty;info_axioms=Refset'.empty;log_axioms=Refset'.empty;symbols=Refmap'.empty;opaques=Refset'.empty;modfile_ids=Id.Set.empty;modfile_mps=DirPath.Map.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)idinletmib=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=KerName.Set.addkn_rec(KerName.Set.addkn_rect!table.recursors)})mib.mind_packetsletis_recursortabler=matchr.globwith|GlobRef.ConstRefc->KerName.Set.mem(Constant.canonicalc)!table.recursors|_->falseletadd_projectiontablenknip=table:={!tablewithprojs=GlobRef.Set_env.add(GlobRef.ConstRefkn)!table.projs}letis_projectiontabler=GlobRef.Set_env.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(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->Constant.labelkn|IndRef(kn,0)->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)^"."^(Id.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_sepspcId.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~name:"extraction-ambiguous-name"~category:CWarnings.CoreCategories.extraction~quickfix:(fun~loc(_,mp,r)->List.map(Quickfix.make~loc)[pr_long_mpmp;pr_long_globalr])(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())leterror_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(),!System.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=tryDirPath.Map.findmp!table.modfile_mpswithNot_found->letid=Id.of_string(raw_string_of_modfile(MPfilemp))inletid'=next_ident_awayid!table.modfile_idsinlets'=Id.to_stringid'intable:={!tablewithmodfile_ids=Id.Set.addid'!table.modfile_ids;modfile_mps=DirPath.Map.addmps'!table.modfile_mps;};s'(* same as [string_of_modfile], but preserves the capital/uncapital 1st char *)letfile_of_modfiletabledp=lets0=Id.to_string(List.hd(DirPath.reprdp))inString.mapi(funic->ifi=0thens0.[0]elsec)(string_of_modfiletabledp)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